Browse Source

Merge branch 'libarchive-upstream' into update-libarchive

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

+ 395 - 70
Utilities/cmlibarchive/CMakeLists.txt

@@ -1,8 +1,8 @@
 #
 #
+CMAKE_MINIMUM_REQUIRED(VERSION 2.8.6 FATAL_ERROR)
 #
 #
 PROJECT(libarchive C)
 PROJECT(libarchive C)
 #
 #
-CMAKE_MINIMUM_REQUIRED(VERSION 2.8 FATAL_ERROR)
 SET(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/build/cmake")
 SET(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/build/cmake")
 if(NOT CMAKE_RUNTIME_OUTPUT_DIRECTORY)
 if(NOT CMAKE_RUNTIME_OUTPUT_DIRECTORY)
   set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${libarchive_BINARY_DIR}/bin)
   set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${libarchive_BINARY_DIR}/bin)
@@ -39,13 +39,24 @@ SET(LIBARCHIVE_VERSION_STRING  "${VERSION}")
 # libarchive 2.8 == interface version 10 = 2 + 8
 # libarchive 2.8 == interface version 10 = 2 + 8
 # libarchive 2.9 == interface version 11 = 2 + 9
 # libarchive 2.9 == interface version 11 = 2 + 9
 # libarchive 3.0 == interface version 12
 # 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
 # Set SOVERSION == Interface version
 # ?? Should there be more here ??
 # ?? Should there be more here ??
 SET(SOVERSION "${INTERFACE_VERSION}")
 SET(SOVERSION "${INTERFACE_VERSION}")
 
 
+# Enalbe CMAKE_PUSH_CHECK_STATE() and CMAKE_POP_CHECK_STATE() macros
+# saving and restoring the state of the variables.
+INCLUDE(CMakePushCheckState)
+
+# Initialize the state of the variables. This initialization is not
+# necessary but this shows you what value the variables initially have.
+SET(CMAKE_REQUIRED_DEFINITIONS)
+SET(CMAKE_REQUIRED_INCLUDES)
+SET(CMAKE_REQUIRED_LIBRARIES)
+SET(CMAKE_REQUIRED_FLAGS)
+
 # Disable warnings to avoid changing 3rd party code.
 # Disable warnings to avoid changing 3rd party code.
 IF("${CMAKE_C_COMPILER_ID}" MATCHES
 IF("${CMAKE_C_COMPILER_ID}" MATCHES
     "^(GNU|Clang|XL|VisualAge|SunPro|MIPSpro|HP|Intel)$")
     "^(GNU|Clang|XL|VisualAge|SunPro|MIPSpro|HP|Intel)$")
@@ -64,6 +75,8 @@ OPTION(ENABLE_OPENSSL "Enable use of OpenSSL" ON)
 OPTION(ENABLE_XATTR "Enable extended attribute support" ON)
 OPTION(ENABLE_XATTR "Enable extended attribute support" ON)
 OPTION(ENABLE_ACL "Enable ACL support" ON)
 OPTION(ENABLE_ACL "Enable ACL support" ON)
 OPTION(ENABLE_ICONV "Enable iconv support" ON)
 OPTION(ENABLE_ICONV "Enable iconv support" ON)
+SET(POSIX_REGEX_LIB "AUTO" CACHE STRING "Choose what library should provide POSIX regular expression support")
+SET(ENABLE_SAFESEH "AUTO" CACHE STRING "Enable use of /SAFESEH linker flag (MSVC only)")
 
 
 IF(WIN32)
 IF(WIN32)
   IF(MSVC60)
   IF(MSVC60)
@@ -74,13 +87,27 @@ IF(WIN32)
   SET(_WIN32_WINNT ${WINVER})
   SET(_WIN32_WINNT ${WINVER})
 ENDIF(WIN32)
 ENDIF(WIN32)
 
 
+IF(MSVC)
+  IF(ENABLE_SAFESEH STREQUAL "YES")
+    SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /SAFESEH")
+    SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /SAFESEH")
+    SET(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} /SAFESEH")
+	SET(CMAKE_REQUIRED_LINKER_FLAGS "/SAFESEH")
+  ELSEIF(ENABLE_SAFESEH STREQUAL "NO")
+    SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /SAFESEH:NO")
+    SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /SAFESEH:NO")
+    SET(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} /SAFESEH:NO")
+	SET(CMAKE_REQUIRED_LINKER_FLAGS "/SAFESEH:NO")
+  ENDIF(ENABLE_SAFESEH STREQUAL "YES")
+ENDIF(MSVC)
+
 IF("${CMAKE_C_PLATFORM_ID}" MATCHES "^(HP-UX)$")
 IF("${CMAKE_C_PLATFORM_ID}" MATCHES "^(HP-UX)$")
   ADD_DEFINITIONS(-D_XOPEN_SOURCE=500) # Ask wchar.h for mbstate_t
   ADD_DEFINITIONS(-D_XOPEN_SOURCE=500) # Ask wchar.h for mbstate_t
 ENDIF()
 ENDIF()
 
 
 #
 #
-INCLUDE(CheckCSourceCompiles)
-INCLUDE(CheckCSourceRuns)
+INCLUDE(LibarchiveCheckCSourceCompiles)
+INCLUDE(LibarchiveCheckCSourceRuns)
 INCLUDE(CheckFileOffsetBits)
 INCLUDE(CheckFileOffsetBits)
 INCLUDE(CheckFuncs)
 INCLUDE(CheckFuncs)
 INCLUDE(CheckHeaderDirent)
 INCLUDE(CheckHeaderDirent)
@@ -125,7 +152,38 @@ MACRO (INSTALL_MAN __mans)
     INSTALL(FILES ${_man} DESTINATION "share/man/man${_mansect}")
     INSTALL(FILES ${_man} DESTINATION "share/man/man${_mansect}")
   ENDFOREACH (_man)
   ENDFOREACH (_man)
 ENDMACRO (INSTALL_MAN __mans)
 ENDMACRO (INSTALL_MAN __mans)
-
+#
+# Find out what macro is needed to use libraries on Windows.
+#
+MACRO (TRY_MACRO_FOR_LIBRARY INCLUDES LIBRARIES
+       TRY_TYPE SAMPLE_SOURCE MACRO_LIST)
+  IF(WIN32 AND NOT CYGWIN)
+    CMAKE_PUSH_CHECK_STATE()	# Save the state of the variables
+    SET(CMAKE_REQUIRED_INCLUDES ${INCLUDES})
+    SET(CMAKE_REQUIRED_LIBRARIES ${LIBRARIES})
+    FOREACH(VAR ${MACRO_LIST})
+      # Clear ${VAR} from CACHE If the libraries which ${VAR} was
+      # checked with are changed.
+      SET(VAR_WITH_LIB "${VAR}_WITH_LIB")
+      GET_PROPERTY(PREV_VAR_WITH_LIB VARIABLE PROPERTY ${VAR_WITH_LIB})
+      IF(NOT "${PREV_VAR_WITH_LIB}" STREQUAL "${LIBRARIES}")
+        UNSET(${VAR} CACHE)
+      ENDIF(NOT "${PREV_VAR_WITH_LIB}" STREQUAL "${LIBRARIES}")
+      # Check if the library can be used with the macro.
+      IF("${TRY_TYPE}" MATCHES "COMPILES")
+        LIBARCHIVE_CHECK_C_SOURCE_COMPILES("${SAMPLE_SOURCE}" ${VAR})
+      ELSEIF("${TRY_TYPE}" MATCHES "RUNS")
+        LIBARCHIVE_CHECK_C_SOURCE_RUNS("${SAMPLE_SOURCE}" ${VAR})
+      ELSE("${TRY_TYPE}" MATCHES "COMPILES")
+        MESSAGE(FATAL_ERROR "UNKNOWN KEYWORD \"${TRY_TYPE}\" FOR TRY_TYPE")
+      ENDIF("${TRY_TYPE}" MATCHES "COMPILES")
+      # Save the libraries which ${VAR} is checked with.
+      SET(${VAR_WITH_LIB} "${LIBRARIES}" CACHE INTERNAL
+          "Macro ${VAR} is checked with")
+    ENDFOREACH(VAR)
+    CMAKE_POP_CHECK_STATE()	# Restore the state of the variables
+  ENDIF(WIN32 AND NOT CYGWIN)
+ENDMACRO (TRY_MACRO_FOR_LIBRARY)
 #
 #
 # Check compress/decompress libraries
 # Check compress/decompress libraries
 #
 #
@@ -172,13 +230,27 @@ IF(ZLIB_FOUND)
   INCLUDE_DIRECTORIES(${ZLIB_INCLUDE_DIR})
   INCLUDE_DIRECTORIES(${ZLIB_INCLUDE_DIR})
   LIST(APPEND ADDITIONAL_LIBS ${ZLIB_LIBRARIES})
   LIST(APPEND ADDITIONAL_LIBS ${ZLIB_LIBRARIES})
   IF(WIN32 AND NOT CYGWIN)
   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)
       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)
   ENDIF(WIN32 AND NOT CYGWIN)
 ELSE(ZLIB_FOUND)
 ELSE(ZLIB_FOUND)
   MESSAGE(FATAL_ERROR "CMake requires zlib to be available to libarchive")
   MESSAGE(FATAL_ERROR "CMake requires zlib to be available to libarchive")
@@ -192,11 +264,21 @@ IF(BZIP2_FOUND)
   SET(HAVE_BZLIB_H 1)
   SET(HAVE_BZLIB_H 1)
   INCLUDE_DIRECTORIES(${BZIP2_INCLUDE_DIR})
   INCLUDE_DIRECTORIES(${BZIP2_INCLUDE_DIR})
   LIST(APPEND ADDITIONAL_LIBS ${BZIP2_LIBRARIES})
   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)
 ENDIF(BZIP2_FOUND)
 MARK_AS_ADVANCED(CLEAR BZIP2_INCLUDE_DIR)
 MARK_AS_ADVANCED(CLEAR BZIP2_INCLUDE_DIR)
-MARK_AS_ADVANCED(CLEAR BZIP2_LIBRARY)
-
-IF(0) # CMake does not need LZMA support in libarchive
+MARK_AS_ADVANCED(CLEAR BZIP2_LIBRARIES)
+IF(0) # CMake does not need LZMA or LZO2 support in libarchive
 #
 #
 # Find LZMA
 # Find LZMA
 #
 #
@@ -206,12 +288,45 @@ IF(LZMA_FOUND)
   SET(HAVE_LZMA_H 1)
   SET(HAVE_LZMA_H 1)
   INCLUDE_DIRECTORIES(${LZMA_INCLUDE_DIR})
   INCLUDE_DIRECTORIES(${LZMA_INCLUDE_DIR})
   LIST(APPEND ADDITIONAL_LIBS ${LZMA_LIBRARIES})
   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)
 ELSEIF(LZMADEC_FOUND)
   SET(HAVE_LIBLZMADEC 1)
   SET(HAVE_LIBLZMADEC 1)
   SET(HAVE_LZMADEC_H 1)
   SET(HAVE_LZMADEC_H 1)
   INCLUDE_DIRECTORIES(${LZMADEC_INCLUDE_DIR})
   INCLUDE_DIRECTORIES(${LZMADEC_INCLUDE_DIR})
   LIST(APPEND ADDITIONAL_LIBS ${LZMADEC_LIBRARIES})
   LIST(APPEND ADDITIONAL_LIBS ${LZMADEC_LIBRARIES})
 ENDIF(LZMA_FOUND)
 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()
 ENDIF()
 
 
 #
 #
@@ -239,7 +354,7 @@ LA_CHECK_INCLUDE_FILE("dlfcn.h" HAVE_DLFCN_H)
 LA_CHECK_INCLUDE_FILE("errno.h" HAVE_ERRNO_H)
 LA_CHECK_INCLUDE_FILE("errno.h" HAVE_ERRNO_H)
 LA_CHECK_INCLUDE_FILE("ext2fs/ext2_fs.h" HAVE_EXT2FS_EXT2_FS_H)
 LA_CHECK_INCLUDE_FILE("ext2fs/ext2_fs.h" HAVE_EXT2FS_EXT2_FS_H)
 
 
-CHECK_C_SOURCE_COMPILES("#include <sys/ioctl.h>
+LIBARCHIVE_CHECK_C_SOURCE_COMPILES("#include <sys/ioctl.h>
 #include <ext2fs/ext2_fs.h>
 #include <ext2fs/ext2_fs.h>
 int main(void) { return EXT2_IOC_GETFLAGS; }" HAVE_WORKING_EXT2_IOC_GETFLAGS)
 int main(void) { return EXT2_IOC_GETFLAGS; }" HAVE_WORKING_EXT2_IOC_GETFLAGS)
 
 
@@ -261,6 +376,7 @@ LA_CHECK_INCLUDE_FILE("process.h" HAVE_PROCESS_H)
 LA_CHECK_INCLUDE_FILE("pwd.h" HAVE_PWD_H)
 LA_CHECK_INCLUDE_FILE("pwd.h" HAVE_PWD_H)
 LA_CHECK_INCLUDE_FILE("regex.h" HAVE_REGEX_H)
 LA_CHECK_INCLUDE_FILE("regex.h" HAVE_REGEX_H)
 LA_CHECK_INCLUDE_FILE("signal.h" HAVE_SIGNAL_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("stdarg.h" HAVE_STDARG_H)
 LA_CHECK_INCLUDE_FILE("stdint.h" HAVE_STDINT_H)
 LA_CHECK_INCLUDE_FILE("stdint.h" HAVE_STDINT_H)
 LA_CHECK_INCLUDE_FILE("stdlib.h" HAVE_STDLIB_H)
 LA_CHECK_INCLUDE_FILE("stdlib.h" HAVE_STDLIB_H)
@@ -301,7 +417,7 @@ FOREACH (it ${_HEADER})
    SET(_INCLUDE_FILES "${_INCLUDE_FILES}#include <${it}>\n")
    SET(_INCLUDE_FILES "${_INCLUDE_FILES}#include <${it}>\n")
 ENDFOREACH (it)
 ENDFOREACH (it)
 
 
-CHECK_C_SOURCE_COMPILES(
+LIBARCHIVE_CHECK_C_SOURCE_COMPILES(
   "#define __EXTENSIONS__ 1
   "#define __EXTENSIONS__ 1
    ${_INCLUDE_FILES}
    ${_INCLUDE_FILES}
    int main() { return 0;}"
    int main() { return 0;}"
@@ -311,14 +427,17 @@ CHECK_C_SOURCE_COMPILES(
 # Find Nettle
 # Find Nettle
 #
 #
 IF(ENABLE_NETTLE)
 IF(ENABLE_NETTLE)
-  CHECK_LIBRARY_EXISTS(nettle "nettle_sha1_digest" "" NETTLE_FOUND)
+  FIND_PACKAGE(Nettle)
   IF(NETTLE_FOUND)
   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)
   ENDIF(NETTLE_FOUND)
+  MARK_AS_ADVANCED(CLEAR NETTLE_INCLUDE_DIR)
+  MARK_AS_ADVANCED(CLEAR NETTLE_LIBRARIES)
 ENDIF(ENABLE_NETTLE)
 ENDIF(ENABLE_NETTLE)
 
 
 #
 #
@@ -332,12 +451,16 @@ ELSE()
 ENDIF()
 ENDIF()
 
 
 # FreeBSD libmd
 # 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
 # How to prove that CRYPTO functions, which have several names on various
@@ -345,13 +468,8 @@ ENDIF(LIBMD_FOUND)
 # required libraries.
 # required libraries.
 #
 #
 MACRO(CHECK_CRYPTO ALGORITHMS IMPLEMENTATION)
 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})
     FOREACH(ALGORITHM ${ALGORITHMS})
+      IF(NOT ARCHIVE_CRYPTO_${ALGORITHM})
       STRING(TOLOWER "${ALGORITHM}" lower_algorithm)
       STRING(TOLOWER "${ALGORITHM}" lower_algorithm)
       STRING(TOUPPER "${ALGORITHM}" algorithm)
       STRING(TOUPPER "${ALGORITHM}" algorithm)
       IF ("${IMPLEMENTATION}" MATCHES "^OPENSSL$" AND NOT OPENSSL_FOUND)
       IF ("${IMPLEMENTATION}" MATCHES "^OPENSSL$" AND NOT OPENSSL_FOUND)
@@ -364,7 +482,7 @@ MACRO(CHECK_CRYPTO ALGORITHMS IMPLEMENTATION)
         # Probe the local implementation for whether this
         # Probe the local implementation for whether this
 	# crypto implementation is available on this platform.
 	# crypto implementation is available on this platform.
 	SET(TRY_CRYPTO_REQUIRED_INCLUDES
 	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)
 	SET(TRY_CRYPTO_REQUIRED_LIBS)
 	IF ("${IMPLEMENTATION}" MATCHES "^OPENSSL$" AND OPENSSL_FOUND)
 	IF ("${IMPLEMENTATION}" MATCHES "^OPENSSL$" AND OPENSSL_FOUND)
 	    SET(TRY_CRYPTO_REQUIRED_INCLUDES
 	    SET(TRY_CRYPTO_REQUIRED_INCLUDES
@@ -372,6 +490,8 @@ MACRO(CHECK_CRYPTO ALGORITHMS IMPLEMENTATION)
 	    SET(TRY_CRYPTO_REQUIRED_LIBS
 	    SET(TRY_CRYPTO_REQUIRED_LIBS
 	        "-DLINK_LIBRARIES:STRING=${OPENSSL_LIBRARIES}")
 	        "-DLINK_LIBRARIES:STRING=${OPENSSL_LIBRARIES}")
 	ELSEIF("${IMPLEMENTATION}" MATCHES "^NETTLE$" AND NETTLE_FOUND)
 	ELSEIF("${IMPLEMENTATION}" MATCHES "^NETTLE$" AND NETTLE_FOUND)
+	    SET(TRY_CRYPTO_REQUIRED_INCLUDES
+	      "${TRY_CRYPTO_REQUIRED_INCLUDES};${NETTLE_INCLUDE_DIR}")
 	    SET(TRY_CRYPTO_REQUIRED_LIBS
 	    SET(TRY_CRYPTO_REQUIRED_LIBS
 	        "-DLINK_LIBRARIES:STRING=${NETTLE_LIBRARY}")
 	        "-DLINK_LIBRARIES:STRING=${NETTLE_LIBRARY}")
 	ELSEIF("${IMPLEMENTATION}" MATCHES "^LIBMD$" AND LIBMD_FOUND)
 	ELSEIF("${IMPLEMENTATION}" MATCHES "^LIBMD$" AND LIBMD_FOUND)
@@ -379,10 +499,15 @@ MACRO(CHECK_CRYPTO ALGORITHMS IMPLEMENTATION)
 	        "-DLINK_LIBRARIES:STRING=${LIBMD_LIBRARY}")
 	        "-DLINK_LIBRARIES:STRING=${LIBMD_LIBRARY}")
 	ENDIF("${IMPLEMENTATION}" MATCHES "^OPENSSL$" AND OPENSSL_FOUND)
 	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"
 	FILE(READ "${CMAKE_CURRENT_SOURCE_DIR}/libarchive/archive_crypto.c"
 	     ARCHIVE_CRYPTO_C)
 	     ARCHIVE_CRYPTO_C)
 
 
-	SET(SOURCE "
+	SET(SOURCE "${CONFDEFS_H}
+
 #define ARCHIVE_${algorithm}_COMPILE_TEST
 #define ARCHIVE_${algorithm}_COMPILE_TEST
 #define ARCHIVE_CRYPTO_${algorithm}_${IMPLEMENTATION}
 #define ARCHIVE_CRYPTO_${algorithm}_${IMPLEMENTATION}
 #define PLATFORM_CONFIG_H \"check_crypto_md.h\"
 #define PLATFORM_CONFIG_H \"check_crypto_md.h\"
@@ -392,10 +517,10 @@ ${ARCHIVE_CRYPTO_C}
 int
 int
 main(int argc, char **argv)
 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;
   return 0;
 }
 }
 ")
 ")
@@ -404,10 +529,16 @@ main(int argc, char **argv)
 	FILE(WRITE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/check_crypto_md.c" "${SOURCE}")
 	FILE(WRITE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/check_crypto_md.c" "${SOURCE}")
 	MESSAGE(STATUS "Checking support for ARCHIVE_CRYPTO_${ALGORITHM}_${IMPLEMENTATION}")
 	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}
 	TRY_COMPILE(ARCHIVE_CRYPTO_${ALGORITHM}_${IMPLEMENTATION}
 	  ${CMAKE_BINARY_DIR}
 	  ${CMAKE_BINARY_DIR}
 	  ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/check_crypto_md.c
 	  ${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_LIBS}"
 	   "${TRY_CRYPTO_REQUIRED_INCLUDES}"
 	   "${TRY_CRYPTO_REQUIRED_INCLUDES}"
 	  OUTPUT_VARIABLE OUTPUT)
 	  OUTPUT_VARIABLE OUTPUT)
@@ -415,6 +546,7 @@ main(int argc, char **argv)
 	# Inform user whether or not we found it; if not, log why we didn't.
 	# Inform user whether or not we found it; if not, log why we didn't.
         IF (ARCHIVE_CRYPTO_${ALGORITHM}_${IMPLEMENTATION})
         IF (ARCHIVE_CRYPTO_${ALGORITHM}_${IMPLEMENTATION})
           MESSAGE(STATUS "Checking support for ARCHIVE_CRYPTO_${ALGORITHM}_${IMPLEMENTATION} -- found")
           MESSAGE(STATUS "Checking support for ARCHIVE_CRYPTO_${ALGORITHM}_${IMPLEMENTATION} -- found")
+		  SET(ARCHIVE_CRYPTO_${ALGORITHM} 1)
         ELSE (ARCHIVE_CRYPTO_${ALGORITHM}_${IMPLEMENTATION})
         ELSE (ARCHIVE_CRYPTO_${ALGORITHM}_${IMPLEMENTATION})
           MESSAGE(STATUS "Checking support for ARCHIVE_CRYPTO_${ALGORITHM}_${IMPLEMENTATION} -- not found")
           MESSAGE(STATUS "Checking support for ARCHIVE_CRYPTO_${ALGORITHM}_${IMPLEMENTATION} -- not found")
           FILE(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
           FILE(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
@@ -433,6 +565,7 @@ main(int argc, char **argv)
 	   LIST(REMOVE_DUPLICATES ADDITIONAL_LIBS)
 	   LIST(REMOVE_DUPLICATES ADDITIONAL_LIBS)
         ENDIF ("${IMPLEMENTATION}" MATCHES "^OPENSSL$" AND OPENSSL_FOUND)
         ENDIF ("${IMPLEMENTATION}" MATCHES "^OPENSSL$" AND OPENSSL_FOUND)
       ENDIF (ARCHIVE_CRYPTO_${ALGORITHM}_${IMPLEMENTATION})
       ENDIF (ARCHIVE_CRYPTO_${ALGORITHM}_${IMPLEMENTATION})
+      ENDIF(NOT ARCHIVE_CRYPTO_${ALGORITHM})
     ENDFOREACH(ALGORITHM ${ALGORITHMS})
     ENDFOREACH(ALGORITHM ${ALGORITHMS})
 ENDMACRO(CHECK_CRYPTO ALGORITHMS IMPLEMENTATION)
 ENDMACRO(CHECK_CRYPTO ALGORITHMS IMPLEMENTATION)
 
 
@@ -448,6 +581,7 @@ ENDMACRO(CHECK_CRYPTO ALGORITHMS IMPLEMENTATION)
 MACRO(CHECK_CRYPTO_WIN CRYPTO_LIST)
 MACRO(CHECK_CRYPTO_WIN CRYPTO_LIST)
   IF(WIN32 AND NOT CYGWIN)
   IF(WIN32 AND NOT CYGWIN)
     FOREACH(CRYPTO ${CRYPTO_LIST})
     FOREACH(CRYPTO ${CRYPTO_LIST})
+      IF(NOT ARCHIVE_CRYPTO_${CRYPTO})
       IF(NOT DEFINED ARCHIVE_CRYPTO_${CRYPTO}_WIN)
       IF(NOT DEFINED ARCHIVE_CRYPTO_${CRYPTO}_WIN)
 	STRING(TOUPPER "${CRYPTO}" crypto)
 	STRING(TOUPPER "${CRYPTO}" crypto)
 	SET(ALGID "")
 	SET(ALGID "")
@@ -467,9 +601,14 @@ MACRO(CHECK_CRYPTO_WIN CRYPTO_LIST)
 	    SET(ALGID "CALG_SHA_512")
 	    SET(ALGID "CALG_SHA_512")
 	ENDIF ("${CRYPTO}" MATCHES "^SHA512$")
 	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 <windows.h>
 #include <wincrypt.h>
 #include <wincrypt.h>
 
 
@@ -484,15 +623,22 @@ main(int argc, char **argv)
 	FILE(WRITE "${SOURCE_FILE}" "${SOURCE}")
 	FILE(WRITE "${SOURCE_FILE}" "${SOURCE}")
 	MESSAGE(STATUS "Checking support for ARCHIVE_CRYPTO_${CRYPTO}_WIN")
 	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
 	TRY_COMPILE(ARCHIVE_CRYPTO_${CRYPTO}_WIN
 	  ${CMAKE_BINARY_DIR}
 	  ${CMAKE_BINARY_DIR}
 	  ${SOURCE_FILE}
 	  ${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)
 	  OUTPUT_VARIABLE OUTPUT)
 
 
 	IF (ARCHIVE_CRYPTO_${CRYPTO}_WIN)
 	IF (ARCHIVE_CRYPTO_${CRYPTO}_WIN)
 	    MESSAGE(STATUS
 	    MESSAGE(STATUS
 	        "Checking support for ARCHIVE_CRYPTO_${CRYPTO}_WIN -- found")
 	        "Checking support for ARCHIVE_CRYPTO_${CRYPTO}_WIN -- found")
+		SET(ARCHIVE_CRYPTO_${CRYPTO} 1)
 	ELSE (ARCHIVE_CRYPTO_${CRYPTO}_WIN)
 	ELSE (ARCHIVE_CRYPTO_${CRYPTO}_WIN)
 	    MESSAGE(STATUS
 	    MESSAGE(STATUS
 	         "Checking support for ARCHIVE_CRYPTO_${CRYPTO}_WIN -- not found")
 	         "Checking support for ARCHIVE_CRYPTO_${CRYPTO}_WIN -- not found")
@@ -504,6 +650,7 @@ main(int argc, char **argv)
 	ENDIF (ARCHIVE_CRYPTO_${CRYPTO}_WIN)
 	ENDIF (ARCHIVE_CRYPTO_${CRYPTO}_WIN)
 
 
       ENDIF(NOT DEFINED ARCHIVE_CRYPTO_${CRYPTO}_WIN)
       ENDIF(NOT DEFINED ARCHIVE_CRYPTO_${CRYPTO}_WIN)
+      ENDIF(NOT ARCHIVE_CRYPTO_${CRYPTO})
     ENDFOREACH(CRYPTO)
     ENDFOREACH(CRYPTO)
   ENDIF(WIN32 AND NOT CYGWIN)
   ENDIF(WIN32 AND NOT CYGWIN)
 ENDMACRO(CHECK_CRYPTO_WIN CRYPTO_LIST)
 ENDMACRO(CHECK_CRYPTO_WIN CRYPTO_LIST)
@@ -517,7 +664,21 @@ ENDMACRO(CHECK_CRYPTO_WIN CRYPTO_LIST)
 #
 #
 MACRO(CHECK_ICONV LIB TRY_ICONV_CONST)
 MACRO(CHECK_ICONV LIB TRY_ICONV_CONST)
   IF(NOT HAVE_ICONV)
   IF(NOT HAVE_ICONV)
-    CHECK_C_SOURCE_COMPILES(
+    CMAKE_PUSH_CHECK_STATE()	# Save the state of the variables
+    IF ("CMAKE_C_COMPILER_ID" MATCHES "^GNU$")
+      #
+      # During checking iconv proto type, we should use -Werror to avoid the
+      # success of iconv detection with a warnig which success is a miss
+      # detection. So this needs for all build mode(even it's a release mode).
+      #
+      SET(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -Werror")
+    ENDIF ("CMAKE_C_COMPILER_ID" MATCHES "^GNU$")
+    IF (MSVC)
+      # NOTE: /WX option is the same as gcc's -Werror option.
+      SET(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} /WX")
+    ENDIF (MSVC)
+    #
+    LIBARCHIVE_CHECK_C_SOURCE_COMPILES(
       "#include <stdlib.h>
       "#include <stdlib.h>
        #include <iconv.h>
        #include <iconv.h>
        int main() {
        int main() {
@@ -532,10 +693,12 @@ MACRO(CHECK_ICONV LIB TRY_ICONV_CONST)
       SET(HAVE_ICONV true)
       SET(HAVE_ICONV true)
       SET(ICONV_CONST ${TRY_ICONV_CONST})
       SET(ICONV_CONST ${TRY_ICONV_CONST})
     ENDIF(HAVE_ICONV_${LIB}_${TRY_ICONV_CONST})
     ENDIF(HAVE_ICONV_${LIB}_${TRY_ICONV_CONST})
+    CMAKE_POP_CHECK_STATE()	# Restore the state of the variables
   ENDIF(NOT HAVE_ICONV)
   ENDIF(NOT HAVE_ICONV)
 ENDMACRO(CHECK_ICONV TRY_ICONV_CONST)
 ENDMACRO(CHECK_ICONV TRY_ICONV_CONST)
 
 
 IF(ENABLE_ICONV)
 IF(ENABLE_ICONV)
+  CMAKE_PUSH_CHECK_STATE()	# Save the state of the variables
   FIND_PATH(ICONV_INCLUDE_DIR iconv.h)
   FIND_PATH(ICONV_INCLUDE_DIR iconv.h)
   MARK_AS_ADVANCED(ICONV_INCLUDE_DIR)
   MARK_AS_ADVANCED(ICONV_INCLUDE_DIR)
   IF(ICONV_INCLUDE_DIR)
   IF(ICONV_INCLUDE_DIR)
@@ -547,9 +710,30 @@ IF(ENABLE_ICONV)
     CHECK_ICONV("libc" "")
     CHECK_ICONV("libc" "")
 
 
     # If iconv isn't in libc and we have a libiconv, try that.
     # 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)
     IF(NOT HAVE_ICONV AND LIBICONV_PATH)
       LIST(APPEND CMAKE_REQUIRED_LIBRARIES ${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" "const")
       CHECK_ICONV("libiconv" "")
       CHECK_ICONV("libiconv" "")
       IF (HAVE_ICONV)
       IF (HAVE_ICONV)
@@ -561,19 +745,36 @@ IF(ENABLE_ICONV)
   # Find locale_charset() for libiconv.
   # Find locale_charset() for libiconv.
   #
   #
   IF(LIBICONV_PATH)
   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_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)
         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)
   ENDIF(LIBICONV_PATH)
+  CMAKE_POP_CHECK_STATE()	# Restore the state of the variables
 ELSE(ENABLE_ICONV)
 ELSE(ENABLE_ICONV)
   # Make sure ICONV variables are not in CACHE after ENABLE_ICONV disabled
   # Make sure ICONV variables are not in CACHE after ENABLE_ICONV disabled
   # (once enabled).
   # (once enabled).
@@ -585,6 +786,10 @@ ELSE(ENABLE_ICONV)
   UNSET(HAVE_ICONV_libiconv_const CACHE)
   UNSET(HAVE_ICONV_libiconv_const CACHE)
   UNSET(ICONV_INCLUDE_DIR CACHE)
   UNSET(ICONV_INCLUDE_DIR CACHE)
   UNSET(LIBICONV_PATH CACHE)
   UNSET(LIBICONV_PATH CACHE)
+  UNSET(LIBICONV_DLL CACHE)
+  UNSET(LIBICONV_STATIC CACHE)
+  UNSET(LIBCHARSET_DLL CACHE)
+  UNSET(LIBCHARSET_STATIC CACHE)
 ENDIF(ENABLE_ICONV)
 ENDIF(ENABLE_ICONV)
 
 
 IF(0) # CMake does not need XML support in libarchive
 IF(0) # CMake does not need XML support in libarchive
@@ -593,6 +798,7 @@ IF(0) # CMake does not need XML support in libarchive
 #
 #
 FIND_PACKAGE(LibXml2)
 FIND_PACKAGE(LibXml2)
 IF(LIBXML2_FOUND)
 IF(LIBXML2_FOUND)
+  CMAKE_PUSH_CHECK_STATE()	# Save the state of the variables
   INCLUDE_DIRECTORIES(${LIBXML2_INCLUDE_DIR})
   INCLUDE_DIRECTORIES(${LIBXML2_INCLUDE_DIR})
   LIST(APPEND ADDITIONAL_LIBS ${LIBXML2_LIBRARIES})
   LIST(APPEND ADDITIONAL_LIBS ${LIBXML2_LIBRARIES})
   SET(HAVE_LIBXML2 1)
   SET(HAVE_LIBXML2 1)
@@ -600,31 +806,151 @@ IF(LIBXML2_FOUND)
   SET(CMAKE_REQUIRED_INCLUDES ${ICONV_INCLUDE_DIR} ${LIBXML2_INCLUDE_DIR})
   SET(CMAKE_REQUIRED_INCLUDES ${ICONV_INCLUDE_DIR} ${LIBXML2_INCLUDE_DIR})
   CHECK_INCLUDE_FILES("libxml/xmlreader.h" HAVE_LIBXML_XMLREADER_H)
   CHECK_INCLUDE_FILES("libxml/xmlreader.h" HAVE_LIBXML_XMLREADER_H)
   CHECK_INCLUDE_FILES("libxml/xmlwriter.h" HAVE_LIBXML_XMLWRITER_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)
 ELSE(LIBXML2_FOUND)
   #
   #
   # Find Expat
   # Find Expat
   #
   #
   FIND_PACKAGE(EXPAT)
   FIND_PACKAGE(EXPAT)
   IF(EXPAT_FOUND)
   IF(EXPAT_FOUND)
+    CMAKE_PUSH_CHECK_STATE()	# Save the state of the variables
     INCLUDE_DIRECTORIES(${EXPAT_INCLUDE_DIR})
     INCLUDE_DIRECTORIES(${EXPAT_INCLUDE_DIR})
     LIST(APPEND ADDITIONAL_LIBS ${EXPAT_LIBRARIES})
     LIST(APPEND ADDITIONAL_LIBS ${EXPAT_LIBRARIES})
     SET(HAVE_LIBEXPAT 1)
     SET(HAVE_LIBEXPAT 1)
     LA_CHECK_INCLUDE_FILE("expat.h" HAVE_EXPAT_H)
     LA_CHECK_INCLUDE_FILE("expat.h" HAVE_EXPAT_H)
+    CMAKE_POP_CHECK_STATE()	# Restore the state of the variables
   ENDIF(EXPAT_FOUND)
   ENDIF(EXPAT_FOUND)
 ENDIF(LIBXML2_FOUND)
 ENDIF(LIBXML2_FOUND)
+MARK_AS_ADVANCED(CLEAR LIBXML2_INCLUDE_DIR)
+MARK_AS_ADVANCED(CLEAR LIBXML2_LIBRARIES)
 ENDIF()
 ENDIF()
 
 
+#
+# POSIX Regular Expression support
+#
+IF(POSIX_REGEX_LIB MATCHES "^(AUTO|LIBC|LIBREGEX)$")
+  #
+  # If PCREPOSIX is not found or not requested, try using regex
+  # from libc or libregex
+  #
+  FIND_PATH(REGEX_INCLUDE_DIR regex.h)
+  IF(REGEX_INCLUDE_DIR)
+    CHECK_FUNCTION_EXISTS_GLIBC(regcomp HAVE_REGCOMP_LIBC)
+    #
+    # If libc does not provide regex, find libregex.
+    #
+    IF(NOT HAVE_REGCOMP_LIBC)
+      CMAKE_PUSH_CHECK_STATE()	# Save the state of the variables
+      FIND_LIBRARY(REGEX_LIBRARY regex)
+      IF(REGEX_LIBRARY)
+        SET(CMAKE_REQUIRED_LIBRARIES ${REGEX_LIBRARY})
+        CHECK_FUNCTION_EXISTS_GLIBC(regcomp HAVE_REGCOMP_LIBREGEX)
+        IF(HAVE_REGCOMP_LIBREGEX)
+          LIST(APPEND ADDITIONAL_LIBS ${REGEX_LIBRARY})
+          #
+          # If regex.h is not found, retry looking for regex.h at
+          # REGEX_INCLUDE_DIR
+          #
+          IF(NOT HAVE_REGEX_H)
+            UNSET(HAVE_REGEX_H CACHE)
+            INCLUDE_DIRECTORIES(${REGEX_INCLUDE_DIR})
+            SET(CMAKE_REQUIRED_INCLUDES ${REGEX_INCLUDE_DIR})
+            LA_CHECK_INCLUDE_FILE("regex.h" HAVE_REGEX_H)
+          ENDIF(NOT HAVE_REGEX_H)
+          # Test if a macro is needed for the library.
+          TRY_MACRO_FOR_LIBRARY(
+            "${REGEX_INCLUDE_DIR}" "${REGEX_LIBRARY}"
+            COMPILES
+            "#include <stddef.h>\n#include <regex.h>\nint main() {regex_t r;return regcomp(&r, \"\", 0);}"
+            "USE_REGEX_DLL;USE_REGEX_STATIC")
+          IF(USE_REGEX_DLL)
+            ADD_DEFINITIONS(-DUSE_REGEX_DLL)
+          ELSEIF(USE_REGEX_STATIC)
+            ADD_DEFINITIONS(-DUSE_REGEX_STATIC)
+          ENDIF(USE_REGEX_DLL)
+        ENDIF(HAVE_REGCOMP_LIBREGEX)
+      ENDIF(REGEX_LIBRARY)
+      CMAKE_POP_CHECK_STATE()	# Restore the state of the variables
+    ENDIF(NOT HAVE_REGCOMP_LIBC)
+  ENDIF(REGEX_INCLUDE_DIR)
+  IF(HAVE_REGCOMP_LIBC OR HAVE_REGCOMP_LIBREGEX)
+    SET(FOUND_POSIX_REGEX_LIB 1)
+  ENDIF(HAVE_REGCOMP_LIBC OR HAVE_REGCOMP_LIBREGEX)
+ENDIF(POSIX_REGEX_LIB MATCHES "^(AUTO|LIBC|LIBREGEX)$")
+
+IF(NOT FOUND_POSIX_REGEX_LIB AND POSIX_REGEX_LIB MATCHES "^(AUTO|LIBPCREPOSIX)$")
+  #
+  # If requested, try finding library for PCREPOSIX
+  #
+  FIND_PACKAGE(LibGCC)
+  FIND_PACKAGE(PCREPOSIX)
+  IF(PCREPOSIX_FOUND)
+    INCLUDE_DIRECTORIES(${PCRE_INCLUDE_DIR})
+    LIST(APPEND ADDITIONAL_LIBS ${PCREPOSIX_LIBRARIES})
+    # Test if a macro is needed for the library.
+    TRY_MACRO_FOR_LIBRARY(
+      "${PCRE_INCLUDE_DIR}" "${PCREPOSIX_LIBRARIES}"
+      COMPILES
+      "#include <pcreposix.h>\nint main() {regex_t r;return regcomp(&r, \"\", 0);}"
+      "WITHOUT_PCRE_STATIC;PCRE_STATIC")
+    IF(NOT WITHOUT_PCRE_STATIC AND PCRE_STATIC)
+      ADD_DEFINITIONS(-DPCRE_STATIC)
+	ELSEIF(NOT WITHOUT_PCRE_STATIC AND NOT PCRE_STATIC AND PCRE_FOUND)
+	  # Determine if pcre static libraries are to be used.
+      LIST(APPEND ADDITIONAL_LIBS ${PCRE_LIBRARIES})
+      SET(TMP_LIBRARIES ${PCREPOSIX_LIBRARIES} ${PCRE_LIBRARIES})
+      MESSAGE(STATUS "trying again with -lpcre included")
+      TRY_MACRO_FOR_LIBRARY(
+        "${PCRE_INCLUDE_DIR}" "${TMP_LIBRARIES}"
+        COMPILES
+        "#include <pcreposix.h>\nint main() {regex_t r;return regcomp(&r, \"\", 0);}"
+        "WITHOUT_PCRE_STATIC;PCRE_STATIC")
+      IF(NOT WITHOUT_PCRE_STATIC AND PCRE_STATIC)
+        ADD_DEFINITIONS(-DPCRE_STATIC)
+      ELSEIF(NOT WITHOUT_PCRE_STATIC AND NOT PCRE_STATIC AND MSVC AND LIBGCC_FOUND)
+        # When doing a Visual Studio build using pcre static libraries
+        # built using the mingw toolchain, -lgcc is needed to resolve
+        # ___chkstk_ms.
+        MESSAGE(STATUS "Visual Studio build detected, trying again with -lgcc included")
+        LIST(APPEND ADDITIONAL_LIBS ${LIBGCC_LIBRARIES})
+        SET(TMP_LIBRARIES ${PCREPOSIX_LIBRARIES} ${PCRE_LIBRARIES} ${LIBGCC_LIBRARIES})
+          TRY_MACRO_FOR_LIBRARY(
+            "${PCRE_INCLUDE_DIR}" "${TMP_LIBRARIES}"
+            COMPILES
+            "#include <pcreposix.h>\nint main() {regex_t r;return regcomp(&r, \"\", 0);}"
+            "WITHOUT_PCRE_STATIC;PCRE_STATIC")
+          IF(NOT WITHOUT_PCRE_STATIC AND PCRE_STATIC)
+            ADD_DEFINITIONS(-DPCRE_STATIC)
+          ENDIF(NOT WITHOUT_PCRE_STATIC AND PCRE_STATIC)
+      ENDIF(NOT WITHOUT_PCRE_STATIC AND PCRE_STATIC)
+    ENDIF(NOT WITHOUT_PCRE_STATIC AND PCRE_STATIC)
+  ENDIF(PCREPOSIX_FOUND)
+  MARK_AS_ADVANCED(CLEAR PCRE_INCLUDE_DIR)
+  MARK_AS_ADVANCED(CLEAR PCREPOSIX_LIBRARIES)
+  MARK_AS_ADVANCED(CLEAR PCRE_LIBRARIES)
+  MARK_AS_ADVANCED(CLEAR LIBGCC_LIBRARIES)
+ENDIF(NOT FOUND_POSIX_REGEX_LIB AND POSIX_REGEX_LIB MATCHES "^(AUTO|LIBPCREPOSIX)$")
+
 #
 #
 # Check functions
 # Check functions
 #
 #
+CMAKE_PUSH_CHECK_STATE()	# Save the state of the variables
 IF ("CMAKE_C_COMPILER_ID" MATCHES "^GNU$")
 IF ("CMAKE_C_COMPILER_ID" MATCHES "^GNU$")
   #
   #
   # During checking functions, we should use -fno-builtin to avoid the
   # During checking functions, we should use -fno-builtin to avoid the
   # failure of function detection which failure is an error "conflicting
   # failure of function detection which failure is an error "conflicting
   # types for built-in function" caused by using -Werror option.
   # 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")
   SET(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -fno-builtin")
 ENDIF ("CMAKE_C_COMPILER_ID" MATCHES "^GNU$")
 ENDIF ("CMAKE_C_COMPILER_ID" MATCHES "^GNU$")
 CHECK_SYMBOL_EXISTS(_CrtSetReportMode "crtdbg.h" HAVE__CrtSetReportMode)
 CHECK_SYMBOL_EXISTS(_CrtSetReportMode "crtdbg.h" HAVE__CrtSetReportMode)
@@ -632,6 +958,7 @@ CHECK_FUNCTION_EXISTS_GLIBC(chflags HAVE_CHFLAGS)
 CHECK_FUNCTION_EXISTS_GLIBC(chown HAVE_CHOWN)
 CHECK_FUNCTION_EXISTS_GLIBC(chown HAVE_CHOWN)
 CHECK_FUNCTION_EXISTS_GLIBC(chroot HAVE_CHROOT)
 CHECK_FUNCTION_EXISTS_GLIBC(chroot HAVE_CHROOT)
 CHECK_FUNCTION_EXISTS_GLIBC(ctime_r HAVE_CTIME_R)
 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(fchdir HAVE_FCHDIR)
 CHECK_FUNCTION_EXISTS_GLIBC(fchflags HAVE_FCHFLAGS)
 CHECK_FUNCTION_EXISTS_GLIBC(fchflags HAVE_FCHFLAGS)
 CHECK_FUNCTION_EXISTS_GLIBC(fchmod HAVE_FCHMOD)
 CHECK_FUNCTION_EXISTS_GLIBC(fchmod HAVE_FCHMOD)
@@ -663,7 +990,6 @@ CHECK_FUNCTION_EXISTS_GLIBC(localtime_r HAVE_LOCALTIME_R)
 CHECK_FUNCTION_EXISTS_GLIBC(lstat HAVE_LSTAT)
 CHECK_FUNCTION_EXISTS_GLIBC(lstat HAVE_LSTAT)
 CHECK_FUNCTION_EXISTS_GLIBC(lutimes HAVE_LUTIMES)
 CHECK_FUNCTION_EXISTS_GLIBC(lutimes HAVE_LUTIMES)
 CHECK_FUNCTION_EXISTS_GLIBC(mbrtowc HAVE_MBRTOWC)
 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(memmove HAVE_MEMMOVE)
 CHECK_FUNCTION_EXISTS_GLIBC(mkdir HAVE_MKDIR)
 CHECK_FUNCTION_EXISTS_GLIBC(mkdir HAVE_MKDIR)
 CHECK_FUNCTION_EXISTS_GLIBC(mkfifo HAVE_MKFIFO)
 CHECK_FUNCTION_EXISTS_GLIBC(mkfifo HAVE_MKFIFO)
@@ -673,6 +999,7 @@ CHECK_FUNCTION_EXISTS_GLIBC(nl_langinfo HAVE_NL_LANGINFO)
 CHECK_FUNCTION_EXISTS_GLIBC(openat HAVE_OPENAT)
 CHECK_FUNCTION_EXISTS_GLIBC(openat HAVE_OPENAT)
 CHECK_FUNCTION_EXISTS_GLIBC(pipe HAVE_PIPE)
 CHECK_FUNCTION_EXISTS_GLIBC(pipe HAVE_PIPE)
 CHECK_FUNCTION_EXISTS_GLIBC(poll HAVE_POLL)
 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(readlink HAVE_READLINK)
 CHECK_FUNCTION_EXISTS_GLIBC(select HAVE_SELECT)
 CHECK_FUNCTION_EXISTS_GLIBC(select HAVE_SELECT)
 CHECK_FUNCTION_EXISTS_GLIBC(setenv HAVE_SETENV)
 CHECK_FUNCTION_EXISTS_GLIBC(setenv HAVE_SETENV)
@@ -697,7 +1024,6 @@ CHECK_FUNCTION_EXISTS_GLIBC(wcrtomb HAVE_WCRTOMB)
 CHECK_FUNCTION_EXISTS_GLIBC(wcscmp HAVE_WCSCMP)
 CHECK_FUNCTION_EXISTS_GLIBC(wcscmp HAVE_WCSCMP)
 CHECK_FUNCTION_EXISTS_GLIBC(wcscpy HAVE_WCSCPY)
 CHECK_FUNCTION_EXISTS_GLIBC(wcscpy HAVE_WCSCPY)
 CHECK_FUNCTION_EXISTS_GLIBC(wcslen HAVE_WCSLEN)
 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(wctomb HAVE_WCTOMB)
 CHECK_FUNCTION_EXISTS_GLIBC(_ctime64_s HAVE__CTIME64_S)
 CHECK_FUNCTION_EXISTS_GLIBC(_ctime64_s HAVE__CTIME64_S)
 CHECK_FUNCTION_EXISTS_GLIBC(_fseeki64 HAVE__FSEEKI64)
 CHECK_FUNCTION_EXISTS_GLIBC(_fseeki64 HAVE__FSEEKI64)
@@ -714,21 +1040,18 @@ CHECK_FUNCTION_EXISTS(vprintf HAVE_VPRINTF)
 CHECK_FUNCTION_EXISTS(wmemcmp HAVE_WMEMCMP)
 CHECK_FUNCTION_EXISTS(wmemcmp HAVE_WMEMCMP)
 CHECK_FUNCTION_EXISTS(wmemcpy HAVE_WMEMCPY)
 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
 # Make sure we have the POSIX version of readdir_r, not the
 # older 2-argument version.
 # older 2-argument version.
-CHECK_C_SOURCE_COMPILES(
+LIBARCHIVE_CHECK_C_SOURCE_COMPILES(
   "#include <dirent.h>\nint main() {DIR *d = opendir(\".\"); struct dirent e,*r; return readdir_r(d,&e,&r);}"
   "#include <dirent.h>\nint main() {DIR *d = opendir(\".\"); struct dirent e,*r; return readdir_r(d,&e,&r);}"
   HAVE_READDIR_R)
   HAVE_READDIR_R)
 
 
 
 
 # Only detect readlinkat() if we also have AT_FDCWD in unistd.h.
 # Only detect readlinkat() if we also have AT_FDCWD in unistd.h.
 # NOTE: linux requires fcntl.h for AT_FDCWD.
 # NOTE: linux requires fcntl.h for AT_FDCWD.
-CHECK_C_SOURCE_COMPILES(
+LIBARCHIVE_CHECK_C_SOURCE_COMPILES(
   "#include <fcntl.h>\n#include <unistd.h>\nint main() {char buf[10]; return readlinkat(AT_FDCWD, \"\", buf, 0);}"
   "#include <fcntl.h>\n#include <unistd.h>\nint main() {char buf[10]; return readlinkat(AT_FDCWD, \"\", buf, 0);}"
   HAVE_READLINKAT)
   HAVE_READLINKAT)
 
 
@@ -737,10 +1060,10 @@ CHECK_C_SOURCE_COMPILES(
 # of interest and verify that the result can be linked.
 # of interest and verify that the result can be linked.
 # CHECK_FUNCTION_EXISTS doesn't accept a header argument,
 # CHECK_FUNCTION_EXISTS doesn't accept a header argument,
 # CHECK_SYMBOL_EXISTS doesn't test linkage.
 # CHECK_SYMBOL_EXISTS doesn't test linkage.
-CHECK_C_SOURCE_COMPILES(
+LIBARCHIVE_CHECK_C_SOURCE_COMPILES(
   "#include <sys/mkdev.h>\nint main() { return major(256); }"
   "#include <sys/mkdev.h>\nint main() { return major(256); }"
   MAJOR_IN_MKDEV)
   MAJOR_IN_MKDEV)
-CHECK_C_SOURCE_COMPILES(
+LIBARCHIVE_CHECK_C_SOURCE_COMPILES(
   "#include <sys/sysmacros.h>\nint main() { return major(256); }"
   "#include <sys/sysmacros.h>\nint main() { return major(256); }"
   MAJOR_IN_SYSMACROS)
   MAJOR_IN_SYSMACROS)
 
 
@@ -1036,6 +1359,8 @@ IF(ENABLE_ACL)
   CHECK_FUNCTION_EXISTS(acl_get_perm_np HAVE_ACL_GET_PERM_NP)
   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 HAVE_ACL_GET_LINK)
   CHECK_FUNCTION_EXISTS(acl_get_link_np HAVE_ACL_GET_LINK_NP)
   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
   # MacOS has an acl.h that isn't POSIX.  It can be detected by
   # checking for ACL_USER
   # checking for ACL_USER

+ 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)

+ 106 - 0
Utilities/cmlibarchive/build/cmake/LibarchiveCheckCSourceCompiles.cmake

@@ -0,0 +1,106 @@
+# - Check if given C source compiles and links into an executable
+# CHECK_C_SOURCE_COMPILES(<code> <var> [FAIL_REGEX <fail-regex>])
+#  <code>       - source code to try to compile, must define 'main'
+#  <var>        - variable to store whether the source code compiled
+#  <fail-regex> - fail if test output matches this regex
+# The following variables may be set before calling this macro to
+# modify the way the check is run:
+#
+#  CMAKE_REQUIRED_FLAGS = string of compile command line flags
+#  CMAKE_REQUIRED_DEFINITIONS = list of macros to define (-DFOO=bar)
+#  CMAKE_REQUIRED_INCLUDES = list of include directories
+#  CMAKE_REQUIRED_LIBRARIES = list of libraries to link
+
+#=============================================================================
+# Copyright 2005-2009 Kitware, Inc.
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file Copyright.txt for details.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+#=============================================================================
+# (To distribute this file outside of CMake, substitute the full
+#  License text for the above reference.)
+
+#
+# Extra arguments added by libarchive
+# CMAKE_REQUIRED_LINKER_FLAGS = string of linker command line flags
+#
+
+include(CMakeExpandImportedTargets)
+
+
+macro(LIBARCHIVE_CHECK_C_SOURCE_COMPILES SOURCE VAR)
+  if("${VAR}" MATCHES "^${VAR}$")
+    set(_FAIL_REGEX)
+    set(_key)
+    foreach(arg ${ARGN})
+      if("${arg}" MATCHES "^(FAIL_REGEX)$")
+        set(_key "${arg}")
+      elseif(_key)
+        list(APPEND _${_key} "${arg}")
+      else()
+        message(FATAL_ERROR "Unknown argument:\n  ${arg}\n")
+      endif()
+    endforeach()
+    set(MACRO_CHECK_FUNCTION_DEFINITIONS
+      "-D${VAR} ${CMAKE_REQUIRED_FLAGS}")
+    if(CMAKE_REQUIRED_LIBRARIES)
+      # this one translates potentially used imported library targets to their files on disk
+      CMAKE_EXPAND_IMPORTED_TARGETS(_ADJUSTED_CMAKE_REQUIRED_LIBRARIES  LIBRARIES  ${CMAKE_REQUIRED_LIBRARIES} CONFIGURATION "${CMAKE_TRY_COMPILE_CONFIGURATION}")
+      set(CHECK_C_SOURCE_COMPILES_ADD_LIBRARIES
+        "-DLINK_LIBRARIES:STRING=${_ADJUSTED_CMAKE_REQUIRED_LIBRARIES}")
+    else()
+      set(CHECK_C_SOURCE_COMPILES_ADD_LIBRARIES)
+    endif()
+    if(CMAKE_REQUIRED_INCLUDES)
+      set(CHECK_C_SOURCE_COMPILES_ADD_INCLUDES
+        "-DINCLUDE_DIRECTORIES:STRING=${CMAKE_REQUIRED_INCLUDES}")
+    else()
+      set(CHECK_C_SOURCE_COMPILES_ADD_INCLUDES)
+    endif()
+	if(CMAKE_REQUIRED_LINKER_FLAGS)
+	  set(CHECK_C_SOURCE_COMPILES_ADD_LINKER_FLAGS
+	    "-DCMAKE_EXE_LINKER_FLAGS:STRING=${CMAKE_REQUIRED_LINKER_FLAGS} -DCMAKE_SHARED_LINKER_FLAGS:STRING=${CMAKE_REQUIRED_LINKER_FLAGS} -DCMAKE_MODULE_LINKER_FLAGS:STRING=${CMAKE_REQUIRED_LINKER_FLAGS}")
+	else()
+	  set(CHECK_C_SOURCE_COMPILES_ADD_LINKER_FLAGS)
+	endif()
+    file(WRITE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/src.c"
+      "${SOURCE}\n")
+
+    message(STATUS "Performing Test ${VAR}")
+    try_compile(${VAR}
+      ${CMAKE_BINARY_DIR}
+      ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/src.c
+      COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS}
+      CMAKE_FLAGS -DCOMPILE_DEFINITIONS:STRING=${MACRO_CHECK_FUNCTION_DEFINITIONS} ${CHECK_C_SOURCE_COMPILES_ADD_LINKER_FLAGS}
+      "${CHECK_C_SOURCE_COMPILES_ADD_LIBRARIES}"
+      "${CHECK_C_SOURCE_COMPILES_ADD_INCLUDES}"
+      OUTPUT_VARIABLE OUTPUT)
+
+    foreach(_regex ${_FAIL_REGEX})
+      if("${OUTPUT}" MATCHES "${_regex}")
+        set(${VAR} 0)
+      endif()
+    endforeach()
+
+    if(${VAR})
+      set(${VAR} 1 CACHE INTERNAL "Test ${VAR}")
+      message(STATUS "Performing Test ${VAR} - Success")
+      file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+        "Performing C SOURCE FILE Test ${VAR} succeded with the following output:\n"
+        "${OUTPUT}\n"
+        "Source file was:\n${SOURCE}\n")
+    else()
+      message(STATUS "Performing Test ${VAR} - Failed")
+      set(${VAR} "" CACHE INTERNAL "Test ${VAR}")
+      file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+        "Performing C SOURCE FILE Test ${VAR} failed with the following output:\n"
+        "${OUTPUT}\n"
+        "Source file was:\n${SOURCE}\n")
+    endif()
+  endif()
+endmacro()
+

+ 102 - 0
Utilities/cmlibarchive/build/cmake/LibarchiveCheckCSourceRuns.cmake

@@ -0,0 +1,102 @@
+# - Check if the given C source code compiles and runs.
+# CHECK_C_SOURCE_RUNS(<code> <var>)
+#  <code>   - source code to try to compile
+#  <var>    - variable to store the result
+#             (1 for success, empty for failure)
+# The following variables may be set before calling this macro to
+# modify the way the check is run:
+#
+#  CMAKE_REQUIRED_FLAGS = string of compile command line flags
+#  CMAKE_REQUIRED_DEFINITIONS = list of macros to define (-DFOO=bar)
+#  CMAKE_REQUIRED_INCLUDES = list of include directories
+#  CMAKE_REQUIRED_LIBRARIES = list of libraries to link
+
+#=============================================================================
+# Copyright 2006-2009 Kitware, Inc.
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file Copyright.txt for details.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+#=============================================================================
+# (To distribute this file outside of CMake, substitute the full
+#  License text for the above reference.)
+
+#
+# Extra arguments added by libarchive
+# CMAKE_REQUIRED_LINKER_FLAGS = string of linker command line flags
+#
+
+include(CMakeExpandImportedTargets)
+
+
+macro(LIBARCHIVE_CHECK_C_SOURCE_RUNS SOURCE VAR)
+  if("${VAR}" MATCHES "^${VAR}$")
+    set(MACRO_CHECK_FUNCTION_DEFINITIONS
+      "-D${VAR} ${CMAKE_REQUIRED_FLAGS}")
+    if(CMAKE_REQUIRED_LIBRARIES)
+      # this one translates potentially used imported library targets to their files on disk
+      CMAKE_EXPAND_IMPORTED_TARGETS(_ADJUSTED_CMAKE_REQUIRED_LIBRARIES  LIBRARIES  ${CMAKE_REQUIRED_LIBRARIES} CONFIGURATION "${CMAKE_TRY_COMPILE_CONFIGURATION}")
+      set(CHECK_C_SOURCE_COMPILES_ADD_LIBRARIES
+        "-DLINK_LIBRARIES:STRING=${_ADJUSTED_CMAKE_REQUIRED_LIBRARIES}")
+    else()
+      set(CHECK_C_SOURCE_COMPILES_ADD_LIBRARIES)
+    endif()
+    if(CMAKE_REQUIRED_INCLUDES)
+      set(CHECK_C_SOURCE_COMPILES_ADD_INCLUDES
+        "-DINCLUDE_DIRECTORIES:STRING=${CMAKE_REQUIRED_INCLUDES}")
+    else()
+      set(CHECK_C_SOURCE_COMPILES_ADD_INCLUDES)
+    endif()
+	if(CMAKE_REQUIRED_LINKER_FLAGS)
+	  set(CHECK_C_SOURCE_COMPILES_ADD_LINKER_FLAGS
+	    "-DCMAKE_EXE_LINKER_FLAGS:STRING=${CMAKE_REQUIRED_LINKER_FLAGS} -DCMAKE_SHARED_LINKER_FLAGS:STRING=${CMAKE_REQUIRED_LINKER_FLAGS} -DCMAKE_MODULE_LINKER_FLAGS:STRING=${CMAKE_REQUIRED_LINKER_FLAGS}")
+	else()
+	  set(CHECK_C_SOURCE_COMPILES_ADD_LINKER_FLAGS)
+	endif()
+    file(WRITE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/src.c"
+      "${SOURCE}\n")
+
+    message(STATUS "Performing Test ${VAR}")
+    try_run(${VAR}_EXITCODE ${VAR}_COMPILED
+      ${CMAKE_BINARY_DIR}
+      ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/src.c
+      COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS}
+      CMAKE_FLAGS -DCOMPILE_DEFINITIONS:STRING=${MACRO_CHECK_FUNCTION_DEFINITIONS} ${CHECK_C_SOURCE_COMPILES_ADD_LINKER_FLAGS}
+      -DCMAKE_SKIP_RPATH:BOOL=${CMAKE_SKIP_RPATH}
+      "${CHECK_C_SOURCE_COMPILES_ADD_LIBRARIES}"
+      "${CHECK_C_SOURCE_COMPILES_ADD_INCLUDES}"
+      COMPILE_OUTPUT_VARIABLE OUTPUT)
+    # if it did not compile make the return value fail code of 1
+    if(NOT ${VAR}_COMPILED)
+      set(${VAR}_EXITCODE 1)
+    endif()
+    # if the return value was 0 then it worked
+    if("${${VAR}_EXITCODE}" EQUAL 0)
+      set(${VAR} 1 CACHE INTERNAL "Test ${VAR}")
+      message(STATUS "Performing Test ${VAR} - Success")
+      file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+        "Performing C SOURCE FILE Test ${VAR} succeded with the following output:\n"
+        "${OUTPUT}\n"
+        "Return value: ${${VAR}}\n"
+        "Source file was:\n${SOURCE}\n")
+    else()
+      if(CMAKE_CROSSCOMPILING AND "${${VAR}_EXITCODE}" MATCHES  "FAILED_TO_RUN")
+        set(${VAR} "${${VAR}_EXITCODE}")
+      else()
+        set(${VAR} "" CACHE INTERNAL "Test ${VAR}")
+      endif()
+
+      message(STATUS "Performing Test ${VAR} - Failed")
+      file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+        "Performing C SOURCE FILE Test ${VAR} failed with the following output:\n"
+        "${OUTPUT}\n"
+        "Return value: ${${VAR}_EXITCODE}\n"
+        "Source file was:\n${SOURCE}\n")
+
+    endif()
+  endif()
+endmacro()
+

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

@@ -393,6 +393,9 @@ typedef uint64_t uintmax_t;
    */
    */
 #cmakedefine HAVE_DIRENT_H 1
 #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. */
 /* Define to 1 if you have the <dlfcn.h> header file. */
 #cmakedefine HAVE_DLFCN_H 1
 #cmakedefine HAVE_DLFCN_H 1
 
 
@@ -579,12 +582,27 @@ typedef uint64_t uintmax_t;
 /* Define to 1 if you have the `expat' library (-lexpat). */
 /* Define to 1 if you have the `expat' library (-lexpat). */
 #cmakedefine HAVE_LIBEXPAT 1
 #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). */
 /* Define to 1 if you have the `lzma' library (-llzma). */
 #cmakedefine HAVE_LIBLZMA 1
 #cmakedefine HAVE_LIBLZMA 1
 
 
 /* Define to 1 if you have the `lzmadec' library (-llzmadec). */
 /* Define to 1 if you have the `lzmadec' library (-llzmadec). */
 #cmakedefine HAVE_LIBLZMADEC 1
 #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). */
 /* Define to 1 if you have the `xml2' library (-lxml2). */
 #cmakedefine HAVE_LIBXML2 1
 #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. */
 /* Define to 1 if you have the <linux/magic.h> header file. */
 #cmakedefine HAVE_LINUX_MAGIC_H 1
 #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. */
 /* Define to 1 if you have the `listea' function. */
 #cmakedefine HAVE_LISTEA 1
 #cmakedefine HAVE_LISTEA 1
 
 
@@ -664,12 +685,15 @@ typedef uint64_t uintmax_t;
 /* Define to 1 if you have the <lzma.h> header file. */
 /* Define to 1 if you have the <lzma.h> header file. */
 #cmakedefine HAVE_LZMA_H 1
 #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. */
 /* Define to 1 if you have the `mbrtowc' function. */
 #cmakedefine HAVE_MBRTOWC 1
 #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. */
 /* Define to 1 if you have the `memmove' function. */
 #cmakedefine HAVE_MEMMOVE 1
 #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'. */
 /* Define to 1 if you have the <ndir.h> header file, and it defines `DIR'. */
 #cmakedefine HAVE_NDIR_H 1
 #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. */
 /* Define to 1 if you have the `nl_langinfo' function. */
 #cmakedefine HAVE_NL_LANGINFO 1
 #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. */
 /* Define to 1 if you have the <paths.h> header file. */
 #cmakedefine HAVE_PATHS_H 1
 #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. */
 /* Define to 1 if you have the `pipe' function. */
 #cmakedefine HAVE_PIPE 1
 #cmakedefine HAVE_PIPE 1
 
 
@@ -709,6 +745,9 @@ typedef uint64_t uintmax_t;
 /* Define to 1 if you have the <poll.h> header file. */
 /* Define to 1 if you have the <poll.h> header file. */
 #cmakedefine HAVE_POLL_H 1
 #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. */
 /* Define to 1 if you have the <process.h> header file. */
 #cmakedefine HAVE_PROCESS_H 1
 #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. */
 /* Define to 1 if you have the <signal.h> header file. */
 #cmakedefine HAVE_SIGNAL_H 1
 #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. */
 /* Define to 1 if you have the `statfs' function. */
 #cmakedefine HAVE_STATFS 1
 #cmakedefine HAVE_STATFS 1
 
 
@@ -952,9 +994,6 @@ typedef uint64_t uintmax_t;
 /* Define to 1 if you have the `wcslen' function. */
 /* Define to 1 if you have the `wcslen' function. */
 #cmakedefine HAVE_WCSLEN 1
 #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. */
 /* Define to 1 if you have the `wctomb' function. */
 #cmakedefine HAVE_WCTOMB 1
 #cmakedefine HAVE_WCTOMB 1
 
 

+ 42 - 5
Utilities/cmlibarchive/build/utils/gen_archive_string_composition_h.sh

@@ -1,10 +1,13 @@
 #!/bin/sh
 #!/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
 inputfile="$1"	# Expect UnicodeData.txt
 outfile=archive_string_composition.h
 outfile=archive_string_composition.h
 pickout=/tmp/mk_unicode_composition_tbl$$.awk
 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"
 # Append the file header of "archive_string_composition.h"
@@ -14,7 +17,7 @@ append_copyright()
 {
 {
 cat > ${outfile} <<CR_END
 cat > ${outfile} <<CR_END
 /*-
 /*-
- * Copyright (c) 2011 libarchive Project
+ * Copyright (c) 2011-2012 libarchive Project
  * All rights reserved.
  * All rights reserved.
  *
  *
  * Redistribution and use in source and binary forms, with or without
  * Redistribution and use in source and binary forms, with or without
@@ -44,7 +47,7 @@ cat > ${outfile} <<CR_END
 /*
 /*
  * ATTENTION!
  * ATTENTION!
  *  This file is generated by build/utils/gen_archive_string_composition_h.sh
  *  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/
  *  See also http://unicode.org/report/tr15/
  */
  */
@@ -76,6 +79,7 @@ BEGIN {
   min = "";
   min = "";
   max = "";
   max = "";
   cmd="sort | awk -F ' ' '{printf \"\\\\t{ 0x%s , 0x%s , 0x%s },\\\\n\",\$1,\$2,\$3}'"
   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[] = {"
   print "static const struct unicode_composition_table u_composition_table[] = {"
 }
 }
 END {
 END {
@@ -178,7 +182,6 @@ END {
   }
   }
   print "};"
   print "};"
   print ""
   print ""
-  print "#endif /* ARCHIVE_STRING_COMPOSITION_H_INCLUDED */"
 }
 }
 #
 #
 #
 #
@@ -241,7 +244,7 @@ function hextoi(hex)
 #}
 #}
 #
 #
 # Exclusion code points specified by  
 # 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
 # 1. Script Specifices
 ##
 ##
@@ -404,6 +407,35 @@ function hextoi(hex)
         print "0"cp[1], "0"cp[2], "0"\$1 | cmd
         print "0"cp[1], "0"cp[2], "0"\$1 | cmd
     else
     else
         print cp[1], cp[2], \$1 | cmd
         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
 AWK_END
 #################################################################################
 #################################################################################
@@ -413,6 +445,11 @@ AWK_END
 #################################################################################
 #################################################################################
 append_copyright
 append_copyright
 awk -f ${pickout} ${inputfile} >> ${outfile}
 awk -f ${pickout} ${inputfile} >> ${outfile}
+awk -f ${pickout2} ${nfdtmp} >> ${outfile}
+echo "#endif /* ARCHIVE_STRING_COMPOSITION_H_INCLUDED */" >> ${outfile}
+echo "" >> ${outfile}
 #
 #
 # Remove awk the script.
 # Remove awk the script.
 rm ${pickout}
 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
 SET(libarchive_SOURCES
   archive_acl.c
   archive_acl.c
   archive_check_magic.c
   archive_check_magic.c
+  archive_cmdline.c
+  archive_cmdline_private.h
+  archive_crc32.h
   archive_crypto.c
   archive_crypto.c
   archive_crypto_private.h
   archive_crypto_private.h
   archive_endian.h
   archive_endian.h
@@ -28,8 +31,12 @@ SET(libarchive_SOURCES
   archive_entry_stat.c
   archive_entry_stat.c
   archive_entry_strmode.c
   archive_entry_strmode.c
   archive_entry_xattr.c
   archive_entry_xattr.c
+  archive_getdate.c
+  archive_match.c
   archive_options.c
   archive_options.c
   archive_options_private.h
   archive_options_private.h
+  archive_pathmatch.c
+  archive_pathmatch.h
   archive_platform.h
   archive_platform.h
   archive_ppmd_private.h
   archive_ppmd_private.h
   archive_ppmd7.c
   archive_ppmd7.c
@@ -38,6 +45,7 @@ SET(libarchive_SOURCES
   archive_rb.c
   archive_rb.c
   archive_rb.h
   archive_rb.h
   archive_read.c
   archive_read.c
+  archive_read_append_filter.c
   archive_read_data_into_fd.c
   archive_read_data_into_fd.c
   archive_read_disk_entry_from_file.c
   archive_read_disk_entry_from_file.c
   archive_read_disk_posix.c
   archive_read_disk_posix.c
@@ -49,11 +57,15 @@ SET(libarchive_SOURCES
   archive_read_open_filename.c
   archive_read_open_filename.c
   archive_read_open_memory.c
   archive_read_open_memory.c
   archive_read_private.h
   archive_read_private.h
+  archive_read_set_format.c
   archive_read_set_options.c
   archive_read_set_options.c
   archive_read_support_filter_all.c
   archive_read_support_filter_all.c
   archive_read_support_filter_bzip2.c
   archive_read_support_filter_bzip2.c
   archive_read_support_filter_compress.c
   archive_read_support_filter_compress.c
   archive_read_support_filter_gzip.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_none.c
   archive_read_support_filter_program.c
   archive_read_support_filter_program.c
   archive_read_support_filter_rpm.c
   archive_read_support_filter_rpm.c
@@ -81,6 +93,7 @@ SET(libarchive_SOURCES
   archive_util.c
   archive_util.c
   archive_virtual.c
   archive_virtual.c
   archive_write.c
   archive_write.c
+  archive_write_disk_acl.c
   archive_write_disk_posix.c
   archive_write_disk_posix.c
   archive_write_disk_private.h
   archive_write_disk_private.h
   archive_write_disk_set_standard_lookup.c
   archive_write_disk_set_standard_lookup.c
@@ -89,11 +102,18 @@ SET(libarchive_SOURCES
   archive_write_open_file.c
   archive_write_open_file.c
   archive_write_open_filename.c
   archive_write_open_filename.c
   archive_write_open_memory.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_bzip2.c
   archive_write_add_filter_compress.c
   archive_write_add_filter_compress.c
+  archive_write_add_filter_grzip.c
   archive_write_add_filter_gzip.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_none.c
   archive_write_add_filter_program.c
   archive_write_add_filter_program.c
+  archive_write_add_filter_uuencode.c
   archive_write_add_filter_xz.c
   archive_write_add_filter_xz.c
   archive_write_set_format.c
   archive_write_set_format.c
   archive_write_set_format_7zip.c
   archive_write_set_format_7zip.c
@@ -107,10 +127,11 @@ SET(libarchive_SOURCES
   archive_write_set_format_pax.c
   archive_write_set_format_pax.c
   archive_write_set_format_shar.c
   archive_write_set_format_shar.c
   archive_write_set_format_ustar.c
   archive_write_set_format_ustar.c
+  archive_write_set_format_v7tar.c
   archive_write_set_format_xar.c
   archive_write_set_format_xar.c
   archive_write_set_format_zip.c
   archive_write_set_format_zip.c
   archive_write_set_options.c
   archive_write_set_options.c
-  filter_fork.c
+  filter_fork_posix.c
   filter_fork.h
   filter_fork.h
 )
 )
 
 

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

@@ -63,13 +63,6 @@
 # else
 # else
 #  define	__LA_SSIZE_T	long
 #  define	__LA_SSIZE_T	long
 # endif
 # 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
 #else
 # include <unistd.h>  /* ssize_t, uid_t, and gid_t */
 # include <unistd.h>  /* ssize_t, uid_t, and gid_t */
 # if defined(_SCO_DS) || defined(__osf__)
 # if defined(_SCO_DS) || defined(__osf__)
@@ -78,8 +71,6 @@
 #  define	__LA_INT64_T	int64_t
 #  define	__LA_INT64_T	int64_t
 # endif
 # endif
 # define	__LA_SSIZE_T	ssize_t
 # define	__LA_SSIZE_T	ssize_t
-# define	__LA_UID_T	uid_t
-# define	__LA_GID_T	gid_t
 #endif
 #endif
 
 
 /*
 /*
@@ -113,6 +104,12 @@
 #define	__LA_PRINTF(fmtarg, firstvararg)	/* nothing */
 #define	__LA_PRINTF(fmtarg, firstvararg)	/* nothing */
 #endif
 #endif
 
 
+#if defined(__GNUC__) && __GNUC__ >= 3 && __GNUC_MINOR__ >= 1
+# define __LA_DEPRECATED __attribute__((deprecated))
+#else
+# define __LA_DEPRECATED
+#endif
+
 #ifdef __cplusplus
 #ifdef __cplusplus
 extern "C" {
 extern "C" {
 #endif
 #endif
@@ -134,13 +131,13 @@ extern "C" {
  * assert that ARCHIVE_VERSION_NUMBER >= 2012108.
  * assert that ARCHIVE_VERSION_NUMBER >= 2012108.
  */
  */
 /* Note: Compiler will complain if this does not match archive_entry.h! */
 /* 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);
 __LA_DECL int		archive_version_number(void);
 
 
 /*
 /*
  * Textual name/version of the library, useful for version displays.
  * 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);
 __LA_DECL const char *	archive_version_string(void);
 
 
 /* Declare our basic types. */
 /* Declare our basic types. */
@@ -210,6 +207,13 @@ typedef int	archive_open_callback(struct archive *, void *_client_data);
 
 
 typedef int	archive_close_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.
  * Codes to identify various stream filters.
  */
  */
@@ -223,6 +227,9 @@ typedef int	archive_close_callback(struct archive *, void *_client_data);
 #define	ARCHIVE_FILTER_UU	7
 #define	ARCHIVE_FILTER_UU	7
 #define	ARCHIVE_FILTER_RPM	8
 #define	ARCHIVE_FILTER_RPM	8
 #define	ARCHIVE_FILTER_LZIP	9
 #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
 #if ARCHIVE_VERSION_NUMBER < 4000000
 #define	ARCHIVE_COMPRESSION_NONE	ARCHIVE_FILTER_NONE
 #define	ARCHIVE_COMPRESSION_NONE	ARCHIVE_FILTER_NONE
@@ -235,6 +242,7 @@ typedef int	archive_close_callback(struct archive *, void *_client_data);
 #define	ARCHIVE_COMPRESSION_UU		ARCHIVE_FILTER_UU
 #define	ARCHIVE_COMPRESSION_UU		ARCHIVE_FILTER_UU
 #define	ARCHIVE_COMPRESSION_RPM		ARCHIVE_FILTER_RPM
 #define	ARCHIVE_COMPRESSION_RPM		ARCHIVE_FILTER_RPM
 #define	ARCHIVE_COMPRESSION_LZIP	ARCHIVE_FILTER_LZIP
 #define	ARCHIVE_COMPRESSION_LZIP	ARCHIVE_FILTER_LZIP
+#define	ARCHIVE_COMPRESSION_LRZIP	ARCHIVE_FILTER_LRZIP
 #endif
 #endif
 
 
 /*
 /*
@@ -307,37 +315,49 @@ __LA_DECL struct archive	*archive_read_new(void);
  */
  */
 
 
 #if ARCHIVE_VERSION_NUMBER < 4000000
 #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 *,
 __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
 __LA_DECL int archive_read_support_compression_program_signature
 		(struct archive *, const char *,
 		(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
 #endif
 
 
 __LA_DECL int archive_read_support_filter_all(struct archive *);
 __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_bzip2(struct archive *);
 __LA_DECL int archive_read_support_filter_compress(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_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_lzip(struct archive *);
 __LA_DECL int archive_read_support_filter_lzma(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_none(struct archive *);
 __LA_DECL int archive_read_support_filter_program(struct archive *,
 __LA_DECL int archive_read_support_filter_program(struct archive *,
 		     const char *command);
 		     const char *command);
 __LA_DECL int archive_read_support_filter_program_signature
 __LA_DECL int archive_read_support_filter_program_signature
-		(struct archive *, const char *,
+		(struct archive *, const char * /* cmd */,
 				    const void * /* match */, size_t);
 				    const void * /* match */, size_t);
-
 __LA_DECL int archive_read_support_filter_rpm(struct archive *);
 __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_uu(struct archive *);
 __LA_DECL int archive_read_support_filter_xz(struct archive *);
 __LA_DECL int archive_read_support_filter_xz(struct archive *);
@@ -359,6 +379,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_xar(struct archive *);
 __LA_DECL int archive_read_support_format_zip(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. */
 /* Set various callbacks. */
 __LA_DECL int archive_read_set_open_callback(struct archive *,
 __LA_DECL int archive_read_set_open_callback(struct archive *,
     archive_open_callback *);
     archive_open_callback *);
@@ -370,8 +401,23 @@ __LA_DECL int archive_read_set_skip_callback(struct archive *,
     archive_skip_callback *);
     archive_skip_callback *);
 __LA_DECL int archive_read_set_close_callback(struct archive *,
 __LA_DECL int archive_read_set_close_callback(struct archive *,
     archive_close_callback *);
     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 *);
 __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. */
 /* Opening freezes the callbacks. */
 __LA_DECL int archive_read_open1(struct archive *);
 __LA_DECL int archive_read_open1(struct archive *);
 
 
@@ -391,11 +437,15 @@ __LA_DECL int archive_read_open2(struct archive *, void *_client_data,
 /* Use this if you know the filename.  Note: NULL indicates stdin. */
 /* Use this if you know the filename.  Note: NULL indicates stdin. */
 __LA_DECL int archive_read_open_filename(struct archive *,
 __LA_DECL int archive_read_open_filename(struct archive *,
 		     const char *_filename, size_t _block_size);
 		     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 *,
 __LA_DECL int archive_read_open_filename_w(struct archive *,
 		     const wchar_t *_filename, size_t _block_size);
 		     const wchar_t *_filename, size_t _block_size);
 /* archive_read_open_file() is a deprecated synonym for ..._open_filename(). */
 /* archive_read_open_file() is a deprecated synonym for ..._open_filename(). */
 __LA_DECL int archive_read_open_file(struct archive *,
 __LA_DECL int archive_read_open_file(struct archive *,
-		     const char *_filename, size_t _block_size);
+		     const char *_filename, size_t _block_size) __LA_DEPRECATED;
 /* Read an archive that's stored in memory. */
 /* Read an archive that's stored in memory. */
 __LA_DECL int archive_read_open_memory(struct archive *,
 __LA_DECL int archive_read_open_memory(struct archive *,
 		     void * buff, size_t size);
 		     void * buff, size_t size);
@@ -427,6 +477,9 @@ __LA_DECL __LA_INT64_T		 archive_read_header_position(struct archive *);
 __LA_DECL __LA_SSIZE_T		 archive_read_data(struct archive *,
 __LA_DECL __LA_SSIZE_T		 archive_read_data(struct archive *,
 				    void *, size_t);
 				    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
  * 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
  * of each returned block.  Note that the client has no way to specify
@@ -510,6 +563,12 @@ __LA_DECL int archive_read_set_options(struct archive *_a,
 /* Default: Do not restore Mac extended metadata. */
 /* Default: Do not restore Mac extended metadata. */
 /* This has no effect except on Mac OS. */
 /* This has no effect except on Mac OS. */
 #define	ARCHIVE_EXTRACT_MAC_METADATA		(0x2000)
 #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 *,
 __LA_DECL int archive_read_extract(struct archive *, struct archive_entry *,
 		     int flags);
 		     int flags);
@@ -530,7 +589,7 @@ __LA_DECL int		 archive_read_close(struct archive *);
 __LA_DECL int		 archive_read_free(struct archive *);
 __LA_DECL int		 archive_read_free(struct archive *);
 #if ARCHIVE_VERSION_NUMBER < 4000000
 #if ARCHIVE_VERSION_NUMBER < 4000000
 /* Synonym for archive_read_free() for backwards compatibility. */
 /* 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
 #endif
 
 
 /*-
 /*-
@@ -563,25 +622,41 @@ __LA_DECL int archive_write_set_skip_file(struct archive *,
     __LA_INT64_T, __LA_INT64_T);
     __LA_INT64_T, __LA_INT64_T);
 
 
 #if ARCHIVE_VERSION_NUMBER < 4000000
 #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 *,
 __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
 #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_bzip2(struct archive *);
 __LA_DECL int archive_write_add_filter_compress(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_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_lzip(struct archive *);
 __LA_DECL int archive_write_add_filter_lzma(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_none(struct archive *);
 __LA_DECL int archive_write_add_filter_program(struct archive *,
 __LA_DECL int archive_write_add_filter_program(struct archive *,
 		     const char *cmd);
 		     const char *cmd);
+__LA_DECL int archive_write_add_filter_uuencode(struct archive *);
 __LA_DECL int archive_write_add_filter_xz(struct archive *);
 __LA_DECL int archive_write_add_filter_xz(struct archive *);
 
 
 
 
@@ -598,14 +673,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_gnutar(struct archive *);
 __LA_DECL int archive_write_set_format_iso9660(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(struct archive *);
+__LA_DECL int archive_write_set_format_mtree_classic(struct archive *);
 /* TODO: int archive_write_set_format_old_tar(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(struct archive *);
 __LA_DECL int archive_write_set_format_pax_restricted(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(struct archive *);
 __LA_DECL int archive_write_set_format_shar_dump(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_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_xar(struct archive *);
 __LA_DECL int archive_write_set_format_zip(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 *,
 __LA_DECL int archive_write_open(struct archive *, void *,
 		     archive_open_callback *, archive_write_callback *,
 		     archive_open_callback *, archive_write_callback *,
 		     archive_close_callback *);
 		     archive_close_callback *);
@@ -614,7 +693,8 @@ __LA_DECL int archive_write_open_filename(struct archive *, const char *_file);
 __LA_DECL int archive_write_open_filename_w(struct archive *,
 __LA_DECL int archive_write_open_filename_w(struct archive *,
 		     const wchar_t *_file);
 		     const wchar_t *_file);
 /* A deprecated synonym for archive_write_open_filename() */
 /* 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 *);
 __LA_DECL int archive_write_open_FILE(struct archive *, FILE *);
 /* _buffSize is the size of the buffer, _used refers to a variable that
 /* _buffSize is the size of the buffer, _used refers to a variable that
  * will be updated after each write into the buffer. */
  * will be updated after each write into the buffer. */
@@ -636,12 +716,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_finish_entry(struct archive *);
 __LA_DECL int		 archive_write_close(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
 /* This can fail if the archive wasn't already closed, in which case
  * archive_write_free() will implicitly call archive_write_close(). */
  * archive_write_free() will implicitly call archive_write_close(). */
 __LA_DECL int		 archive_write_free(struct archive *);
 __LA_DECL int		 archive_write_free(struct archive *);
 #if ARCHIVE_VERSION_NUMBER < 4000000
 #if ARCHIVE_VERSION_NUMBER < 4000000
 /* Synonym for archive_write_free() for backwards compatibility. */
 /* 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
 #endif
 
 
 /*
 /*
@@ -765,11 +849,42 @@ __LA_DECL int	archive_read_disk_open_w(struct archive *, const wchar_t *);
  * traversal.
  * traversal.
  */
  */
 __LA_DECL int	archive_read_disk_descend(struct archive *);
 __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(struct archive *);
 __LA_DECL int	archive_read_disk_current_filesystem_is_synthetic(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 *);
 __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. */
 /* Request that the access time of the entry visited by travesal be restored. */
 __LA_DECL int  archive_read_disk_set_atime_restored(struct archive *);
 __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
  * Accessor functions to read/set various information in
@@ -789,13 +904,17 @@ __LA_DECL const char *	 archive_filter_name(struct archive *, int);
 /* These don't properly handle multiple filters, so are deprecated and
 /* These don't properly handle multiple filters, so are deprecated and
  * will eventually be removed. */
  * will eventually be removed. */
 /* As of libarchive 3.0, this is an alias for archive_filter_bytes(a, -1); */
 /* 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); */
 /* 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); */
 /* 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); */
 /* 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
 #endif
 
 
 __LA_DECL int		 archive_errno(struct archive *);
 __LA_DECL int		 archive_errno(struct archive *);
@@ -809,14 +928,116 @@ __LA_DECL void		 archive_copy_error(struct archive *dest,
 			    struct archive *src);
 			    struct archive *src);
 __LA_DECL int		 archive_file_count(struct archive *);
 __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
 #ifdef __cplusplus
 }
 }
 #endif
 #endif
 
 
 /* These are meaningless outside of this header. */
 /* These are meaningless outside of this header. */
 #undef __LA_DECL
 #undef __LA_DECL
-#undef __LA_GID_T
-#undef __LA_UID_T
 
 
 /* These need to remain defined because they're used in the
 /* These need to remain defined because they're used in the
  * callback type definitions.  XXX Fix this.  This is ugly. XXX */
  * 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);
 		    int type, int permset, int tag);
 static struct archive_acl_entry *acl_new_entry(struct archive_acl *acl,
 static struct archive_acl_entry *acl_new_entry(struct archive_acl *acl,
 		    int type, int permset, int tag, int id);
 		    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	isint_w(const wchar_t *start, const wchar_t *end, int *result);
 static int	ismode_w(const wchar_t *start, const wchar_t *end, int *result);
 static int	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,
 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 int	ismode(const char *start, const char *end, int *result);
 static void	next_field(const char **p, const char **start,
 static void	next_field(const char **p, const char **start,
 		    const char **end, char *sep);
 		    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);
 		    const char *test);
 static void	append_entry(char **p, const char *prefix, int tag,
 static void	append_entry(char **p, const char *prefix, int tag,
 		    const char *name, int perm, int id);
 		    const char *name, int perm, int id);
@@ -152,7 +155,7 @@ archive_acl_add_entry_w_len(struct archive_acl *acl,
 	return ARCHIVE_OK;
 	return ARCHIVE_OK;
 }
 }
 
 
-int
+static int
 archive_acl_add_entry_len_l(struct archive_acl *acl,
 archive_acl_add_entry_len_l(struct archive_acl *acl,
     int type, int permset, int tag, int id, const char *name, size_t len,
     int type, int permset, int tag, int id, const char *name, size_t len,
     struct archive_string_conv *sc)
     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;
 	*permset = acl->acl_p->permset;
 	*tag = acl->acl_p->tag;
 	*tag = acl->acl_p->tag;
 	*id = acl->acl_p->id;
 	*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;
 		*name = NULL;
+	}
 	acl->acl_p = acl->acl_p->next;
 	acl->acl_p = acl->acl_p->next;
 	return (ARCHIVE_OK);
 	return (ARCHIVE_OK);
 }
 }
@@ -438,7 +444,7 @@ archive_acl_text_w(struct archive *a, struct archive_acl *acl, int flags)
 	const wchar_t *prefix;
 	const wchar_t *prefix;
 	wchar_t separator;
 	wchar_t separator;
 	struct archive_acl_entry *ap;
 	struct archive_acl_entry *ap;
-	int id;
+	int id, r;
 	wchar_t *wp;
 	wchar_t *wp;
 
 
 	if (acl->acl_text_w != NULL) {
 	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 += 8; /* "default:" */
 			length += 5; /* tag name */
 			length += 5; /* tag name */
 			length += 1; /* colon */
 			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);
 				length += wcslen(wname);
+			else if (r < 0 && errno == ENOMEM)
+				return (NULL);
 			else
 			else
 				length += sizeof(uid_t) * 3 + 1;
 				length += sizeof(uid_t) * 3 + 1;
 			length ++; /* colon */
 			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. */
 	/* Now, allocate the string and actually populate it. */
 	wp = acl->acl_text_w = (wchar_t *)malloc(length * sizeof(wchar_t));
 	wp = acl->acl_text_w = (wchar_t *)malloc(length * sizeof(wchar_t));
 	if (wp == NULL)
 	if (wp == NULL)
-		__archive_errx(1, "No memory to generate the text version of the ACL");
+		return (NULL);
 	count = 0;
 	count = 0;
 	if ((flags & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) {
 	if ((flags & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) {
 		append_entry_w(&wp, NULL, ARCHIVE_ENTRY_ACL_USER_OBJ, NULL,
 		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;
 		ap = acl->acl_head;
 		while (ap != NULL) {
 		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;
 			ap = ap->next;
 		}
 		}
@@ -523,17 +534,20 @@ archive_acl_text_w(struct archive *a, struct archive_acl *acl, int flags)
 		ap = acl->acl_head;
 		ap = acl->acl_head;
 		count = 0;
 		count = 0;
 		while (ap != NULL) {
 		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;
 			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. */
 	/* Now, allocate the string and actually populate it. */
 	p = acl->acl_text = (char *)malloc(length);
 	p = acl->acl_text = (char *)malloc(length);
 	if (p == NULL)
 	if (p == NULL)
-		__archive_errx(1, "No memory to generate the text version of the ACL");
+		return (-1);
 	count = 0;
 	count = 0;
 	if ((flags & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) {
 	if ((flags & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) {
 		append_entry(&p, NULL, ARCHIVE_ENTRY_ACL_USER_OBJ, NULL,
 		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;
 			type = default_type;
 
 
 		name.start = name.end = NULL;
 		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))
 			if (!ismode(field[2].start, field[2].end, &permset))
 				return (ARCHIVE_WARN);
 				return (ARCHIVE_WARN);
 			if (id != -1 || field[1].start < field[1].end) {
 			if (id != -1 || field[1].start < field[1].end) {
@@ -1096,7 +1110,7 @@ archive_acl_parse_l(struct archive_acl *acl,
 				name = field[1];
 				name = field[1];
 			} else
 			} else
 				tag = ARCHIVE_ENTRY_ACL_USER_OBJ;
 				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))
 			if (!ismode(field[2].start, field[2].end, &permset))
 				return (ARCHIVE_WARN);
 				return (ARCHIVE_WARN);
 			if (id != -1 || field[1].start < field[1].end) {
 			if (id != -1 || field[1].start < field[1].end) {
@@ -1104,7 +1118,7 @@ archive_acl_parse_l(struct archive_acl *acl,
 				name = field[1];
 				name = field[1];
 			} else
 			} else
 				tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ;
 				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
 			if (fields == 2
 			    && field[1].start < field[1].end
 			    && field[1].start < field[1].end
 			    && ismode(field[1].start, field[1].end, &permset)) {
 			    && ismode(field[1].start, field[1].end, &permset)) {
@@ -1117,7 +1131,7 @@ archive_acl_parse_l(struct archive_acl *acl,
 			} else
 			} else
 				return (ARCHIVE_WARN);
 				return (ARCHIVE_WARN);
 			tag = ARCHIVE_ENTRY_ACL_OTHER;
 			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
 			if (fields == 2
 			    && field[1].start < field[1].end
 			    && field[1].start < field[1].end
 			    && ismode(field[1].start, field[1].end, &permset)) {
 			    && 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.
  * This makes it easy to handle the obvious abbreviations: 'u' for 'user', etc.
  */
  */
 static int
 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)
 	if (start == end)
 		return (0);
 		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_READ_MAGIC:	return ("archive_read");
 	case ARCHIVE_WRITE_DISK_MAGIC:	return ("archive_write_disk");
 	case ARCHIVE_WRITE_DISK_MAGIC:	return ("archive_write_disk");
 	case ARCHIVE_READ_DISK_MAGIC:	return ("archive_read_disk");
 	case ARCHIVE_READ_DISK_MAGIC:	return ("archive_read_disk");
+	case ARCHIVE_MATCH_MAGIC:	return ("archive_match");
 	default:			return NULL;
 	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
 static int
 win_crypto_Final(unsigned char *buf, size_t bufsize, Digest_CTX *ctx)
 win_crypto_Final(unsigned char *buf, size_t bufsize, Digest_CTX *ctx)
 {
 {
-	DWORD siglen = bufsize;
+	DWORD siglen = (DWORD)bufsize;
 
 
 	if (!ctx->valid)
 	if (!ctx->valid)
 		return (ARCHIVE_FAILED);
 		return (ARCHIVE_FAILED);
@@ -1222,8 +1222,10 @@ __archive_stub_sha512final(archive_sha512_ctx *ctx, void *md)
  * 2. libc2
  * 2. libc2
  * 3. libc3
  * 3. libc3
  * 4. libSystem
  * 4. libSystem
- * 5. OpenSSL
- * 6. Windows API
+ * 5. Nettle
+ * 6. OpenSSL
+ * 7. libmd
+ * 8. Windows API
  */
  */
 const struct archive_crypto __archive_crypto =
 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;
 	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
 static inline void
@@ -189,8 +189,8 @@ archive_le64enc(void *pp, uint64_t u)
 {
 {
 	unsigned char *p = (unsigned char *)pp;
 	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
 #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
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\" 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
 .Dt ARCHIVE_ENTRY 3
 .Os
 .Os
 .Sh NAME
 .Sh NAME
@@ -34,6 +34,8 @@
 .Nm archive_entry_free ,
 .Nm archive_entry_free ,
 .Nm archive_entry_new ,
 .Nm archive_entry_new ,
 .Nd functions for managing archive entry descriptions
 .Nd functions for managing archive entry descriptions
+.Sh LIBRARY
+Streaming Archive Library (libarchive, -larchive)
 .Sh SYNOPSIS
 .Sh SYNOPSIS
 .In archive_entry.h
 .In archive_entry.h
 .Ft "struct archive_entry *"
 .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;
 	char *p;
 
 
 	if (archive_mstring_get_mbs(entry->archive,
 	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)
 	if (entry->ae_fflags_set == 0  &&  entry->ae_fflags_clear == 0)
 		return (NULL);
 		return (NULL);
@@ -390,6 +393,8 @@ archive_entry_fflags_text(struct archive_entry *entry)
 	if (archive_mstring_get_mbs(entry->archive,
 	if (archive_mstring_get_mbs(entry->archive,
 	    &entry->ae_fflags_text, &f) == 0)
 	    &entry->ae_fflags_text, &f) == 0)
 		return (f);
 		return (f);
+	if (errno == ENOMEM)
+		__archive_errx(1, "No memory");
 	return (NULL);
 	return (NULL);
 }
 }
 
 
@@ -405,6 +410,8 @@ archive_entry_gname(struct archive_entry *entry)
 	const char *p;
 	const char *p;
 	if (archive_mstring_get_mbs(entry->archive, &entry->ae_gname, &p) == 0)
 	if (archive_mstring_get_mbs(entry->archive, &entry->ae_gname, &p) == 0)
 		return (p);
 		return (p);
+	if (errno == ENOMEM)
+		__archive_errx(1, "No memory");
 	return (NULL);
 	return (NULL);
 }
 }
 
 
@@ -414,6 +421,8 @@ archive_entry_gname_w(struct archive_entry *entry)
 	const wchar_t *p;
 	const wchar_t *p;
 	if (archive_mstring_get_wcs(entry->archive, &entry->ae_gname, &p) == 0)
 	if (archive_mstring_get_wcs(entry->archive, &entry->ae_gname, &p) == 0)
 		return (p);
 		return (p);
+	if (errno == ENOMEM)
+		__archive_errx(1, "No memory");
 	return (NULL);
 	return (NULL);
 }
 }
 
 
@@ -428,9 +437,13 @@ const char *
 archive_entry_hardlink(struct archive_entry *entry)
 archive_entry_hardlink(struct archive_entry *entry)
 {
 {
 	const char *p;
 	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)
 	    entry->archive, &entry->ae_hardlink, &p) == 0)
 		return (p);
 		return (p);
+	if (errno == ENOMEM)
+		__archive_errx(1, "No memory");
 	return (NULL);
 	return (NULL);
 }
 }
 
 
@@ -438,9 +451,13 @@ const wchar_t *
 archive_entry_hardlink_w(struct archive_entry *entry)
 archive_entry_hardlink_w(struct archive_entry *entry)
 {
 {
 	const wchar_t *p;
 	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)
 	    entry->archive, &entry->ae_hardlink, &p) == 0)
 		return (p);
 		return (p);
+	if (errno == ENOMEM)
+		__archive_errx(1, "No memory");
 	return (NULL);
 	return (NULL);
 }
 }
 
 
@@ -511,6 +528,8 @@ archive_entry_pathname(struct archive_entry *entry)
 	if (archive_mstring_get_mbs(
 	if (archive_mstring_get_mbs(
 	    entry->archive, &entry->ae_pathname, &p) == 0)
 	    entry->archive, &entry->ae_pathname, &p) == 0)
 		return (p);
 		return (p);
+	if (errno == ENOMEM)
+		__archive_errx(1, "No memory");
 	return (NULL);
 	return (NULL);
 }
 }
 
 
@@ -521,6 +540,8 @@ archive_entry_pathname_w(struct archive_entry *entry)
 	if (archive_mstring_get_wcs(
 	if (archive_mstring_get_wcs(
 	    entry->archive, &entry->ae_pathname, &p) == 0)
 	    entry->archive, &entry->ae_pathname, &p) == 0)
 		return (p);
 		return (p);
+	if (errno == ENOMEM)
+		__archive_errx(1, "No memory");
 	return (NULL);
 	return (NULL);
 }
 }
 
 
@@ -584,6 +605,8 @@ archive_entry_sourcepath(struct archive_entry *entry)
 	if (archive_mstring_get_mbs(
 	if (archive_mstring_get_mbs(
 	    entry->archive, &entry->ae_sourcepath, &p) == 0)
 	    entry->archive, &entry->ae_sourcepath, &p) == 0)
 		return (p);
 		return (p);
+	if (errno == ENOMEM)
+		__archive_errx(1, "No memory");
 	return (NULL);
 	return (NULL);
 }
 }
 
 
@@ -601,9 +624,13 @@ const char *
 archive_entry_symlink(struct archive_entry *entry)
 archive_entry_symlink(struct archive_entry *entry)
 {
 {
 	const char *p;
 	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)
 	    entry->archive, &entry->ae_symlink, &p) == 0)
 		return (p);
 		return (p);
+	if (errno == ENOMEM)
+		__archive_errx(1, "No memory");
 	return (NULL);
 	return (NULL);
 }
 }
 
 
@@ -611,9 +638,13 @@ const wchar_t *
 archive_entry_symlink_w(struct archive_entry *entry)
 archive_entry_symlink_w(struct archive_entry *entry)
 {
 {
 	const wchar_t *p;
 	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)
 	    entry->archive, &entry->ae_symlink, &p) == 0)
 		return (p);
 		return (p);
+	if (errno == ENOMEM)
+		__archive_errx(1, "No memory");
 	return (NULL);
 	return (NULL);
 }
 }
 
 
@@ -641,6 +672,8 @@ archive_entry_uname(struct archive_entry *entry)
 	const char *p;
 	const char *p;
 	if (archive_mstring_get_mbs(entry->archive, &entry->ae_uname, &p) == 0)
 	if (archive_mstring_get_mbs(entry->archive, &entry->ae_uname, &p) == 0)
 		return (p);
 		return (p);
+	if (errno == ENOMEM)
+		__archive_errx(1, "No memory");
 	return (NULL);
 	return (NULL);
 }
 }
 
 
@@ -650,6 +683,8 @@ archive_entry_uname_w(struct archive_entry *entry)
 	const wchar_t *p;
 	const wchar_t *p;
 	if (archive_mstring_get_wcs(entry->archive, &entry->ae_uname, &p) == 0)
 	if (archive_mstring_get_wcs(entry->archive, &entry->ae_uname, &p) == 0)
 		return (p);
 		return (p);
+	if (errno == ENOMEM)
+		__archive_errx(1, "No memory");
 	return (NULL);
 	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,
 	if (archive_mstring_update_utf8(entry->archive,
 	    &entry->ae_gname, name) == 0)
 	    &entry->ae_gname, name) == 0)
 		return (1);
 		return (1);
+	if (errno == ENOMEM)
+		__archive_errx(1, "No memory");
 	return (0);
 	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,
 	if (archive_mstring_update_utf8(entry->archive,
 	    &entry->ae_hardlink, target) == 0)
 	    &entry->ae_hardlink, target) == 0)
 		return (1);
 		return (1);
+	if (errno == ENOMEM)
+		__archive_errx(1, "No memory");
 	return (0);
 	return (0);
 }
 }
 
 
@@ -932,7 +971,11 @@ archive_entry_update_link_utf8(struct archive_entry *entry, const char *target)
 	else
 	else
 		r = archive_mstring_update_utf8(entry->archive,
 		r = archive_mstring_update_utf8(entry->archive,
 		    &entry->ae_hardlink, target);
 		    &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
 int
@@ -1005,6 +1048,8 @@ archive_entry_update_pathname_utf8(struct archive_entry *entry, const char *name
 	if (archive_mstring_update_utf8(entry->archive,
 	if (archive_mstring_update_utf8(entry->archive,
 	    &entry->ae_pathname, name) == 0)
 	    &entry->ae_pathname, name) == 0)
 		return (1);
 		return (1);
+	if (errno == ENOMEM)
+		__archive_errx(1, "No memory");
 	return (0);
 	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,
 	if (archive_mstring_update_utf8(entry->archive,
 	    &entry->ae_symlink, linkname) == 0)
 	    &entry->ae_symlink, linkname) == 0)
 		return (1);
 		return (1);
+	if (errno == ENOMEM)
+		__archive_errx(1, "No memory");
 	return (0);
 	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,
 	if (archive_mstring_update_utf8(entry->archive,
 	    &entry->ae_uname, name) == 0)
 	    &entry->ae_uname, name) == 0)
 		return (1);
 		return (1);
+	if (errno == ENOMEM)
+		__archive_errx(1, "No memory");
 	return (0);
 	return (0);
 }
 }
 
 
@@ -1269,7 +1318,12 @@ int
 archive_entry_acl_next(struct archive_entry *entry, int want_type, int *type,
 archive_entry_acl_next(struct archive_entry *entry, int want_type, int *type,
     int *permset, int *tag, int *id, const char **name)
     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 *
 const wchar_t *
 archive_entry_acl_text_w(struct archive_entry *entry, int flags)
 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 *
 const char *
@@ -1288,7 +1346,7 @@ archive_entry_acl_text(struct archive_entry *entry, int flags)
 	const char *p;
 	const char *p;
 	if (archive_acl_text_l(&entry->acl, flags, &p, NULL, NULL) != 0
 	if (archive_acl_text_l(&entry->acl, flags, &p, NULL, NULL) != 0
 	    && errno == ENOMEM)
 	    && errno == ENOMEM)
-		return (NULL);
+		__archive_errx(1, "No memory");
 	return (p);
 	return (p);
 }
 }
 
 
@@ -1391,6 +1449,9 @@ static struct flag {
 	{ "nouunlnk",	L"nouunlnk",		UF_NOUNLINK,	0 },
 	{ "nouunlnk",	L"nouunlnk",		UF_NOUNLINK,	0 },
 	{ "nouunlink",	L"nouunlink",		UF_NOUNLINK,	0 },
 	{ "nouunlink",	L"nouunlink",		UF_NOUNLINK,	0 },
 #endif
 #endif
+#ifdef UF_COMPRESSED
+	{ "nocompressed",L"nocompressed",	UF_COMPRESSED,	0 },
+#endif
 #ifdef EXT2_UNRM_FL
 #ifdef EXT2_UNRM_FL
         { "nouunlink",	L"nouunlink",		EXT2_UNRM_FL,	0},
         { "nouunlink",	L"nouunlink",		EXT2_UNRM_FL,	0},
 #endif
 #endif

+ 20 - 25
Utilities/cmlibarchive/libarchive/archive_entry.h

@@ -29,7 +29,7 @@
 #define	ARCHIVE_ENTRY_H_INCLUDED
 #define	ARCHIVE_ENTRY_H_INCLUDED
 
 
 /* Note: Compiler will complain if this does not match archive.h! */
 /* 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
  * Note: archive_entry.h is for use outside of libarchive; the
@@ -47,21 +47,9 @@
 #include <windows.h>
 #include <windows.h>
 #endif
 #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__)
 #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
 #else
 #include <unistd.h>
 #include <unistd.h>
 # if defined(_SCO_DS) || defined(__osf__)
 # if defined(_SCO_DS) || defined(__osf__)
@@ -69,17 +57,17 @@
 # else
 # else
 #  define	__LA_INT64_T	int64_t
 #  define	__LA_INT64_T	int64_t
 # endif
 # 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
 #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
  * 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
  * portable values to platform-native values when entries are read from
  * or written to disk.
  * 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_IFMT		((__LA_MODE_T)0170000)
 #define AE_IFREG	((__LA_MODE_T)0100000)
 #define AE_IFREG	((__LA_MODE_T)0100000)
 #define AE_IFLNK	((__LA_MODE_T)0120000)
 #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
  * manipulate archives on systems different than the ones they were
  * created on.
  * 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 const struct stat	*archive_entry_stat(struct archive_entry *);
 __LA_DECL void	archive_entry_copy_stat(struct archive_entry *, const struct stat *);
 __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
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\" SUCH DAMAGE.
 .\"
 .\"
-.Dd February 21, 2010
+.Dd February 2, 2012
 .Dt ARCHIVE_ENTRY_ACL 3
 .Dt ARCHIVE_ENTRY_ACL 3
 .Os
 .Os
 .Sh NAME
 .Sh NAME
@@ -35,6 +35,8 @@
 .Nm archive_entry_acl_reset ,
 .Nm archive_entry_acl_reset ,
 .Nm archive_entry_acl_text_w
 .Nm archive_entry_acl_text_w
 .Nd functions for manipulating Access Control Lists in archive entry descriptions
 .Nd functions for manipulating Access Control Lists in archive entry descriptions
+.Sh LIBRARY
+Streaming Archive Library (libarchive, -larchive)
 .Sh SYNOPSIS
 .Sh SYNOPSIS
 .In archive_entry.h
 .In archive_entry.h
 .Ft void
 .Ft void
@@ -132,7 +134,7 @@ All files have an access ACL
 This specifies the permissions required for access to the file itself.
 This specifies the permissions required for access to the file itself.
 Directories have an additional ACL
 Directories have an additional ACL
 .Pq Dv ARCHIVE_ENTRY_ACL_TYPE_DEFAULT ,
 .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
 .Pp
 .Fn archive_entry_acl_add_entry
 .Fn archive_entry_acl_add_entry
 and
 and

+ 3 - 3
Utilities/cmlibarchive/libarchive/archive_entry_copy_bhfi.c

@@ -34,7 +34,7 @@ __FBSDID("$FreeBSD$");
 #define EPOC_TIME ARCHIVE_LITERAL_ULL(116444736000000000)
 #define EPOC_TIME ARCHIVE_LITERAL_ULL(116444736000000000)
 
 
 __inline static void
 __inline static void
-fileTimeToUtc(const FILETIME *filetime, time_t *time, long *ns)
+fileTimeToUtc(const FILETIME *filetime, time_t *t, long *ns)
 {
 {
 	ULARGE_INTEGER utc;
 	ULARGE_INTEGER utc;
 
 
@@ -42,10 +42,10 @@ fileTimeToUtc(const FILETIME *filetime, time_t *time, long *ns)
 	utc.LowPart  = filetime->dwLowDateTime;
 	utc.LowPart  = filetime->dwLowDateTime;
 	if (utc.QuadPart >= EPOC_TIME) {
 	if (utc.QuadPart >= EPOC_TIME) {
 		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 */
 		*ns = (long)(utc.QuadPart % 10000000) * 100;/* nano seconds base */
 	} else {
 	} else {
-		*time = 0;
+		*t = 0;
 		*ns = 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.
 			 * for future use.
 			 */
 			 */
 			le = insert_entry(res, *e);
 			le = insert_entry(res, *e);
+			if (le == NULL)
+				/* XXX We should return an error code XXX */
+				return;
 			le->entry = *e;
 			le->entry = *e;
 			*e = NULL;
 			*e = NULL;
 		}
 		}
@@ -362,7 +365,7 @@ insert_entry(struct archive_entry_linkresolver *res,
 	if (res->number_entries > res->number_buckets * 2)
 	if (res->number_entries > res->number_buckets * 2)
 		grow_hash(res);
 		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);
 	bucket = hash & (res->number_buckets - 1);
 
 
 	/* If we could allocate the entry, record it. */
 	/* 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
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\" SUCH DAMAGE.
 .\"
 .\"
-.Dd February 20, 2010
+.Dd February 2, 2012
 .Dt ARCHIVE_ENTRY_LINKIFY 3
 .Dt ARCHIVE_ENTRY_LINKIFY 3
 .Os
 .Os
 .Sh NAME
 .Sh NAME
@@ -33,7 +33,7 @@
 .Nm archive_entry_linkify
 .Nm archive_entry_linkify
 .Nd hardlink resolver functions
 .Nd hardlink resolver functions
 .Sh LIBRARY
 .Sh LIBRARY
-.Lb libarchive
+Streaming Archive Library (libarchive, -larchive)
 .Sh SYNOPSIS
 .Sh SYNOPSIS
 .In archive_entry.h
 .In archive_entry.h
 .Ft struct archive_entry_linkresolver *
 .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
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\" SUCH DAMAGE.
 .\"
 .\"
-.Dd February 22, 2010
+.Dd February 2, 2012
 .Dt ARCHIVE_ENTRY_PATHS 3
 .Dt ARCHIVE_ENTRY_PATHS 3
 .Os
 .Os
 .Sh NAME
 .Sh NAME
@@ -51,6 +51,8 @@
 .Nm archive_entry_copy_symlink_w ,
 .Nm archive_entry_copy_symlink_w ,
 .Nm archve_entry_update_symlink_utf8
 .Nm archve_entry_update_symlink_utf8
 .Nd functions for manipulating path names in archive entry descriptions
 .Nd functions for manipulating path names in archive entry descriptions
+.Sh LIBRARY
+Streaming Archive Library (libarchive, -larchive)
 .Sh SYNOPSIS
 .Sh SYNOPSIS
 .In archive_entry.h
 .In archive_entry.h
 .Ft const char *
 .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
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\" SUCH DAMAGE.
 .\"
 .\"
-.Dd February 22, 2010
+.Dd February 2, 2012
 .Dt ARCHIVE_ENTRY_PERMS 3
 .Dt ARCHIVE_ENTRY_PERMS 3
 .Os
 .Os
 .Sh NAME
 .Sh NAME
@@ -52,6 +52,8 @@
 .Nm archive_entry_copy_fflags_text ,
 .Nm archive_entry_copy_fflags_text ,
 .Nm archive_entry_copy_fflags_text_w
 .Nm archive_entry_copy_fflags_text_w
 .Nd functions for manipulating ownership and permissions in archive entry descriptions
 .Nd functions for manipulating ownership and permissions in archive entry descriptions
+.Sh LIBRARY
+Streaming Archive Library (libarchive, -larchive)
 .Sh SYNOPSIS
 .Sh SYNOPSIS
 .In archive_entry.h
 .In archive_entry.h
 .Ft gid_t
 .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
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\" SUCH DAMAGE.
 .\"
 .\"
-.Dd May 12, 2008
-.Dt ARCHIVE_ENTRY 3
+.Dd February 2, 2012
+.Dt ARCHIVE_ENTRY_STAT 3
 .Os
 .Os
 .Sh NAME
 .Sh NAME
 .Nm archive_entry_stat ,
 .Nm archive_entry_stat ,
@@ -56,6 +56,8 @@
 .Nm archive_entry_rdevminor ,
 .Nm archive_entry_rdevminor ,
 .Nm archive_entry_set_rdevminor ,
 .Nm archive_entry_set_rdevminor ,
 .Nd accessor functions for manipulating archive entry descriptions
 .Nd accessor functions for manipulating archive entry descriptions
+.Sh LIBRARY
+Streaming Archive Library (libarchive, -larchive)
 .Sh SYNOPSIS
 .Sh SYNOPSIS
 .In archive_entry.h
 .In archive_entry.h
 .Ft const struct stat *
 .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_ctime = archive_entry_ctime(entry);
 	st->st_mtime = archive_entry_mtime(entry);
 	st->st_mtime = archive_entry_mtime(entry);
 	st->st_dev = archive_entry_dev(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_nlink = archive_entry_nlink(entry);
 	st->st_rdev = archive_entry_rdev(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);
 	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
 	 * TODO: On Linux, store 32 or 64 here depending on whether
 	 * the cached stat structure is a stat32 or a stat64.  This
 	 * 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;
 	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
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\" 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
 .Dt ARCHIVE_ENTRY_TIME 3
 .Os
 .Os
 .Sh NAME
 .Sh NAME
@@ -50,6 +50,8 @@
 .Nm archive_entry_set_mtime ,
 .Nm archive_entry_set_mtime ,
 .Nm archive_entry_unset_mtime ,
 .Nm archive_entry_unset_mtime ,
 .Nd functions for manipulating times in archive entry descriptions
 .Nd functions for manipulating times in archive entry descriptions
+.Sh LIBRARY
+Streaming Archive Library (libarchive, -larchive)
 .Sh SYNOPSIS
 .Sh SYNOPSIS
 .In archive_entry.h
 .In archive_entry.h
 .Ft time_t
 .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)
     int magic, const char *fn, option_handler use_option)
 {
 {
 	const char *mp, *op, *vp;
 	const char *mp, *op, *vp;
+	int r;
 
 
 	archive_check_magic(a, magic, ARCHIVE_STATE_NEW, fn);
 	archive_check_magic(a, magic, ARCHIVE_STATE_NEW, fn);
 
 
@@ -47,10 +48,24 @@ _archive_set_option(struct archive *a,
 
 
 	if (op == NULL && vp == NULL)
 	if (op == NULL && vp == NULL)
 		return (ARCHIVE_OK);
 		return (ARCHIVE_OK);
-	if (op == NULL)
+	if (op == NULL) {
+		archive_set_error(a, ARCHIVE_ERRNO_MISC, "Empty option");
 		return (ARCHIVE_FAILED);
 		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
 int
@@ -72,6 +87,8 @@ _archive_set_either_option(struct archive *a, const char *m, const char *o, cons
 	if (r2 == ARCHIVE_FATAL)
 	if (r2 == ARCHIVE_FATAL)
 		return (ARCHIVE_FATAL);
 		return (ARCHIVE_FATAL);
 
 
+	if (r2 == ARCHIVE_WARN - 1)
+		return r1;
 	return r1 > r2 ? r1 : r2;
 	return r1 > r2 ? r1 : r2;
 }
 }
 
 
@@ -79,7 +96,7 @@ int
 _archive_set_options(struct archive *a, const char *options,
 _archive_set_options(struct archive *a, const char *options,
     int magic, const char *fn, option_handler use_option)
     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;
 	char *data;
 	const char *s, *mod, *opt, *val;
 	const char *s, *mod, *opt, *val;
 
 
@@ -96,12 +113,42 @@ _archive_set_options(struct archive *a, const char *options,
 		mod = opt = val = NULL;
 		mod = opt = val = NULL;
 
 
 		parse_option(&s, &mod, &opt, &val);
 		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);
 		r = use_option(a, mod, opt, val);
 		if (r == ARCHIVE_FATAL) {
 		if (r == ARCHIVE_FATAL) {
 			free(data);
 			free(data);
 			return (ARCHIVE_FATAL);
 			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)
 		if (r == ARCHIVE_OK)
 			anyok = 1;
 			anyok = 1;
 		else
 		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))));
     upState.Freq = (Byte)(1 + ((2 * cf <= s0) ? (5 * cf > s0) : ((2 * cf + 3 * s0 - 1) / (2 * s0))));
   }
   }
 
 
-  do
+  while (numPs != 0)
   {
   {
     /* Create Child */
     /* Create Child */
     CTX_PTR c1; /* = AllocContext(p); */
     CTX_PTR c1; /* = AllocContext(p); */
@@ -435,7 +435,6 @@ static CTX_PTR CreateSuccessors(CPpmd7 *p, Bool skip)
     SetSuccessor(ps[--numPs], REF(c1));
     SetSuccessor(ps[--numPs], REF(c1));
     c = c1;
     c = c1;
   }
   }
-  while (numPs != 0);
   
   
   return c;
   return c;
 }
 }
@@ -778,7 +777,7 @@ static void Range_Normalize(CPpmd7z_RangeDec *p)
       if(p->Range >= p->Bottom)
       if(p->Range >= p->Bottom)
         break;
         break;
       else
       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->Code = (p->Code << 8) | p->Stream->Read((void *)p->Stream);
     p->Range <<= 8;
     p->Range <<= 8;
@@ -991,7 +990,7 @@ static void RangeEnc_ShiftLow(CPpmd7z_RangeEnc *p)
     p->Cache = (Byte)((UInt32)p->Low >> 24);
     p->Cache = (Byte)((UInt32)p->Low >> 24);
   }
   }
   p->CacheSize++;
   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)
 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;
   CPpmd_Byte_Ref;
 
 
 #define PPMD_SetAllBitsIn256Bytes(p) \
 #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
 #endif

+ 2 - 0
Utilities/cmlibarchive/libarchive/archive_private.h

@@ -50,6 +50,7 @@
 #define	ARCHIVE_READ_MAGIC	(0xdeb0c5U)
 #define	ARCHIVE_READ_MAGIC	(0xdeb0c5U)
 #define	ARCHIVE_WRITE_DISK_MAGIC (0xc001b0c5U)
 #define	ARCHIVE_WRITE_DISK_MAGIC (0xc001b0c5U)
 #define	ARCHIVE_READ_DISK_MAGIC (0xbadb0c5U)
 #define	ARCHIVE_READ_DISK_MAGIC (0xbadb0c5U)
+#define	ARCHIVE_MATCH_MAGIC	(0xcad11c9U)
 
 
 #define	ARCHIVE_STATE_NEW	1U
 #define	ARCHIVE_STATE_NEW	1U
 #define	ARCHIVE_STATE_HEADER	2U
 #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_errx(int retvalue, const char *msg) __LA_DEAD;
 
 
+void	__archive_ensure_cloexec_flag(int fd);
 int	__archive_mktemp(const char *tmpdir);
 int	__archive_mktemp(const char *tmpdir);
 
 
 int	__archive_clean(struct archive *);
 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)
     const struct archive_rb_tree_ops *ops)
 {
 {
 	rbt->rbt_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 *
 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_father = old_child;
 	struct archive_rb_node * const new_child = old_father;
 	struct archive_rb_node * const new_child = old_father;
 
 
+	if (new_father == NULL)
+		return;
 	/*
 	/*
 	 * Exchange descendant linkages.
 	 * Exchange descendant linkages.
 	 */
 	 */
@@ -377,13 +379,13 @@ __archive_rb_tree_swap_prune_and_rebalance(struct archive_rb_tree *rbt,
 
 
 	if (standin_father == self) {
 	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.
 		 * our parent.
 		 */
 		 */
 		standin_son = standin->rb_nodes[standin_which];
 		standin_son = standin->rb_nodes[standin_which];
 	} else {
 	} 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.
 		 * on the same side as our parent.
 		 */
 		 */
 		standin_son = standin->rb_nodes[standin_other];
 		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
 		 * If we are about to delete the standin's father, then when
 		 * we call rebalance, we need to use ourselves as our father.
 		 * 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
 		 * our standin's father we only need to reparent the standin's
 		 * brother.
 		 * 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_node_swap(rbt, self, which);
  *	__archive_rb_tree_prune_node(rbt, self, F);
  *	__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
 static void
 __archive_rb_tree_prune_blackred_branch(
 __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
 	 * red-black tree.  So if we must remove a node, attempt to rearrange
 	 * the tree so we can remove a red node.
 	 * 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  -->  *  |
 	 * |    T  -->    T  |    or    |  R  -->  *  |
 	 * |  s    -->  *    |
 	 * |  s    -->  *    |
@@ -517,7 +519,7 @@ __archive_rb_tree_remove_node(struct archive_rb_tree *rbt,
 	}
 	}
 	if (!RB_TWOCHILDREN_P(self)) {
 	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.
 		 * black and has one red child.
 		 *
 		 *
 		 * |      T  -->      T  -->      T  |
 		 * |      T  -->      T  -->      T  |
@@ -552,6 +554,8 @@ __archive_rb_tree_removal_rebalance(struct archive_rb_tree *rbt,
 		unsigned int other = which ^ RB_DIR_OTHER;
 		unsigned int other = which ^ RB_DIR_OTHER;
 		struct archive_rb_node *brother = parent->rb_nodes[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
 		 * For cases 1, 2a, and 2b, our brother's children must
 		 * be black and our father must be black
 		 * 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);
 				__archive_rb_tree_reparent_nodes(parent, other);
 				brother = parent->rb_nodes[other];
 				brother = parent->rb_nodes[other];
+				if (brother == NULL)
+					return;/* The tree may be broken. */
 			} else {
 			} else {
 				/*
 				/*
 				 * Both our parent and brother are black.
 				 * 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,
 			 * If we had two red nephews, then after the swap,
 			 * our former father would have a red grandson. 
 			 * 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]);
 			RB_MARK_BLACK(brother->rb_nodes[other]);
 			__archive_rb_tree_reparent_nodes(parent, other);
 			__archive_rb_tree_reparent_nodes(parent, other);
 			break;		/* We're done! */
 			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])) {
 	if (RB_SENTINEL_P(self->rb_nodes[direction])) {
 		while (!RB_ROOT_P(rbt, self)) {
 		while (!RB_ROOT_P(rbt, self)) {
-			if (other == RB_POSITION(self))
+			if (other == (unsigned int)RB_POSITION(self))
 				return RB_FATHER(self);
 				return RB_FATHER(self);
 			self = 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
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\" 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
 .Dt ARCHIVE_READ 3
 .Os
 .Os
 .Sh NAME
 .Sh NAME
 .Nm archive_read
 .Nm archive_read
 .Nd functions for reading streaming archives
 .Nd functions for reading streaming archives
+.Sh LIBRARY
+Streaming Archive Library (libarchive, -larchive)
 .Sh SYNOPSIS
 .Sh SYNOPSIS
 .In archive.h
 .In archive.h
 .Sh DESCRIPTION
 .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_filters(struct archive_read *);
 static int	choose_format(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 struct archive_vtable *archive_read_vtable(void);
 static int64_t	_archive_filter_bytes(struct archive *, int);
 static int64_t	_archive_filter_bytes(struct archive *, int);
 static int	_archive_filter_code(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;
 			int64_t get, ask = request;
 			if (ask > skip_limit)
 			if (ask > skip_limit)
 				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)
 			if (get == 0)
 				return (total);
 				return (total);
 			request -= get;
 			request -= get;
 			total += get;
 			total += get;
 		}
 		}
-		return total;
 	} else if (self->archive->client.seeker != NULL
 	} else if (self->archive->client.seeker != NULL
 		&& request > 64 * 1024) {
 		&& request > 64 * 1024) {
 		/* If the client provided a seeker but not a skipper,
 		/* 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.
 		 * only do this for skips of over 64k.
 		 */
 		 */
 		int64_t before = self->position;
 		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)
 		if (after != before + request)
 			return ARCHIVE_FATAL;
 			return ARCHIVE_FATAL;
 		return after - before;
 		return after - before;
@@ -242,14 +239,64 @@ client_seek_proxy(struct archive_read_filter *self, int64_t offset, int whence)
 static int
 static int
 client_close_proxy(struct archive_read_filter *self)
 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);
 	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
 int
 archive_read_set_open_callback(struct archive *_a,
 archive_read_set_open_callback(struct archive *_a,
     archive_open_callback *client_opener)
     archive_open_callback *client_opener)
@@ -305,22 +352,110 @@ archive_read_set_close_callback(struct archive *_a,
 	return ARCHIVE_OK;
 	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
 int
 archive_read_set_callback_data(struct archive *_a, void *client_data)
 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;
 	struct archive_read *a = (struct archive_read *)_a;
 	archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW,
 	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;
 	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
 int
 archive_read_open1(struct archive *_a)
 archive_read_open1(struct archive *_a)
 {
 {
 	struct archive_read *a = (struct archive_read *)_a;
 	struct archive_read *a = (struct archive_read *)_a;
-	struct archive_read_filter *filter;
+	struct archive_read_filter *filter, *tmp;
 	int slot, e;
 	int slot, e;
+	unsigned int i;
 
 
 	archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW,
 	archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW,
 	    "archive_read_open");
 	    "archive_read_open");
@@ -335,11 +470,14 @@ archive_read_open1(struct archive *_a)
 
 
 	/* Open data source. */
 	/* Open data source. */
 	if (a->client.opener != NULL) {
 	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 (e != 0) {
 			/* If the open failed, call the closer to clean up. */
 			/* 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);
 			return (e);
 		}
 		}
 	}
 	}
@@ -350,31 +488,51 @@ archive_read_open1(struct archive *_a)
 	filter->bidder = NULL;
 	filter->bidder = NULL;
 	filter->upstream = NULL;
 	filter->upstream = NULL;
 	filter->archive = a;
 	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->read = client_read_proxy;
 	filter->skip = client_skip_proxy;
 	filter->skip = client_skip_proxy;
 	filter->seek = client_seek_proxy;
 	filter->seek = client_seek_proxy;
 	filter->close = client_close_proxy;
 	filter->close = client_close_proxy;
+	filter->sswitch = client_switch_proxy;
 	filter->name = "none";
 	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;
 	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);
 	return (e);
 }
 }
 
 
@@ -414,8 +572,8 @@ choose_filters(struct archive_read *a)
 			/* Verify the filter by asking it for some data. */
 			/* Verify the filter by asking it for some data. */
 			__archive_read_filter_ahead(a->filter, 1, &avail);
 			__archive_read_filter_ahead(a->filter, 1, &avail);
 			if (avail < 0) {
 			if (avail < 0) {
-				close_filters(a);
-				free_filters(a);
+				__archive_read_close_filters(a);
+				__archive_read_free_filters(a);
 				return (ARCHIVE_FATAL);
 				return (ARCHIVE_FATAL);
 			}
 			}
 			a->archive.compression_name = a->filter->name;
 			a->archive.compression_name = a->filter->name;
@@ -433,8 +591,8 @@ choose_filters(struct archive_read *a)
 		a->filter = filter;
 		a->filter = filter;
 		r = (best_bidder->init)(a->filter);
 		r = (best_bidder->init)(a->filter);
 		if (r != ARCHIVE_OK) {
 		if (r != ARCHIVE_OK) {
-			close_filters(a);
-			free_filters(a);
+			__archive_read_close_filters(a);
+			__archive_read_free_filters(a);
 			return (ARCHIVE_FATAL);
 			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_output_offset = 0;
 	a->read_data_remaining = 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. */
 	/* EOF always wins; otherwise return the worst error. */
 	return (r2 < r1 || r2 == ARCHIVE_EOF) ? r2 : r1;
 	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) {
 	while (s > 0) {
 		if (a->read_data_remaining == 0) {
 		if (a->read_data_remaining == 0) {
 			read_buf = a->read_data_block;
 			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,
 			r = _archive_read_data_block(&a->archive, &read_buf,
 			    &a->read_data_remaining, &a->read_data_offset);
 			    &a->read_data_remaining, &a->read_data_offset);
 			a->read_data_block = read_buf;
 			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. */
 		/* 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) {
 		    a->read_data_offset) {
 			len = s;
 			len = s;
 		} else if (a->read_data_output_offset <
 		} else if (a->read_data_output_offset <
 		    a->read_data_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
 		} else
 			len = 0;
 			len = 0;
 
 
@@ -665,6 +828,8 @@ archive_read_data(struct archive *_a, void *buff, size_t s)
 			bytes_read += len;
 			bytes_read += len;
 		}
 		}
 	}
 	}
+	a->read_data_is_posix_read = 0;
+	a->read_data_requested = 0;
 	return (bytes_read);
 	return (bytes_read);
 }
 }
 
 
@@ -699,6 +864,23 @@ archive_read_data_skip(struct archive *_a)
 	return (r);
 	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.
  * Read the next block of entry data from the archive.
  * This is a zero-copy interface; the client receives a pointer,
  * 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);
 	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;
 	struct archive_read_filter *f = a->filter;
 	int r = ARCHIVE_OK;
 	int r = ARCHIVE_OK;
@@ -746,8 +928,8 @@ close_filters(struct archive_read *a)
 	return r;
 	return r;
 }
 }
 
 
-static void
-free_filters(struct archive_read *a)
+void
+__archive_read_free_filters(struct archive_read *a)
 {
 {
 	while (a->filter != NULL) {
 	while (a->filter != NULL) {
 		struct archive_read_filter *t = a->filter->upstream;
 		struct archive_read_filter *t = a->filter->upstream;
@@ -791,7 +973,7 @@ _archive_read_close(struct archive *_a)
 	/* TODO: Clean up the formatters. */
 	/* TODO: Clean up the formatters. */
 
 
 	/* Release the filter objects. */
 	/* Release the filter objects. */
-	r1 = close_filters(a);
+	r1 = __archive_read_close_filters(a);
 	if (r1 < r)
 	if (r1 < r)
 		r = r1;
 		r = r1;
 
 
@@ -830,7 +1012,7 @@ _archive_read_free(struct archive *_a)
 	}
 	}
 
 
 	/* Free the filters */
 	/* Free the filters */
-	free_filters(a);
+	__archive_read_free_filters(a);
 
 
 	/* Release the bidder objects. */
 	/* Release the bidder objects. */
 	n = sizeof(a->bidders)/sizeof(a->bidders[0]);
 	n = sizeof(a->bidders)/sizeof(a->bidders[0]);
@@ -847,6 +1029,7 @@ _archive_read_free(struct archive *_a)
 		archive_entry_free(a->entry);
 		archive_entry_free(a->entry);
 	a->archive.magic = 0;
 	a->archive.magic = 0;
 	__archive_clean(&a->archive);
 	__archive_clean(&a->archive);
+	free(a->client.dataset);
 	free(a);
 	free(a);
 	return (r);
 	return (r);
 }
 }
@@ -856,7 +1039,8 @@ get_filter(struct archive *_a, int n)
 {
 {
 	struct archive_read *a = (struct archive_read *)_a;
 	struct archive_read *a = (struct archive_read *)_a;
 	struct archive_read_filter *f = a->filter;
 	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) {
 	if (n == -1 && f != NULL) {
 		struct archive_read_filter *last = f;
 		struct archive_read_filter *last = f;
 		f = f->upstream;
 		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_header)(struct archive_read *, struct archive_entry *),
     int (*read_data)(struct archive_read *, const void **, size_t *, int64_t *),
     int (*read_data)(struct archive_read *, const void **, size_t *, int64_t *),
     int (*read_data_skip)(struct archive_read *),
     int (*read_data_skip)(struct archive_read *),
+    int64_t (*seek_data)(struct archive_read *, int64_t, int),
     int (*cleanup)(struct archive_read *))
     int (*cleanup)(struct archive_read *))
 {
 {
 	int i, number_slots;
 	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_header = read_header;
 			a->formats[i].read_data = read_data;
 			a->formats[i].read_data = read_data;
 			a->formats[i].read_data_skip = read_data_skip;
 			a->formats[i].read_data_skip = read_data_skip;
+			a->formats[i].seek_data = seek_data;
 			a->formats[i].cleanup = cleanup;
 			a->formats[i].cleanup = cleanup;
 			a->formats[i].data = format_data;
 			a->formats[i].data = format_data;
 			a->formats[i].name = name;
 			a->formats[i].name = name;
@@ -1074,7 +1260,8 @@ __archive_read_filter_ahead(struct archive_read_filter *filter,
 		if (filter->next > filter->buffer &&
 		if (filter->next > filter->buffer &&
 		    filter->next + min > filter->buffer + filter->buffer_size) {
 		    filter->next + min > filter->buffer + filter->buffer_size) {
 			if (filter->avail > 0)
 			if (filter->avail > 0)
-				memmove(filter->buffer, filter->next, filter->avail);
+				memmove(filter->buffer, filter->next,
+				    filter->avail);
 			filter->next = filter->buffer;
 			filter->next = filter->buffer;
 		}
 		}
 
 
@@ -1089,15 +1276,26 @@ __archive_read_filter_ahead(struct archive_read_filter *filter,
 			    &filter->client_buff);
 			    &filter->client_buff);
 			if (bytes_read < 0) {		/* Read error. */
 			if (bytes_read < 0) {		/* Read error. */
 				filter->client_total = filter->client_avail = 0;
 				filter->client_total = filter->client_avail = 0;
-				filter->client_next = filter->client_buff = NULL;
+				filter->client_next =
+				    filter->client_buff = NULL;
 				filter->fatal = 1;
 				filter->fatal = 1;
 				if (avail != NULL)
 				if (avail != NULL)
 					*avail = ARCHIVE_FATAL;
 					*avail = ARCHIVE_FATAL;
 				return (NULL);
 				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_total = filter->client_avail = 0;
-				filter->client_next = filter->client_buff = NULL;
+				filter->client_next =
+				    filter->client_buff = NULL;
 				filter->end_of_file = 1;
 				filter->end_of_file = 1;
 				/* Return whatever we do have. */
 				/* Return whatever we do have. */
 				if (avail != NULL)
 				if (avail != NULL)
@@ -1107,9 +1305,7 @@ __archive_read_filter_ahead(struct archive_read_filter *filter,
 			filter->client_total = bytes_read;
 			filter->client_total = bytes_read;
 			filter->client_avail = filter->client_total;
 			filter->client_avail = filter->client_total;
 			filter->client_next = filter->client_buff;
 			filter->client_next = filter->client_buff;
-		}
-		else
-		{
+		} else {
 			/*
 			/*
 			 * We can't satisfy the request from the copy
 			 * We can't satisfy the request from the copy
 			 * buffer or the existing client data, so we
 			 * buffer or the existing client data, so we
@@ -1130,9 +1326,10 @@ __archive_read_filter_ahead(struct archive_read_filter *filter,
 					t *= 2;
 					t *= 2;
 					if (t <= s) { /* Integer overflow! */
 					if (t <= s) { /* Integer overflow! */
 						archive_set_error(
 						archive_set_error(
-							&filter->archive->archive,
-							ENOMEM,
-						    "Unable to allocate copy buffer");
+						    &filter->archive->archive,
+						    ENOMEM,
+						    "Unable to allocate copy"
+						    " buffer");
 						filter->fatal = 1;
 						filter->fatal = 1;
 						if (avail != NULL)
 						if (avail != NULL)
 							*avail = ARCHIVE_FATAL;
 							*avail = ARCHIVE_FATAL;
@@ -1171,8 +1368,8 @@ __archive_read_filter_ahead(struct archive_read_filter *filter,
 			if (tocopy > filter->client_avail)
 			if (tocopy > filter->client_avail)
 				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. */
 			/* Remove this data from client buffer. */
 			filter->client_next += tocopy;
 			filter->client_next += tocopy;
 			filter->client_avail -= 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. */
 	/* Use up the copy buffer first. */
 	if (filter->avail > 0) {
 	if (filter->avail > 0) {
-		min = minimum(request, (int64_t)filter->avail);
+		min = (size_t)minimum(request, (int64_t)filter->avail);
 		filter->next += min;
 		filter->next += min;
 		filter->avail -= min;
 		filter->avail -= min;
 		request -= min;
 		request -= min;
@@ -1241,7 +1438,7 @@ advance_file_pointer(struct archive_read_filter *filter, int64_t request)
 
 
 	/* Then use up the client buffer. */
 	/* Then use up the client buffer. */
 	if (filter->client_avail > 0) {
 	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_next += min;
 		filter->client_avail -= min;
 		filter->client_avail -= min;
 		request -= min;
 		request -= min;
@@ -1275,6 +1472,13 @@ advance_file_pointer(struct archive_read_filter *filter, int64_t request)
 		}
 		}
 
 
 		if (bytes_read == 0) {
 		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->client_buff = NULL;
 			filter->end_of_file = 1;
 			filter->end_of_file = 1;
 			return (total_bytes_skipped);
 			return (total_bytes_skipped);
@@ -1283,7 +1487,7 @@ advance_file_pointer(struct archive_read_filter *filter, int64_t request)
 		if (bytes_read >= request) {
 		if (bytes_read >= request) {
 			filter->client_next =
 			filter->client_next =
 			    ((const char *)filter->client_buff) + request;
 			    ((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;
 			filter->client_total = bytes_read;
 			total_bytes_skipped += request;
 			total_bytes_skipped += request;
 			filter->position += request;
 			filter->position += request;
@@ -1306,15 +1510,109 @@ __archive_read_seek(struct archive_read *a, int64_t offset, int whence)
 }
 }
 
 
 int64_t
 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;
 	int64_t r;
+	unsigned int cursor;
 
 
 	if (filter->closed || filter->fatal)
 	if (filter->closed || filter->fatal)
 		return (ARCHIVE_FATAL);
 		return (ARCHIVE_FATAL);
 	if (filter->seek == NULL)
 	if (filter->seek == NULL)
 		return (ARCHIVE_FAILED);
 		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) {
 	if (r >= 0) {
 		/*
 		/*
 		 * Ouch.  Clearing the buffer like this hurts, especially
 		 * 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$
 .\" $FreeBSD$
 .\"
 .\"
-.Dd March 22, 2011
+.Dd February 2, 2012
 .Dt ARCHIVE_READ_DATA 3
 .Dt ARCHIVE_READ_DATA 3
 .Os
 .Os
 .Sh NAME
 .Sh NAME
@@ -33,6 +33,8 @@
 .Nm archive_read_data_skip ,
 .Nm archive_read_data_skip ,
 .Nm archive_read_data_into_fd
 .Nm archive_read_data_into_fd
 .Nd functions for reading streaming archives
 .Nd functions for reading streaming archives
+.Sh LIBRARY
+Streaming Archive Library (libarchive, -larchive)
 .Sh SYNOPSIS
 .Sh SYNOPSIS
 .In archive.h
 .In archive.h
 .Ft ssize_t
 .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) {
 	while (target_offset > actual_offset) {
 		to_write = nulls_size;
 		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);
 			to_write = (size_t)(target_offset - actual_offset);
 		bytes_written = write(fd, nulls, to_write);
 		bytes_written = write(fd, nulls, to_write);
 		if (bytes_written < 0) {
 		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
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\" 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
 .Dt ARCHIVE_READ_DISK 3
 .Os
 .Os
 .Sh NAME
 .Sh NAME
@@ -42,6 +42,8 @@
 .Nm archive_read_finish ,
 .Nm archive_read_finish ,
 .Nm archive_read_free
 .Nm archive_read_free
 .Nd functions for reading objects from disk
 .Nd functions for reading objects from disk
+.Sh LIBRARY
+Streaming Archive Library (libarchive, -larchive)
 .Sh SYNOPSIS
 .Sh SYNOPSIS
 .In archive.h
 .In archive.h
 .Ft struct archive *
 .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) 2003-2009 Tim Kientzle
- * Copyright (c) 2010 Michihiro NAKAJIMA
+ * Copyright (c) 2010-2012 Michihiro NAKAJIMA
  * All rights reserved.
  * All rights reserved.
  *
  *
  * Redistribution and use in source and binary forms, with or without
  * 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
 #ifdef HAVE_SYS_STAT_H
 #include <sys/stat.h>
 #include <sys/stat.h>
 #endif
 #endif
-#ifdef HAVE_SYS_XATTR_H
+#if defined(HAVE_SYS_XATTR_H)
 #include <sys/xattr.h>
 #include <sys/xattr.h>
+#elif defined(HAVE_ATTR_XATTR_H)
+#include <attr/xattr.h>
 #endif
 #endif
 #ifdef HAVE_SYS_EA_H
 #ifdef HAVE_SYS_EA_H
 #include <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
 #ifdef HAVE_ACL_LIBACL_H
 #include <acl/libacl.h>
 #include <acl/libacl.h>
 #endif
 #endif
-#ifdef HAVE_ATTR_XATTR_H
-#include <attr/xattr.h>
-#endif
 #ifdef HAVE_COPYFILE_H
 #ifdef HAVE_COPYFILE_H
 #include <copyfile.h>
 #include <copyfile.h>
 #endif
 #endif
@@ -104,6 +103,10 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_read_disk_entry_from_file.c 2010
 #include "archive_private.h"
 #include "archive_private.h"
 #include "archive_read_disk_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
  * Linux and FreeBSD plug this obvious hole in POSIX.1e in
  * different ways.
  * 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
 #define	ACL_GET_PERM acl_get_perm_np
 #endif
 #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 *,
 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 *,
 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 *,
 static int setup_sparse(struct archive_read_disk *,
-    struct archive_entry *, int fd);
+    struct archive_entry *, int *fd);
 
 
 int
 int
 archive_read_disk_entry_from_file(struct archive *_a,
 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
 	 * 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. */
 	 * open file descriptor which we can use in the subsequent lookups. */
 	if ((S_ISREG(st->st_mode) || S_ISDIR(st->st_mode))) {
 	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) {
 		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)
 			if (r == 0 && stflags != 0)
 				archive_entry_set_fflags(entry, 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");
 			    "Couldn't read link data");
 			return (ARCHIVE_FAILED);
 			return (ARCHIVE_FAILED);
 		}
 		}
+		if (a->tree != NULL) {
 #ifdef HAVE_READLINKAT
 #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 */
 #endif /* HAVE_READLINKAT */
-		lnklen = readlink(path, linkbuffer, linkbuffer_len);
+		} else
+			lnklen = readlink(path, linkbuffer, linkbuffer_len);
 		if (lnklen < 0) {
 		if (lnklen < 0) {
 			archive_set_error(&a->archive, errno,
 			archive_set_error(&a->archive, errno,
 			    "Couldn't read link data");
 			    "Couldn't read link data");
@@ -232,14 +250,16 @@ archive_read_disk_entry_from_file(struct archive *_a,
 	}
 	}
 #endif /* HAVE_READLINK || HAVE_READLINKAT */
 #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)
 	if (r1 < r)
 		r = r1;
 		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)
 	if (r1 < r)
 		r = r1;
 		r = r1;
 
 
@@ -265,16 +285,18 @@ archive_read_disk_entry_from_file(struct archive *_a,
  */
  */
 static int
 static int
 setup_mac_metadata(struct archive_read_disk *a,
 setup_mac_metadata(struct archive_read_disk *a,
-    struct archive_entry *entry, int fd)
+    struct archive_entry *entry, int *fd)
 {
 {
 	int tempfd = -1;
 	int tempfd = -1;
 	int copyfile_flags = COPYFILE_NOFOLLOW | COPYFILE_ACL | COPYFILE_XATTR;
 	int copyfile_flags = COPYFILE_NOFOLLOW | COPYFILE_ACL | COPYFILE_XATTR;
 	struct stat copyfile_stat;
 	struct stat copyfile_stat;
 	int ret = ARCHIVE_OK;
 	int ret = ARCHIVE_OK;
-	void *buff;
+	void *buff = NULL;
 	int have_attrs;
 	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);
 	name = archive_entry_sourcepath(entry);
 	if (name == NULL)
 	if (name == NULL)
 		name = archive_entry_pathname(entry);
 		name = archive_entry_pathname(entry);
@@ -284,6 +306,14 @@ setup_mac_metadata(struct archive_read_disk *a,
 		return (ARCHIVE_WARN);
 		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. */
 	/* Short-circuit if there's nothing to do. */
 	have_attrs = copyfile(name, NULL, 0, copyfile_flags | COPYFILE_CHECK);
 	have_attrs = copyfile(name, NULL, 0, copyfile_flags | COPYFILE_CHECK);
 	if (have_attrs == -1) {
 	if (have_attrs == -1) {
@@ -299,25 +329,28 @@ setup_mac_metadata(struct archive_read_disk *a,
 		tempdir = getenv("TMPDIR");
 		tempdir = getenv("TMPDIR");
 	if (tempdir == NULL)
 	if (tempdir == NULL)
 		tempdir = _PATH_TMP;
 		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
 	/* XXX I wish copyfile() could pack directly to a memory
 	 * buffer; that would avoid the temp file here.  For that
 	 * buffer; that would avoid the temp file here.  For that
 	 * matter, it would be nice if fcopyfile() actually worked,
 	 * matter, it would be nice if fcopyfile() actually worked,
 	 * that would reduce the many open/close races here. */
 	 * 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,
 		archive_set_error(&a->archive, errno,
 		    "Could not pack extended attributes");
 		    "Could not pack extended attributes");
 		ret = ARCHIVE_WARN;
 		ret = ARCHIVE_WARN;
 		goto cleanup;
 		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)) {
 	if (fstat(tempfd, &copyfile_stat)) {
 		archive_set_error(&a->archive, errno,
 		archive_set_error(&a->archive, errno,
 		    "Could not check size of extended attributes");
 		    "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);
 	archive_entry_copy_mac_metadata(entry, buff, copyfile_stat.st_size);
 
 
 cleanup:
 cleanup:
-	if (tempfd >= 0)
+	if (tempfd >= 0) {
 		close(tempfd);
 		close(tempfd);
-	if (tempfile != NULL)
-		unlink(tempfile);
+		unlink(tempfile.s);
+	}
+	archive_string_free(&tempfile);
+	free(buff);
 	return (ret);
 	return (ret);
 }
 }
 
 
@@ -354,7 +389,7 @@ cleanup:
  */
  */
 static int
 static int
 setup_mac_metadata(struct archive_read_disk *a,
 setup_mac_metadata(struct archive_read_disk *a,
-    struct archive_entry *entry, int fd)
+    struct archive_entry *entry, int *fd)
 {
 {
 	(void)a; /* UNUSED */
 	(void)a; /* UNUSED */
 	(void)entry; /* UNUSED */
 	(void)entry; /* UNUSED */
@@ -364,16 +399,19 @@ setup_mac_metadata(struct archive_read_disk *a,
 #endif
 #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);
     struct archive_entry *entry, acl_t acl, int archive_entry_acl_type);
 
 
 static int
 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;
 	const char	*accpath;
 	acl_t		 acl;
 	acl_t		 acl;
+#if HAVE_ACL_IS_TRIVIAL_NP
+	int		r;
+#endif
 
 
 	accpath = archive_entry_sourcepath(entry);
 	accpath = archive_entry_sourcepath(entry);
 	if (accpath == NULL)
 	if (accpath == NULL)
@@ -381,9 +419,38 @@ setup_acls_posix1e(struct archive_read_disk *a,
 
 
 	archive_entry_acl_clear(entry);
 	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. */
 	/* 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
 #if HAVE_ACL_GET_LINK_NP
 	else if (!a->follow_symlinks)
 	else if (!a->follow_symlinks)
 		acl = acl_get_link_np(accpath, ACL_TYPE_ACCESS);
 		acl = acl_get_link_np(accpath, ACL_TYPE_ACCESS);
@@ -397,7 +464,7 @@ setup_acls_posix1e(struct archive_read_disk *a,
 	else
 	else
 		acl = acl_get_file(accpath, ACL_TYPE_ACCESS);
 		acl = acl_get_file(accpath, ACL_TYPE_ACCESS);
 	if (acl != NULL) {
 	if (acl != NULL) {
-		setup_acl_posix1e(a, entry, acl,
+		translate_acl(a, entry, acl,
 		    ARCHIVE_ENTRY_ACL_TYPE_ACCESS);
 		    ARCHIVE_ENTRY_ACL_TYPE_ACCESS);
 		acl_free(acl);
 		acl_free(acl);
 	}
 	}
@@ -406,7 +473,7 @@ setup_acls_posix1e(struct archive_read_disk *a,
 	if (S_ISDIR(archive_entry_mode(entry))) {
 	if (S_ISDIR(archive_entry_mode(entry))) {
 		acl = acl_get_file(accpath, ACL_TYPE_DEFAULT);
 		acl = acl_get_file(accpath, ACL_TYPE_DEFAULT);
 		if (acl != NULL) {
 		if (acl != NULL) {
-			setup_acl_posix1e(a, entry, acl,
+			translate_acl(a, entry, acl,
 			    ARCHIVE_ENTRY_ACL_TYPE_DEFAULT);
 			    ARCHIVE_ENTRY_ACL_TYPE_DEFAULT);
 			acl_free(acl);
 			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_tag_t	 acl_tag;
+	acl_entry_type_t acl_type;
+	acl_flagset_t	 acl_flagset;
 	acl_entry_t	 acl_entry;
 	acl_entry_t	 acl_entry;
 	acl_permset_t	 acl_permset;
 	acl_permset_t	 acl_permset;
+	int		 brand, i, r, entry_acl_type;
 	int		 s, ae_id, ae_tag, ae_perm;
 	int		 s, ae_id, ae_tag, ae_perm;
 	const char	*ae_name;
 	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);
 	s = acl_get_entry(acl, ACL_FIRST_ENTRY, &acl_entry);
 	while (s == 1) {
 	while (s == 1) {
 		ae_id = -1;
 		ae_id = -1;
 		ae_name = NULL;
 		ae_name = NULL;
+		ae_perm = 0;
 
 
 		acl_get_tag_type(acl_entry, &acl_tag);
 		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_id = (int)*(uid_t *)acl_get_qualifier(acl_entry);
 			ae_name = archive_read_disk_uname(&a->archive, ae_id);
 			ae_name = archive_read_disk_uname(&a->archive, ae_id);
 			ae_tag = ARCHIVE_ENTRY_ACL_USER;
 			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_id = (int)*(gid_t *)acl_get_qualifier(acl_entry);
 			ae_name = archive_read_disk_gname(&a->archive, ae_id);
 			ae_name = archive_read_disk_gname(&a->archive, ae_id);
 			ae_tag = ARCHIVE_ENTRY_ACL_GROUP;
 			ae_tag = ARCHIVE_ENTRY_ACL_GROUP;
-		} else if (acl_tag == ACL_MASK) {
+			break;
+		case ACL_MASK:
 			ae_tag = ARCHIVE_ENTRY_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;
 			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;
 			ae_tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ;
-		} else if (acl_tag == ACL_OTHER) {
+			break;
+		case ACL_OTHER:
 			ae_tag = ARCHIVE_ENTRY_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. */
 			/* Skip types that libarchive can't support. */
+			s = acl_get_entry(acl, ACL_NEXT_ENTRY, &acl_entry);
 			continue;
 			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);
 		s = acl_get_entry(acl, ACL_NEXT_ENTRY, &acl_entry);
 	}
 	}
+	return (ARCHIVE_OK);
 }
 }
 #else
 #else
 static int
 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)a;      /* UNUSED */
 	(void)entry;  /* UNUSED */
 	(void)entry;  /* UNUSED */
@@ -571,7 +750,7 @@ setup_xattr(struct archive_read_disk *a,
 
 
 static int
 static int
 setup_xattrs(struct archive_read_disk *a,
 setup_xattrs(struct archive_read_disk *a,
-    struct archive_entry *entry, int fd)
+    struct archive_entry *entry, int *fd)
 {
 {
 	char *list, *p;
 	char *list, *p;
 	const char *path;
 	const char *path;
@@ -581,16 +760,30 @@ setup_xattrs(struct archive_read_disk *a,
 	if (path == NULL)
 	if (path == NULL)
 		path = archive_entry_pathname(entry);
 		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 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)
 	else if (!a->follow_symlinks)
 		list_size = llistxattr(path, NULL, 0);
 		list_size = llistxattr(path, NULL, 0);
 	else
 	else
 		list_size = listxattr(path, NULL, 0);
 		list_size = listxattr(path, NULL, 0);
 #elif HAVE_FLISTEA
 #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)
 	else if (!a->follow_symlinks)
 		list_size = llistea(path, NULL, 0);
 		list_size = llistea(path, NULL, 0);
 	else
 	else
@@ -614,15 +807,15 @@ setup_xattrs(struct archive_read_disk *a,
 	}
 	}
 
 
 #if HAVE_FLISTXATTR
 #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)
 	else if (!a->follow_symlinks)
 		list_size = llistxattr(path, list, list_size);
 		list_size = llistxattr(path, list, list_size);
 	else
 	else
 		list_size = listxattr(path, list, list_size);
 		list_size = listxattr(path, list, list_size);
 #elif HAVE_FLISTEA
 #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)
 	else if (!a->follow_symlinks)
 		list_size = llistea(path, list, list_size);
 		list_size = llistea(path, list, list_size);
 	else
 	else
@@ -640,7 +833,7 @@ setup_xattrs(struct archive_read_disk *a,
 		if (strncmp(p, "system.", 7) == 0 ||
 		if (strncmp(p, "system.", 7) == 0 ||
 				strncmp(p, "xfsroot.", 8) == 0)
 				strncmp(p, "xfsroot.", 8) == 0)
 			continue;
 			continue;
-		setup_xattr(a, entry, p, fd);
+		setup_xattr(a, entry, p, *fd);
 	}
 	}
 
 
 	free(list);
 	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);
 		size = extattr_get_file(accpath, namespace, name, value, size);
 
 
 	if (size == -1) {
 	if (size == -1) {
+		free(value);
 		archive_set_error(&a->archive, errno,
 		archive_set_error(&a->archive, errno,
 		    "Couldn't read extended attribute");
 		    "Couldn't read extended attribute");
 		return (ARCHIVE_WARN);
 		return (ARCHIVE_WARN);
@@ -714,7 +908,7 @@ setup_xattr(struct archive_read_disk *a, struct archive_entry *entry,
 
 
 static int
 static int
 setup_xattrs(struct archive_read_disk *a,
 setup_xattrs(struct archive_read_disk *a,
-    struct archive_entry *entry, int fd)
+    struct archive_entry *entry, int *fd)
 {
 {
 	char buff[512];
 	char buff[512];
 	char *list, *p;
 	char *list, *p;
@@ -726,8 +920,22 @@ setup_xattrs(struct archive_read_disk *a,
 	if (path == NULL)
 	if (path == NULL)
 		path = archive_entry_pathname(entry);
 		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)
 	else if (!a->follow_symlinks)
 		list_size = extattr_list_link(path, namespace, NULL, 0);
 		list_size = extattr_list_link(path, namespace, NULL, 0);
 	else
 	else
@@ -749,8 +957,8 @@ setup_xattrs(struct archive_read_disk *a,
 		return (ARCHIVE_FATAL);
 		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)
 	else if (!a->follow_symlinks)
 		list_size = extattr_list_link(path, namespace, list, list_size);
 		list_size = extattr_list_link(path, namespace, list, list_size);
 	else
 	else
@@ -772,7 +980,7 @@ setup_xattrs(struct archive_read_disk *a,
 		name = buff + strlen(buff);
 		name = buff + strlen(buff);
 		memcpy(name, p + 1, len);
 		memcpy(name, p + 1, len);
 		name[len] = '\0';
 		name[len] = '\0';
-		setup_xattr(a, entry, namespace, name, buff, fd);
+		setup_xattr(a, entry, namespace, name, buff, *fd);
 		p += 1 + len;
 		p += 1 + len;
 	}
 	}
 
 
@@ -787,7 +995,7 @@ setup_xattrs(struct archive_read_disk *a,
  */
  */
 static int
 static int
 setup_xattrs(struct archive_read_disk *a,
 setup_xattrs(struct archive_read_disk *a,
-    struct archive_entry *entry, int fd)
+    struct archive_entry *entry, int *fd)
 {
 {
 	(void)a;     /* UNUSED */
 	(void)a;     /* UNUSED */
 	(void)entry; /* UNUSED */
 	(void)entry; /* UNUSED */
@@ -816,14 +1024,13 @@ setup_xattrs(struct archive_read_disk *a,
 
 
 static int
 static int
 setup_sparse(struct archive_read_disk *a,
 setup_sparse(struct archive_read_disk *a,
-    struct archive_entry *entry, int fd)
+    struct archive_entry *entry, int *fd)
 {
 {
 	char buff[4096];
 	char buff[4096];
 	struct fiemap *fm;
 	struct fiemap *fm;
 	struct fiemap_extent *fe;
 	struct fiemap_extent *fe;
 	int64_t size;
 	int64_t size;
 	int count, do_fiemap;
 	int count, do_fiemap;
-	int initial_fd = fd;
 	int exit_sts = ARCHIVE_OK;
 	int exit_sts = ARCHIVE_OK;
 
 
 	if (archive_entry_filetype(entry) != AE_IFREG
 	if (archive_entry_filetype(entry) != AE_IFREG
@@ -831,20 +1038,27 @@ setup_sparse(struct archive_read_disk *a,
 	    || archive_entry_hardlink(entry) != NULL)
 	    || archive_entry_hardlink(entry) != NULL)
 		return (ARCHIVE_OK);
 		return (ARCHIVE_OK);
 
 
-	if (fd < 0) {
+	if (*fd < 0) {
 		const char *path;
 		const char *path;
 
 
 		path = archive_entry_sourcepath(entry);
 		path = archive_entry_sourcepath(entry);
 		if (path == NULL)
 		if (path == NULL)
 			path = archive_entry_pathname(entry);
 			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,
 			archive_set_error(&a->archive, errno,
 			    "Can't open `%s'", path);
 			    "Can't open `%s'", path);
 			return (ARCHIVE_FAILED);
 			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);
 	count = (sizeof(buff) - sizeof(*fm))/sizeof(*fe);
 	fm = (struct fiemap *)buff;
 	fm = (struct fiemap *)buff;
 	fm->fm_start = 0;
 	fm->fm_start = 0;
@@ -856,29 +1070,22 @@ setup_sparse(struct archive_read_disk *a,
 	for (;;) {
 	for (;;) {
 		int i, r;
 		int i, r;
 
 
-		r = ioctl(fd, FS_IOC_FIEMAP, fm); 
+		r = ioctl(*fd, FS_IOC_FIEMAP, fm); 
 		if (r < 0) {
 		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;
 			goto exit_setup_sparse;
 		}
 		}
 		if (fm->fm_mapped_extents == 0)
 		if (fm->fm_mapped_extents == 0)
 			break;
 			break;
 		fe = fm->fm_extents;
 		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)) {
 			if (!(fe->fe_flags & FIEMAP_EXTENT_UNWRITTEN)) {
 				/* The fe_length of the last block does not
 				/* The fe_length of the last block does not
 				 * adjust itself to its size files. */
 				 * adjust itself to its size files. */
 				int64_t length = fe->fe_length;
 				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;
 					length -= fe->fe_logical + length - size;
 				if (fe->fe_logical == 0 && length == size) {
 				if (fe->fe_logical == 0 && length == size) {
 					/* This is not sparse. */
 					/* This is not sparse. */
@@ -899,8 +1106,6 @@ setup_sparse(struct archive_read_disk *a,
 			break;
 			break;
 	}
 	}
 exit_setup_sparse:
 exit_setup_sparse:
-	if (initial_fd != fd)
-		close(fd);
 	return (exit_sts);
 	return (exit_sts);
 }
 }
 
 
@@ -912,10 +1117,9 @@ exit_setup_sparse:
 
 
 static int
 static int
 setup_sparse(struct archive_read_disk *a,
 setup_sparse(struct archive_read_disk *a,
-    struct archive_entry *entry, int fd)
+    struct archive_entry *entry, int *fd)
 {
 {
 	int64_t size;
 	int64_t size;
-	int initial_fd = fd;
 	off_t initial_off; /* FreeBSD/Solaris only, so off_t okay here */
 	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 */
 	off_t off_s, off_e; /* FreeBSD/Solaris only, so off_t okay here */
 	int exit_sts = ARCHIVE_OK;
 	int exit_sts = ARCHIVE_OK;
@@ -926,33 +1130,50 @@ setup_sparse(struct archive_read_disk *a,
 		return (ARCHIVE_OK);
 		return (ARCHIVE_OK);
 
 
 	/* Does filesystem support the reporting of hole ? */
 	/* 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);
 			return (ARCHIVE_OK);
-		initial_off = lseek(fd, 0, SEEK_CUR);
+		initial_off = lseek(*fd, 0, SEEK_CUR);
 		if (initial_off != 0)
 		if (initial_off != 0)
-			lseek(fd, 0, SEEK_SET);
+			lseek(*fd, 0, SEEK_SET);
 	} else {
 	} else {
 		const char *path;
 		const char *path;
 
 
 		path = archive_entry_sourcepath(entry);
 		path = archive_entry_sourcepath(entry);
 		if (path == NULL)
 		if (path == NULL)
 			path = archive_entry_pathname(entry);
 			path = archive_entry_pathname(entry);
+			
 		if (pathconf(path, _PC_MIN_HOLE_SIZE) <= 0)
 		if (pathconf(path, _PC_MIN_HOLE_SIZE) <= 0)
 			return (ARCHIVE_OK);
 			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,
 			archive_set_error(&a->archive, errno,
 			    "Can't open `%s'", path);
 			    "Can't open `%s'", path);
 			return (ARCHIVE_FAILED);
 			return (ARCHIVE_FAILED);
 		}
 		}
+		__archive_ensure_cloexec_flag(*fd);
 		initial_off = 0;
 		initial_off = 0;
 	}
 	}
 
 
 	off_s = 0;
 	off_s = 0;
 	size = archive_entry_size(entry);
 	size = archive_entry_size(entry);
 	while (off_s < size) {
 	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 (off_s == (off_t)-1) {
 			if (errno == ENXIO)
 			if (errno == ENXIO)
 				break;/* no more hole */
 				break;/* no more hole */
@@ -961,10 +1182,10 @@ setup_sparse(struct archive_read_disk *a,
 			exit_sts = ARCHIVE_FAILED;
 			exit_sts = ARCHIVE_FAILED;
 			goto exit_setup_sparse;
 			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) {
 			if (errno == ENXIO) {
-				off_e = lseek(fd, 0, SEEK_END);
+				off_e = lseek(*fd, 0, SEEK_END);
 				if (off_e != (off_t)-1)
 				if (off_e != (off_t)-1)
 					break;/* no more data */
 					break;/* no more data */
 			}
 			}
@@ -980,10 +1201,7 @@ setup_sparse(struct archive_read_disk *a,
 		off_s = off_e;
 		off_s = off_e;
 	}
 	}
 exit_setup_sparse:
 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);
 	return (exit_sts);
 }
 }
 
 
@@ -994,7 +1212,7 @@ exit_setup_sparse:
  */
  */
 static int
 static int
 setup_sparse(struct archive_read_disk *a,
 setup_sparse(struct archive_read_disk *a,
-    struct archive_entry *entry, int fd)
+    struct archive_entry *entry, int *fd)
 {
 {
 	(void)a;     /* UNUSED */
 	(void)a;     /* UNUSED */
 	(void)entry; /* 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) 2003-2009 Tim Kientzle
- * Copyright (c) 2010,2011 Michihiro NAKAJIMA
+ * Copyright (c) 2010-2012 Michihiro NAKAJIMA
  * All rights reserved.
  * All rights reserved.
  *
  *
  * Redistribution and use in source and binary forms, with or without
  * Redistribution and use in source and binary forms, with or without
@@ -52,6 +52,19 @@ __FBSDID("$FreeBSD$");
 #ifdef HAVE_LINUX_MAGIC_H
 #ifdef HAVE_LINUX_MAGIC_H
 #include <linux/magic.h>
 #include <linux/magic.h>
 #endif
 #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
 #ifdef HAVE_DIRECT_H
 #include <direct.h>
 #include <direct.h>
 #endif
 #endif
@@ -76,6 +89,9 @@ __FBSDID("$FreeBSD$");
 #ifdef HAVE_UNISTD_H
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
 #include <unistd.h>
 #endif
 #endif
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
 
 
 #include "archive.h"
 #include "archive.h"
 #include "archive_string.h"
 #include "archive_string.h"
@@ -89,6 +105,9 @@ __FBSDID("$FreeBSD$");
 #ifndef O_BINARY
 #ifndef O_BINARY
 #define O_BINARY	0
 #define O_BINARY	0
 #endif
 #endif
+#ifndef O_CLOEXEC
+#define O_CLOEXEC	0
+#endif
 
 
 /*-
 /*-
  * This is a new directory-walking system that addresses a number
  * This is a new directory-walking system that addresses a number
@@ -222,6 +241,7 @@ struct tree {
 	char			 symlink_mode;
 	char			 symlink_mode;
 	struct filesystem	*current_filesystem;
 	struct filesystem	*current_filesystem;
 	struct filesystem	*filesystem_table;
 	struct filesystem	*filesystem_table;
+	int			 initial_filesystem_id;
 	int			 current_filesystem_id;
 	int			 current_filesystem_id;
 	int			 max_filesystem_id;
 	int			 max_filesystem_id;
 	int			 allocated_filesytem;
 	int			 allocated_filesytem;
@@ -240,6 +260,7 @@ struct tree {
 #define	onWorkingDir	64 /* We are on the working dir where we are
 #define	onWorkingDir	64 /* We are on the working dir where we are
 			    * reading directory entry at this time. */
 			    * reading directory entry at this time. */
 #define	needsRestoreTimes 128
 #define	needsRestoreTimes 128
+#define	onInitialDir	256 /* We are on the initial dir. */
 
 
 static int
 static int
 tree_dir_next_posix(struct tree *t);
 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	setup_sparse(struct archive_read_disk *, struct archive_entry *);
 static int	close_and_restore_time(int fd, struct tree *,
 static int	close_and_restore_time(int fd, struct tree *,
 		    struct restore_time *);
 		    struct restore_time *);
+static int	open_on_current_dir(struct tree *, const char *, int);
+static int	tree_dup(int);
 
 
 
 
 static struct archive_vtable *
 static struct archive_vtable *
@@ -430,16 +453,19 @@ archive_read_disk_new(void)
 {
 {
 	struct archive_read_disk *a;
 	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)
 	if (a == NULL)
 		return (NULL);
 		return (NULL);
-	memset(a, 0, sizeof(*a));
 	a->archive.magic = ARCHIVE_READ_DISK_MAGIC;
 	a->archive.magic = ARCHIVE_READ_DISK_MAGIC;
 	a->archive.state = ARCHIVE_STATE_NEW;
 	a->archive.state = ARCHIVE_STATE_NEW;
 	a->archive.vtable = archive_read_disk_vtable();
 	a->archive.vtable = archive_read_disk_vtable();
 	a->lookup_uname = trivial_lookup_uname;
 	a->lookup_uname = trivial_lookup_uname;
 	a->lookup_gname = trivial_lookup_gname;
 	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);
 	return (&a->archive);
 }
 }
 
 
@@ -555,6 +581,37 @@ archive_read_disk_set_atime_restored(struct archive *_a)
 #endif
 #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.
  * Trivial implementations of gname/uname lookup functions.
  * These are normally overridden by the client, but these stub
  * 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.
 	 * Open the current file.
 	 */
 	 */
 	if (t->entry_fd < 0) {
 	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.
 		 * 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;
 			flags |= O_NOATIME;
 		do {
 		do {
 #endif
 #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);
 			    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)
 #if defined(O_NOATIME)
 			/*
 			/*
 			 * When we did open the file with O_NOATIME flag,
 			 * 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;
 	t->entry_buff_size = t->current_filesystem->buff_size;
 
 
 	buffbytes = t->entry_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;
 		buffbytes = t->current_sparse->length;
 
 
 	/*
 	/*
@@ -802,29 +855,17 @@ abort_read_data:
 }
 }
 
 
 static int
 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 *st; /* info to use for this entry */
 	const struct stat *lst;/* lstat() information */
 	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;
 	st = NULL;
 	lst = NULL;
 	lst = NULL;
+	t->descend = 0;
 	do {
 	do {
 		switch (tree_next(t)) {
 		switch (tree_next(t)) {
 		case TREE_ERROR_FATAL:
 		case TREE_ERROR_FATAL:
@@ -859,6 +900,38 @@ _archive_read_next_header2(struct archive *_a, struct archive_entry *entry)
 		}	
 		}	
 	} while (lst == NULL);
 	} 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.
 	 * 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);
 		tree_enter_initial_dir(t);
 		return (ARCHIVE_FATAL);
 		return (ARCHIVE_FATAL);
 	}
 	}
+	if (t->initial_filesystem_id == -1)
+		t->initial_filesystem_id = t->current_filesystem_id;
+	if (!a->traverse_mount_points) {
+		if (t->initial_filesystem_id != t->current_filesystem_id)
+			return (ARCHIVE_RETRY);
+	}
 	t->descend = descend;
 	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);
 	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 = archive_entry_mtime(entry);
 	t->restore_time.mtime_nsec = archive_entry_mtime_nsec(entry);
 	t->restore_time.mtime_nsec = archive_entry_mtime_nsec(entry);
 	t->restore_time.atime = archive_entry_atime(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.filetype = archive_entry_filetype(entry);
 	t->restore_time.noatime = t->current_filesystem->noatime;
 	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.
 	 * 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. */
 	/* Return to the initial directory. */
 	tree_enter_initial_dir(t);
 	tree_enter_initial_dir(t);
-	archive_entry_copy_sourcepath(entry, tree_current_path(t));
 
 
 	/*
 	/*
 	 * EOF and FATAL are persistent at this layer.  By
 	 * 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;
 		break;
 	case ARCHIVE_OK:
 	case ARCHIVE_OK:
 	case ARCHIVE_WARN:
 	case ARCHIVE_WARN:
+		/* Overwrite the sourcepath based on the initial directory. */
+		archive_entry_copy_sourcepath(entry, tree_current_path(t));
 		t->entry_total = 0;
 		t->entry_total = 0;
 		if (archive_entry_filetype(entry) == AE_IFREG) {
 		if (archive_entry_filetype(entry) == AE_IFREG) {
 			t->nlink = archive_entry_nlink(entry);
 			t->nlink = archive_entry_nlink(entry);
@@ -1018,6 +1189,48 @@ setup_sparse(struct archive_read_disk *a, struct archive_entry *entry)
 	return (ARCHIVE_OK);
 	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
  * Called by the client to mark the directory just returned from
  * tree_next() as needing to be visited.
  * 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 archive_read_disk *a = (struct archive_read_disk *)_a;
 	struct tree *t = a->tree;
 	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");
 	    "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)) {
 	if (tree_current_is_physical_dir(t)) {
 		tree_push(t, t->basename, t->current_filesystem_id,
 		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);
 	archive_string_init(&path);
 	if (archive_string_append_from_wcs(&path, pathname,
 	if (archive_string_append_from_wcs(&path, pathname,
 	    wcslen(pathname)) != 0) {
 	    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;
 		a->archive.state = ARCHIVE_STATE_FATAL;
 		ret = ARCHIVE_FATAL;
 		ret = ARCHIVE_FATAL;
 	} else
 	} else
@@ -1151,15 +1366,17 @@ update_current_filesystem(struct archive_read_disk *a, int64_t dev)
 	fid = t->max_filesystem_id++;
 	fid = t->max_filesystem_id++;
 	if (t->max_filesystem_id > t->allocated_filesytem) {
 	if (t->max_filesystem_id > t->allocated_filesytem) {
 		size_t s;
 		size_t s;
+		void *p;
 
 
 		s = t->max_filesystem_id * 2;
 		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,
 			archive_set_error(&a->archive, ENOMEM,
 			    "Can't allocate tar data");
 			    "Can't allocate tar data");
 			return (ARCHIVE_FATAL);
 			return (ARCHIVE_FATAL);
 		}
 		}
+		t->filesystem_table = (struct filesystem *)p;
 		t->allocated_filesytem = s;
 		t->allocated_filesytem = s;
 	}
 	}
 	t->current_filesystem_id = fid;
 	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->synthetic = -1;
 	t->current_filesystem->remote = -1;
 	t->current_filesystem->remote = -1;
 	if (tree_current_is_symblic_link_target(t)) {
 	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
 		 * Get file system statistics on any directory
 		 * where current is.
 		 * where current is.
 		 */
 		 */
 		int fd = openat(tree_current_dir_fd(t),
 		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) {
 		if (fd < 0) {
 			archive_set_error(&a->archive, errno,
 			archive_set_error(&a->archive, errno,
 			    "openat failed");
 			    "openat failed");
@@ -1285,6 +1503,10 @@ setup_current_filesystem(struct archive_read_disk *a)
 			xr = get_xfer_size(t, fd, NULL);
 			xr = get_xfer_size(t, fd, NULL);
 		close(fd);
 		close(fd);
 #else
 #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);
 		r = statfs(tree_current_access_path(t), &sfs);
 		if (r == 0)
 		if (r == 0)
 			xr = get_xfer_size(t, -1, tree_current_access_path(t));
 			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;
 	t->current_filesystem->name_max = sfs.f_namemax;
 #else
 #else
 	/* Mac OS X does not have f_namemax in struct statfs. */
 	/* 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);
 		nm = pathconf(tree_current_access_path(t), _PC_NAME_MAX);
-	else
+	} else
 		nm = fpathconf(tree_current_dir_fd(t), _PC_NAME_MAX);
 		nm = fpathconf(tree_current_dir_fd(t), _PC_NAME_MAX);
 	if (nm == -1)
 	if (nm == -1)
 		t->current_filesystem->name_max = NAME_MAX;
 		t->current_filesystem->name_max = NAME_MAX;
@@ -1360,6 +1586,10 @@ setup_current_filesystem(struct archive_read_disk *a)
 	int r, xr = 0;
 	int r, xr = 0;
 
 
 	t->current_filesystem->synthetic = -1;
 	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)) {
 	if (tree_current_is_symblic_link_target(t)) {
 		r = statvfs(tree_current_access_path(t), &sfs);
 		r = statvfs(tree_current_access_path(t), &sfs);
 		if (r == 0)
 		if (r == 0)
@@ -1434,13 +1664,14 @@ setup_current_filesystem(struct archive_read_disk *a)
 	int r, vr = 0, xr = 0;
 	int r, vr = 0, xr = 0;
 
 
 	if (tree_current_is_symblic_link_target(t)) {
 	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
 		 * Get file system statistics on any directory
 		 * where current is.
 		 * where current is.
 		 */
 		 */
 		int fd = openat(tree_current_dir_fd(t),
 		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) {
 		if (fd < 0) {
 			archive_set_error(&a->archive, errno,
 			archive_set_error(&a->archive, errno,
 			    "openat failed");
 			    "openat failed");
@@ -1452,6 +1683,10 @@ setup_current_filesystem(struct archive_read_disk *a)
 			xr = get_xfer_size(t, fd, NULL);
 			xr = get_xfer_size(t, fd, NULL);
 		close(fd);
 		close(fd);
 #else
 #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);
 		vr = statvfs(tree_current_access_path(t), &svfs);
 		r = statfs(tree_current_access_path(t), &sfs);
 		r = statfs(tree_current_access_path(t), &sfs);
 		if (r == 0)
 		if (r == 0)
@@ -1463,9 +1698,11 @@ setup_current_filesystem(struct archive_read_disk *a)
 		r = fstatfs(tree_current_dir_fd(t), &sfs);
 		r = fstatfs(tree_current_dir_fd(t), &sfs);
 		if (r == 0)
 		if (r == 0)
 			xr = get_xfer_size(t, tree_current_dir_fd(t), NULL);
 			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
 #else
+		if (tree_enter_working_dir(t) != 0) {
+			archive_set_error(&a->archive, errno, "fchdir failed");
+			return (ARCHIVE_FAILED);
+		}
 		vr = statvfs(".", &svfs);
 		vr = statvfs(".", &svfs);
 		r = statfs(".", &sfs);
 		r = statfs(".", &sfs);
 		if (r == 0)
 		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->synthetic = -1;/* Not supported */
 	t->current_filesystem->remote = -1;/* Not supported */
 	t->current_filesystem->remote = -1;/* Not supported */
 	if (tree_current_is_symblic_link_target(t)) {
 	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
 		 * Get file system statistics on any directory
 		 * where current is.
 		 * where current is.
 		 */
 		 */
 		int fd = openat(tree_current_dir_fd(t),
 		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) {
 		if (fd < 0) {
 			archive_set_error(&a->archive, errno,
 			archive_set_error(&a->archive, errno,
 			    "openat failed");
 			    "openat failed");
@@ -1553,6 +1791,10 @@ setup_current_filesystem(struct archive_read_disk *a)
 			xr = get_xfer_size(t, fd, NULL);
 			xr = get_xfer_size(t, fd, NULL);
 		close(fd);
 		close(fd);
 #else
 #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);
 		r = statvfs(tree_current_access_path(t), &sfs);
 		if (r == 0)
 		if (r == 0)
 			xr = get_xfer_size(t, -1, tree_current_access_path(t));
 			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);
 		r = fstatvfs(tree_current_dir_fd(t), &sfs);
 		if (r == 0)
 		if (r == 0)
 			xr = get_xfer_size(t, tree_current_dir_fd(t), NULL);
 			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
 #else
+		if (tree_enter_working_dir(t) != 0) {
+			archive_set_error(&a->archive, errno, "fchdir failed");
+			return (ARCHIVE_FAILED);
+		}
 		r = statvfs(".", &sfs);
 		r = statvfs(".", &sfs);
 		if (r == 0)
 		if (r == 0)
 			xr = get_xfer_size(t, -1, ".");
 			xr = get_xfer_size(t, -1, ".");
@@ -1622,9 +1866,13 @@ setup_current_filesystem(struct archive_read_disk *a)
 #if defined(HAVE_READDIR_R)
 #if defined(HAVE_READDIR_R)
 	/* Set maximum filename length. */
 	/* Set maximum filename length. */
 #  if defined(_PC_NAME_MAX)
 #  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);
 		nm = pathconf(tree_current_access_path(t), _PC_NAME_MAX);
-	else
+	} else
 		nm = fpathconf(tree_current_dir_fd(t), _PC_NAME_MAX);
 		nm = fpathconf(tree_current_dir_fd(t), _PC_NAME_MAX);
 	if (nm == -1)
 	if (nm == -1)
 #  endif /* _PC_NAME_MAX */
 #  endif /* _PC_NAME_MAX */
@@ -1653,7 +1901,8 @@ static int
 close_and_restore_time(int fd, struct tree *t, struct restore_time *rt)
 close_and_restore_time(int fd, struct tree *t, struct restore_time *rt)
 {
 {
 #ifndef HAVE_UTIMES
 #ifndef HAVE_UTIMES
-	(void)a; /* UNUSED */
+	(void)t; /* UNUSED */
+	(void)rt; /* UNUSED */
 	return (close(fd));
 	return (close(fd));
 #else
 #else
 #if defined(HAVE_FUTIMENS) && !defined(__CYGWIN__)
 #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);
 	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.
  * 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)
 tree_reopen(struct tree *t, const char *path, int restore_time)
 {
 {
 	t->flags = (restore_time)?needsRestoreTimes:0;
 	t->flags = (restore_time)?needsRestoreTimes:0;
+	t->flags |= onInitialDir;
 	t->visit_type = 0;
 	t->visit_type = 0;
 	t->tree_errno = 0;
 	t->tree_errno = 0;
 	t->dirname_length = 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_fd = -1;
 	t->entry_eof = 0;
 	t->entry_eof = 0;
 	t->entry_remaining_bytes = 0;
 	t->entry_remaining_bytes = 0;
+	t->initial_filesystem_id = -1;
 
 
 	/* First item is set up a lot like a symlink traversal. */
 	/* First item is set up a lot like a symlink traversal. */
 	tree_push(t, path, 0, 0, 0, NULL);
 	tree_push(t, path, 0, 0, 0, NULL);
 	t->stack->flags = needsFirstVisit;
 	t->stack->flags = needsFirstVisit;
 	t->maxOpenCount = t->openCount = 1;
 	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);
 	return (t);
 }
 }
 
 
 static int
 static int
 tree_descent(struct tree *t)
 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);
 	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) {
 	if (new_fd < 0) {
 		t->tree_errno = errno;
 		t->tree_errno = errno;
 		r = TREE_ERROR_DIR;
 		r = TREE_ERROR_DIR;
@@ -1829,30 +2118,10 @@ tree_descent(struct tree *t)
 				t->maxOpenCount = t->openCount;
 				t->maxOpenCount = t->openCount;
 		} else
 		} else
 			close(t->working_dir_fd);
 			close(t->working_dir_fd);
+		/* Renew the current working directory. */
 		t->working_dir_fd = new_fd;
 		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);
 	return (r);
 }
 }
 
 
@@ -1863,37 +2132,23 @@ static int
 tree_ascend(struct tree *t)
 tree_ascend(struct tree *t)
 {
 {
 	struct tree_entry *te;
 	struct tree_entry *te;
-	int r = 0, prev_dir_fd;
+	int new_fd, r = 0, prev_dir_fd;
 
 
 	te = t->stack;
 	te = t->stack;
 	prev_dir_fd = t->working_dir_fd;
 	prev_dir_fd = t->working_dir_fd;
-#if defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_FDOPENDIR)
 	if (te->flags & isDirLink)
 	if (te->flags & isDirLink)
-		t->working_dir_fd = te->symlink_parent_fd;
+		new_fd = te->symlink_parent_fd;
 	else {
 	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 {
 	} 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
 		/* Current directory has been changed, we should
 		 * close an fd of previous working directory. */
 		 * close an fd of previous working directory. */
 		close_and_restore_time(prev_dir_fd, t, &te->restore_time);
 		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;
 	int r = 0;
 
 
-	if (t->flags & onWorkingDir) {
+	if ((t->flags & onInitialDir) == 0) {
 		r = fchdir(t->initial_dir_fd);
 		r = fchdir(t->initial_dir_fd);
-		if (r == 0)
+		if (r == 0) {
 			t->flags &= ~onWorkingDir;
 			t->flags &= ~onWorkingDir;
+			t->flags |= onInitialDir;
+		}
 	}
 	}
 	return (r);
 	return (r);
 }
 }
@@ -1937,8 +2194,10 @@ tree_enter_working_dir(struct tree *t)
 	 */
 	 */
 	if (t->depth > 0 && (t->flags & onWorkingDir) == 0) {
 	if (t->depth > 0 && (t->flags & onWorkingDir) == 0) {
 		r = fchdir(t->working_dir_fd);
 		r = fchdir(t->working_dir_fd);
-		if (r == 0)
+		if (r == 0) {
+			t->flags &= ~onInitialDir;
 			t->flags |= onWorkingDir;
 			t->flags |= onWorkingDir;
+		}
 	}
 	}
 	return (r);
 	return (r);
 }
 }
@@ -2045,10 +2304,16 @@ tree_dir_next_posix(struct tree *t)
 #endif
 #endif
 
 
 #if defined(HAVE_FDOPENDIR)
 #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
+		}
+#endif /* HAVE_FDOPENDIR */
+		if (t->d == NULL) {
 			r = tree_ascend(t); /* Undo "chdir" */
 			r = tree_ascend(t); /* Undo "chdir" */
 			tree_pop(t);
 			tree_pop(t);
 			t->tree_errno = errno;
 			t->tree_errno = errno;
@@ -2075,11 +2340,21 @@ tree_dir_next_posix(struct tree *t)
 #endif /* HAVE_READDIR_R */
 #endif /* HAVE_READDIR_R */
 	}
 	}
 	for (;;) {
 	for (;;) {
+		errno = 0;
 #if defined(HAVE_READDIR_R)
 #if defined(HAVE_READDIR_R)
 		r = readdir_r(t->d, t->dirent, &t->de);
 		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) {
 		if (r != 0 || t->de == NULL) {
 #else
 #else
-		errno = 0;
 		t->de = readdir(t->d);
 		t->de = readdir(t->d);
 		if (t->de == NULL) {
 		if (t->de == NULL) {
 			r = errno;
 			r = errno;
@@ -2118,6 +2393,8 @@ tree_current_stat(struct tree *t)
 		if (fstatat(tree_current_dir_fd(t),
 		if (fstatat(tree_current_dir_fd(t),
 		    tree_current_access_path(t), &t->st, 0) != 0)
 		    tree_current_access_path(t), &t->st, 0) != 0)
 #else
 #else
+		if (tree_enter_working_dir(t) != 0)
+			return NULL;
 		if (stat(tree_current_access_path(t), &t->st) != 0)
 		if (stat(tree_current_access_path(t), &t->st) != 0)
 #endif
 #endif
 			return NULL;
 			return NULL;
@@ -2138,6 +2415,8 @@ tree_current_lstat(struct tree *t)
 		    tree_current_access_path(t), &t->lst,
 		    tree_current_access_path(t), &t->lst,
 		    AT_SYMLINK_NOFOLLOW) != 0)
 		    AT_SYMLINK_NOFOLLOW) != 0)
 #else
 #else
+		if (tree_enter_working_dir(t) != 0)
+			return NULL;
 		if (lstat(tree_current_access_path(t), &t->lst) != 0)
 		if (lstat(tree_current_access_path(t), &t->lst) != 0)
 #endif
 #endif
 			return NULL;
 			return NULL;
@@ -2159,11 +2438,14 @@ tree_current_is_dir(struct tree *t)
 	 */
 	 */
 	if (t->flags & hasLstat) {
 	if (t->flags & hasLstat) {
 		/* If lstat() says it's a dir, it must be a dir. */
 		/* 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;
 			return 1;
 		/* Not a dir; might be a link to a dir. */
 		/* 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 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;
 			return 0;
 		/*
 		/*
 		 * It's a link, but we don't know what it's a link to,
 		 * 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() 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 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
 	 * 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;
 	struct tree_entry *te;
 
 
 	for (te = t->current->parent; te != NULL; te = te->parent) {
 	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 (1);
 	}
 	}
 	return (0);
 	return (0);
@@ -2238,7 +2525,8 @@ tree_current_is_symblic_link_target(struct tree *t)
 
 
 	lst = tree_current_lstat(t);
 	lst = tree_current_lstat(t);
 	st = tree_current_stat(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);
 	    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
 #define ARCHIVE_READ_DISK_PRIVATE_H_INCLUDED
 
 
 struct tree;
 struct tree;
+struct archive_entry;
 
 
 struct archive_read_disk {
 struct archive_read_disk {
 	struct archive	archive;
 	struct archive	archive;
@@ -55,10 +56,18 @@ struct archive_read_disk {
 
 
 	/* Directory traversals. */
 	/* Directory traversals. */
 	struct tree *tree;
 	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 . */
 	/* Set 1 if users request to restore atime . */
 	int		 restore_time;
 	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);
 	const char * (*lookup_gname)(void *private, int64_t gid);
 	void	(*cleanup_gname)(void *private);
 	void	(*cleanup_gname)(void *private);
@@ -66,6 +75,18 @@ struct archive_read_disk {
 	const char * (*lookup_uname)(void *private, int64_t uid);
 	const char * (*lookup_uname)(void *private, int64_t uid);
 	void	(*cleanup_uname)(void *private);
 	void	(*cleanup_uname)(void *private);
 	void	 *lookup_uname_data;
 	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
 #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$
 .\" $FreeBSD$
 .\"
 .\"
-.Dd March 22, 2011
+.Dd February 2, 2012
 .Dt ARCHIVE_READ_EXTRACT 3
 .Dt ARCHIVE_READ_EXTRACT 3
 .Os
 .Os
 .Sh NAME
 .Sh NAME
@@ -32,6 +32,8 @@
 .Nm archive_read_extract2 ,
 .Nm archive_read_extract2 ,
 .Nm archive_read_extract_set_progress_callback
 .Nm archive_read_extract_set_progress_callback
 .Nd functions for reading streaming archives
 .Nd functions for reading streaming archives
+.Sh LIBRARY
+Streaming Archive Library (libarchive, -larchive)
 .Sh SYNOPSIS
 .Sh SYNOPSIS
 .In archive.h
 .In archive.h
 .Ft int
 .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);
 			return (ARCHIVE_OK);
 		if (r != ARCHIVE_OK)
 		if (r != ARCHIVE_OK)
 			return (r);
 			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)
 		if (r < ARCHIVE_WARN)
 			r = ARCHIVE_WARN;
 			r = ARCHIVE_WARN;
 		if (r != ARCHIVE_OK) {
 		if (r != ARCHIVE_OK) {

+ 3 - 1
Utilities/cmlibarchive/libarchive/archive_read_filter.3

@@ -24,7 +24,7 @@
 .\"
 .\"
 .\" $FreeBSD$
 .\" $FreeBSD$
 .\"
 .\"
-.Dd March 19, 2011
+.Dd February 2, 2012
 .Dt ARCHIVE_READ_FILTER 3
 .Dt ARCHIVE_READ_FILTER 3
 .Os
 .Os
 .Sh NAME
 .Sh NAME
@@ -39,6 +39,8 @@
 .Nm archive_read_support_filter_program_signature
 .Nm archive_read_support_filter_program_signature
 .Nd functions for reading streaming archives
 .Nd functions for reading streaming archives
 .\"
 .\"
+.Sh LIBRARY
+Streaming Archive Library (libarchive, -larchive)
 .Sh SYNOPSIS
 .Sh SYNOPSIS
 .In archive.h
 .In archive.h
 .Ft int
 .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
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\" 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
 .Dt ARCHIVE_READ_FORMAT 3
 .Os
 .Os
 .Sh NAME
 .Sh NAME
@@ -45,6 +45,8 @@
 .Nm archive_read_support_format_zip
 .Nm archive_read_support_format_zip
 .Nd functions for reading streaming archives
 .Nd functions for reading streaming archives
 .\"
 .\"
+.Sh LIBRARY
+Streaming Archive Library (libarchive, -larchive)
 .Sh SYNOPSIS
 .Sh SYNOPSIS
 .In archive.h
 .In archive.h
 .Ft int
 .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
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\" 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
 .Dt ARCHIVE_READ_FREE 3
 .Os
 .Os
 .Sh NAME
 .Sh NAME
@@ -32,6 +32,8 @@
 .Nm archive_read_finish ,
 .Nm archive_read_finish ,
 .Nm archive_read_free
 .Nm archive_read_free
 .Nd functions for reading streaming archives
 .Nd functions for reading streaming archives
+.Sh LIBRARY
+Streaming Archive Library (libarchive, -larchive)
 .Sh SYNOPSIS
 .Sh SYNOPSIS
 .In archive.h
 .In archive.h
 .Ft int
 .Ft int

+ 3 - 1
Utilities/cmlibarchive/libarchive/archive_read_header.3

@@ -24,13 +24,15 @@
 .\"
 .\"
 .\" $FreeBSD$
 .\" $FreeBSD$
 .\"
 .\"
-.Dd March 22, 2011
+.Dd February 2, 2012
 .Dt ARCHIVE_READ_HEADER 3
 .Dt ARCHIVE_READ_HEADER 3
 .Os
 .Os
 .Sh NAME
 .Sh NAME
 .Nm archive_read_next_header ,
 .Nm archive_read_next_header ,
 .Nm archive_read_next_header2
 .Nm archive_read_next_header2
 .Nd functions for reading streaming archives
 .Nd functions for reading streaming archives
+.Sh LIBRARY
+Streaming Archive Library (libarchive, -larchive)
 .Sh SYNOPSIS
 .Sh SYNOPSIS
 .In archive.h
 .In archive.h
 .Ft int
 .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
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\" 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
 .Dt ARCHIVE_READ_NEW 3
 .Os
 .Os
 .Sh NAME
 .Sh NAME
 .Nm archive_read_new
 .Nm archive_read_new
 .Nd functions for reading streaming archives
 .Nd functions for reading streaming archives
+.Sh LIBRARY
+Streaming Archive Library (libarchive, -larchive)
 .Sh SYNOPSIS
 .Sh SYNOPSIS
 .In archive.h
 .In archive.h
 .Ft struct archive *
 .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
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\" 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
 .Dt ARCHIVE_READ_OPEN 3
 .Os
 .Os
 .Sh NAME
 .Sh NAME
@@ -35,6 +35,8 @@
 .Nm archive_read_open_filename ,
 .Nm archive_read_open_filename ,
 .Nm archive_read_open_memory ,
 .Nm archive_read_open_memory ,
 .Nd functions for reading streaming archives
 .Nd functions for reading streaming archives
+.Sh LIBRARY
+Streaming Archive Library (libarchive, -larchive)
 .Sh SYNOPSIS
 .Sh SYNOPSIS
 .In archive.h
 .In archive.h
 .Ft int
 .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 (bytes_read < 0) {
 			if (errno == EINTR)
 			if (errno == EINTR)
 				continue;
 				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);
 		return (bytes_read);
 	}
 	}
@@ -129,8 +130,8 @@ static int64_t
 file_skip(struct archive *a, void *client_data, int64_t request)
 file_skip(struct archive *a, void *client_data, int64_t request)
 {
 {
 	struct read_fd_data *mine = (struct read_fd_data *)client_data;
 	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. */
 	int skip_bits = sizeof(skip) * 8 - 1;  /* off_t is a signed type. */
 
 
 	if (!mine->use_lseek)
 	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)
 file_read(struct archive *a, void *client_data, const void **buff)
 {
 {
 	struct read_FILE_data *mine = (struct read_FILE_data *)client_data;
 	struct read_FILE_data *mine = (struct read_FILE_data *)client_data;
-	ssize_t bytes_read;
+	size_t bytes_read;
 
 
 	*buff = mine->buffer;
 	*buff = mine->buffer;
 	bytes_read = fread(mine->buffer, 1, mine->block_size, mine->f);
 	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");
 		archive_set_error(a, errno, "Error reading file");
 	}
 	}
 	return (bytes_read);
 	return (bytes_read);

+ 120 - 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
 #endif
 
 
 #include "archive.h"
 #include "archive.h"
+#include "archive_private.h"
 #include "archive_string.h"
 #include "archive_string.h"
 
 
 #ifndef O_BINARY
 #ifndef O_BINARY
 #define O_BINARY 0
 #define O_BINARY 0
 #endif
 #endif
+#ifndef O_CLOEXEC
+#define O_CLOEXEC	0
+#endif
 
 
 struct read_file_data {
 struct read_file_data {
 	int	 fd;
 	int	 fd;
@@ -79,9 +83,10 @@ struct read_file_data {
 	} filename; /* Must be last! */
 	} filename; /* Must be last! */
 };
 };
 
 
+static int	file_open(struct archive *, void *);
 static int	file_close(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 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_seek(struct archive *, void *, int64_t request, int);
 static int64_t	file_skip(struct archive *, void *, int64_t request);
 static int64_t	file_skip(struct archive *, void *, int64_t request);
@@ -98,26 +103,76 @@ int
 archive_read_open_filename(struct archive *a, const char *filename,
 archive_read_open_filename(struct archive *a, const char *filename,
     size_t block_size)
     size_t block_size)
 {
 {
-	enum fnt_e filename_type;
+	const char *filenames[2] = { filename, NULL };
+	return archive_read_open_filenames(a, filenames, block_size);
+}
+
+int
+archive_read_open_filenames(struct archive *a, const char **filenames,
+    size_t block_size)
+{
+	struct read_file_data *mine;
+	const char *filename = NULL;
+	if (filenames)
+		filename = *(filenames++);
+
+	archive_clear_error(a);
+	do
+	{
+		if (filename == NULL)
+			filename = "";
+		mine = (struct read_file_data *)calloc(1,
+			sizeof(*mine) + strlen(filename));
+		if (mine == NULL)
+			goto no_memory;
+		strcpy(mine->filename.m, filename);
+		mine->block_size = block_size;
+		mine->fd = -1;
+		mine->buffer = NULL;
+		mine->st_mode = mine->use_lseek = 0;
+		if (filename == NULL || filename[0] == '\0') {
+			mine->filename_type = FNT_STDIN;
+		} else
+			mine->filename_type = FNT_MBS;
+		if (archive_read_append_callback_data(a, mine) != (ARCHIVE_OK))
+			return (ARCHIVE_FATAL);
+		if (filenames == NULL)
+			break;
+		filename = *(filenames++);
+	} while (filename != NULL && filename[0] != '\0');
+	archive_read_set_open_callback(a, file_open);
+	archive_read_set_read_callback(a, file_read);
+	archive_read_set_skip_callback(a, file_skip);
+	archive_read_set_close_callback(a, file_close);
+	archive_read_set_switch_callback(a, file_switch);
+	archive_read_set_seek_callback(a, file_seek);
 
 
-	if (filename == NULL || filename[0] == '\0') {
-		filename_type = FNT_STDIN;
-	} else
-		filename_type = FNT_MBS;
-	return (file_open_filename(a, filename_type, filename, block_size));
+	return (archive_read_open1(a));
+no_memory:
+	archive_set_error(a, ENOMEM, "No memory");
+	return (ARCHIVE_FATAL);
 }
 }
 
 
 int
 int
 archive_read_open_filename_w(struct archive *a, const wchar_t *wfilename,
 archive_read_open_filename_w(struct archive *a, const wchar_t *wfilename,
     size_t block_size)
     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') {
 	if (wfilename == NULL || wfilename[0] == L'\0') {
-		filename_type = FNT_STDIN;
+		mine->filename_type = FNT_STDIN;
 	} else {
 	} else {
 #if defined(_WIN32) && !defined(__CYGWIN__)
 #if defined(_WIN32) && !defined(__CYGWIN__)
-		filename_type = FNT_WCS;
+		mine->filename_type = FNT_WCS;
+		wcscpy(mine->filename.w, wfilename);
 #else
 #else
 		/*
 		/*
 		 * POSIX system does not support a wchar_t interface for
 		 * POSIX system does not support a wchar_t interface for
@@ -125,31 +180,43 @@ archive_read_open_filename_w(struct archive *a, const wchar_t *wfilename,
 		 * filename to multi-byte one and use it.
 		 * filename to multi-byte one and use it.
 		 */
 		 */
 		struct archive_string fn;
 		struct archive_string fn;
-		int r;
 
 
 		archive_string_init(&fn);
 		archive_string_init(&fn);
 		if (archive_string_append_from_wcs(&fn, wfilename,
 		if (archive_string_append_from_wcs(&fn, wfilename,
 		    wcslen(wfilename)) != 0) {
 		    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);
 			archive_string_free(&fn);
+			free(mine);
 			return (ARCHIVE_FATAL);
 			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);
 		archive_string_free(&fn);
-		return (r);
 #endif
 #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
 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 stat st;
-	struct read_file_data *mine;
+	struct read_file_data *mine = (struct read_file_data *)client_data;
 	void *buffer;
 	void *buffer;
 	const char *filename = NULL;
 	const char *filename = NULL;
 	const wchar_t *wfilename = NULL;
 	const wchar_t *wfilename = NULL;
@@ -164,7 +231,7 @@ file_open_filename(struct archive *a, enum fnt_e filename_type,
 #endif
 #endif
 
 
 	archive_clear_error(a);
 	archive_clear_error(a);
-	if (filename_type == FNT_STDIN) {
+	if (mine->filename_type == FNT_STDIN) {
 		/* We used to delegate stdin support by
 		/* We used to delegate stdin support by
 		 * directly calling archive_read_open_fd(a,0,block_size)
 		 * directly calling archive_read_open_fd(a,0,block_size)
 		 * here, but that doesn't (and shouldn't) handle the
 		 * here, but that doesn't (and shouldn't) handle the
@@ -179,9 +246,10 @@ file_open_filename(struct archive *a, enum fnt_e filename_type,
 		setmode(0, O_BINARY);
 		setmode(0, O_BINARY);
 #endif
 #endif
 		filename = "";
 		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) {
 		if (fd < 0) {
 			archive_set_error(a, errno,
 			archive_set_error(a, errno,
 			    "Failed to open '%s'", filename);
 			    "Failed to open '%s'", filename);
@@ -189,7 +257,7 @@ file_open_filename(struct archive *a, enum fnt_e filename_type,
 		}
 		}
 	} else {
 	} else {
 #if defined(_WIN32) && !defined(__CYGWIN__)
 #if defined(_WIN32) && !defined(__CYGWIN__)
-		wfilename = (const wchar_t *)_filename;
+		wfilename = mine->filename.w;
 		fd = _wopen(wfilename, O_RDONLY | O_BINARY);
 		fd = _wopen(wfilename, O_RDONLY | O_BINARY);
 		if (fd < 0 && errno == ENOENT) {
 		if (fd < 0 && errno == ENOENT) {
 			wchar_t *fullpath;
 			wchar_t *fullpath;
@@ -211,7 +279,7 @@ file_open_filename(struct archive *a, enum fnt_e filename_type,
 #endif
 #endif
 	}
 	}
 	if (fstat(fd, &st) != 0) {
 	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'",
 			archive_set_error(a, errno, "Can't stat '%S'",
 			    wfilename);
 			    wfilename);
 		else
 		else
@@ -276,50 +344,32 @@ file_open_filename(struct archive *a, enum fnt_e filename_type,
 #endif
 #endif
 	/* TODO: Add an "is_tape_like" variable and appropriate tests. */
 	/* 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.  */
 	/* Disk-like devices prefer power-of-two block sizes.  */
 	/* Use provided block_size as a guide so users have some control. */
 	/* Use provided block_size as a guide so users have some control. */
 	if (is_disk_like) {
 	if (is_disk_like) {
 		size_t new_block_size = 64 * 1024;
 		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 < 64 * 1024 * 1024)
 			new_block_size *= 2;
 			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) {
 	if (mine == NULL || buffer == NULL) {
 		archive_set_error(a, ENOMEM, "No memory");
 		archive_set_error(a, ENOMEM, "No memory");
 		free(mine);
 		free(mine);
 		free(buffer);
 		free(buffer);
 		return (ARCHIVE_FATAL);
 		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->buffer = buffer;
 	mine->fd = fd;
 	mine->fd = fd;
 	/* Remember mode so close can decide whether to flush. */
 	/* Remember mode so close can decide whether to flush. */
 	mine->st_mode = st.st_mode;
 	mine->st_mode = st.st_mode;
 
 
 	/* Disk-like inputs can use lseek(). */
 	/* 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;
 		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
 static ssize_t
@@ -397,9 +447,7 @@ file_skip_lseek(struct archive *a, void *client_data, int64_t request)
 	/* TODO: Deal with case where off_t isn't 64 bits.
 	/* TODO: Deal with case where off_t isn't 64 bits.
 	 * This shouldn't be a problem on Linux or other POSIX
 	 * This shouldn't be a problem on Linux or other POSIX
 	 * systems, since the configuration logic for libarchive
 	 * 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 &&
 	if ((old_offset = lseek(mine->fd, 0, SEEK_CUR)) >= 0 &&
 	    (new_offset = lseek(mine->fd, request, SEEK_CUR)) >= 0)
 	    (new_offset = lseek(mine->fd, request, SEEK_CUR)) >= 0)
@@ -450,7 +498,7 @@ static int64_t
 file_seek(struct archive *a, void *client_data, int64_t request, int whence)
 file_seek(struct archive *a, void *client_data, int64_t request, int whence)
 {
 {
 	struct read_file_data *mine = (struct read_file_data *)client_data;
 	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. */
 	/* We use off_t here because lseek() is declared that way. */
 	/* See above for notes about when off_t is less than 64 bits. */
 	/* See above for notes about when off_t is less than 64 bits. */
@@ -471,7 +519,7 @@ file_seek(struct archive *a, void *client_data, int64_t request, int whence)
 }
 }
 
 
 static int
 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;
 	struct read_file_data *mine = (struct read_file_data *)client_data;
 
 
@@ -504,6 +552,23 @@ file_close(struct archive *a, void *client_data)
 			close(mine->fd);
 			close(mine->fd);
 	}
 	}
 	free(mine->buffer);
 	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);
 	free(mine);
 	return (ARCHIVE_OK);
 	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;
 	struct read_memory_data *mine = (struct read_memory_data *)client_data;
 
 
+	(void)a; /* UNUSED */
 	switch (whence) {
 	switch (whence) {
 	case SEEK_SET:
 	case SEEK_SET:
 		mine->p = mine->start + offset;
 		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 {
 struct archive_read_filter_bidder {
 	/* Configuration data for the bidder. */
 	/* Configuration data for the bidder. */
 	void *data;
 	void *data;
+	/* Name of the filter */
+	const char *name;
 	/* Taste the upstream filter to see if we handle this. */
 	/* Taste the upstream filter to see if we handle this. */
 	int (*bid)(struct archive_read_filter_bidder *,
 	int (*bid)(struct archive_read_filter_bidder *,
 	    struct archive_read_filter *);
 	    struct archive_read_filter *);
@@ -82,6 +84,8 @@ struct archive_read_filter {
 	struct archive_read_filter_bidder *bidder; /* My bidder. */
 	struct archive_read_filter_bidder *bidder; /* My bidder. */
 	struct archive_read_filter *upstream; /* Who I read from. */
 	struct archive_read_filter *upstream; /* Who I read from. */
 	struct archive_read *archive; /* Associated archive. */
 	struct archive_read *archive; /* Associated archive. */
+	/* Open a block for reading */
+	int (*open)(struct archive_read_filter *self);
 	/* Return next block. */
 	/* Return next block. */
 	ssize_t (*read)(struct archive_read_filter *, const void **);
 	ssize_t (*read)(struct archive_read_filter *, const void **);
 	/* Skip forward this many bytes. */
 	/* 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);
 	int64_t (*seek)(struct archive_read_filter *self, int64_t offset, int whence);
 	/* Close (just this filter) and free(self). */
 	/* Close (just this filter) and free(self). */
 	int (*close)(struct archive_read_filter *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. */
 	/* My private data. */
 	void *data;
 	void *data;
 
 
@@ -118,13 +124,22 @@ struct archive_read_filter {
  * transformation filters.  This will probably break the API/ABI and
  * transformation filters.  This will probably break the API/ABI and
  * so should be deferred at least until libarchive 3.0.
  * 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 {
 struct archive_read_client {
 	archive_open_callback	*opener;
 	archive_open_callback	*opener;
 	archive_read_callback	*reader;
 	archive_read_callback	*reader;
 	archive_skip_callback	*skipper;
 	archive_skip_callback	*skipper;
 	archive_seek_callback	*seeker;
 	archive_seek_callback	*seeker;
 	archive_close_callback	*closer;
 	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 {
 struct archive_read {
@@ -134,8 +149,8 @@ struct archive_read {
 
 
 	/* Dev/ino of the archive being read/written. */
 	/* Dev/ino of the archive being read/written. */
 	int		  skip_file_set;
 	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
 	 * Used by archive_read_data() to track blocks and copy
@@ -146,18 +161,33 @@ struct archive_read {
 	int64_t		  read_data_output_offset;
 	int64_t		  read_data_output_offset;
 	size_t		  read_data_remaining;
 	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;
 	struct archive_read_client client;
 
 
 	/* Registered filter bidders. */
 	/* Registered filter bidders. */
-	struct archive_read_filter_bidder bidders[9];
+	struct archive_read_filter_bidder bidders[14];
 
 
 	/* Last filter in chain */
 	/* Last filter in chain */
 	struct archive_read_filter *filter;
 	struct archive_read_filter *filter;
 
 
+	/* Whether to bypass filter bidding process */
+	int bypass_filter_bidding;
+
 	/* File offset of beginning of most recently-read header. */
 	/* File offset of beginning of most recently-read header. */
 	int64_t		  header_position;
 	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
 	 * Format detection is mostly the same as compression
 	 * detection, with one significant difference: The bidders
 	 * 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_header)(struct archive_read *, struct archive_entry *);
 		int	(*read_data)(struct archive_read *, const void **, size_t *, int64_t *);
 		int	(*read_data)(struct archive_read *, const void **, size_t *, int64_t *);
 		int	(*read_data_skip)(struct archive_read *);
 		int	(*read_data_skip)(struct archive_read *);
+		int64_t	(*seek_data)(struct archive_read *, int64_t, int);
 		int	(*cleanup)(struct archive_read *);
 		int	(*cleanup)(struct archive_read *);
 	}	formats[16];
 	}	formats[16];
 	struct archive_format_descriptor	*format; /* Active format. */
 	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_header)(struct archive_read *, struct archive_entry *),
 	    int (*read_data)(struct archive_read *, const void **, size_t *, int64_t *),
 	    int (*read_data)(struct archive_read *, const void **, size_t *, int64_t *),
 	    int (*read_data_skip)(struct archive_read *),
 	    int (*read_data_skip)(struct archive_read *),
+	    int64_t (*seek_data)(struct archive_read *, int64_t, int),
 	    int (*cleanup)(struct archive_read *));
 	    int (*cleanup)(struct archive_read *));
 
 
 int __archive_read_get_bidder(struct archive_read *a,
 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_consume(struct archive_read *, int64_t);
 int64_t	__archive_read_filter_consume(struct archive_read_filter *, int64_t);
 int64_t	__archive_read_filter_consume(struct archive_read_filter *, int64_t);
 int __archive_read_program(struct archive_read_filter *, const char *);
 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
 #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$
 .\" $FreeBSD$
 .\"
 .\"
-.Dd April 13, 2009
+.Dd February 2, 2012
 .Dt ARCHIVE_READ_OPTIONS 3
 .Dt ARCHIVE_READ_OPTIONS 3
 .Os
 .Os
 .Sh NAME
 .Sh NAME
@@ -34,6 +34,8 @@
 .Nm archive_read_set_options
 .Nm archive_read_set_options
 .Nd functions controlling options for reading archives
 .Nd functions controlling options for reading archives
 .\"
 .\"
+.Sh LIBRARY
+Streaming Archive Library (libarchive, -larchive)
 .Sh SYNOPSIS
 .Sh SYNOPSIS
 .Ft int
 .Ft int
 .Fo archive_read_set_filter_option
 .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_read *a = (struct archive_read *)_a;
 	struct archive_format_descriptor *format;
 	struct archive_format_descriptor *format;
 	size_t i;
 	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++) {
 	for (i = 0; i < sizeof(a->formats)/sizeof(a->formats[0]); i++) {
 		format = &a->formats[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)
 		if (r == ARCHIVE_OK)
 			rv = 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);
 	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 *a = (struct archive_read *)_a;
 	struct archive_read_filter *filter;
 	struct archive_read_filter *filter;
 	struct archive_read_filter_bidder *bidder;
 	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) {
 	for (filter = a->filter; filter != NULL; filter = filter->upstream) {
 		bidder = filter->bidder;
 		bidder = filter->bidder;
@@ -135,6 +139,10 @@ archive_set_filter_option(struct archive *_a, const char *m, const char *o,
 		if (r == ARCHIVE_OK)
 		if (r == ARCHIVE_OK)
 			rv = 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);
 	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);
 	archive_read_support_filter_bzip2(a);
 	/* The decompress code doesn't use an outside library. */
 	/* The decompress code doesn't use an outside library. */
 	archive_read_support_filter_compress(a);
 	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);
 	archive_read_support_filter_gzip(a);
 	/* Lzip falls back to "unlzip" command-line program. */
 	/* Lzip falls back to "unlzip" command-line program. */
 	archive_read_support_filter_lzip(a);
 	archive_read_support_filter_lzip(a);
@@ -63,6 +63,12 @@ archive_read_support_filter_all(struct archive *a)
 	archive_read_support_filter_uu(a);
 	archive_read_support_filter_uu(a);
 	/* The decode code doesn't use an outside library. */
 	/* The decode code doesn't use an outside library. */
 	archive_read_support_filter_rpm(a);
 	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
 	/* Note: We always return ARCHIVE_OK here, even if some of the
 	 * above return ARCHIVE_WARN.  The intent here is to enable
 	 * 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);
 		return (ARCHIVE_FATAL);
 
 
 	reader->data = NULL;
 	reader->data = NULL;
+	reader->name = "bzip2";
 	reader->bid = bzip2_reader_bid;
 	reader->bid = bzip2_reader_bid;
 	reader->init = bzip2_reader_init;
 	reader->init = bzip2_reader_init;
 	reader->options = NULL;
 	reader->options = NULL;
@@ -102,7 +103,7 @@ archive_read_support_filter_bzip2(struct archive *_a)
 	return (ARCHIVE_OK);
 	return (ARCHIVE_OK);
 #else
 #else
 	archive_set_error(_a, ARCHIVE_ERRNO_MISC,
 	archive_set_error(_a, ARCHIVE_ERRNO_MISC,
-	    "Using external bunzip2 program");
+	    "Using external bzip2 program");
 	return (ARCHIVE_WARN);
 	return (ARCHIVE_WARN);
 #endif
 #endif
 }
 }
@@ -170,11 +171,11 @@ bzip2_reader_init(struct archive_read_filter *self)
 {
 {
 	int r;
 	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()
 	/* Note: We set the format here even if __archive_read_program()
 	 * above fails.  We do, after all, know what the format is
 	 * above fails.  We do, after all, know what the format is
 	 * even if we weren't able to read it. */
 	 * even if we weren't able to read it. */
-	self->code = ARCHIVE_COMPRESSION_BZIP2;
+	self->code = ARCHIVE_FILTER_BZIP2;
 	self->name = "bzip2";
 	self->name = "bzip2";
 	return (r);
 	return (r);
 }
 }
@@ -192,7 +193,7 @@ bzip2_reader_init(struct archive_read_filter *self)
 	void *out_block;
 	void *out_block;
 	struct private_data *state;
 	struct private_data *state;
 
 
-	self->code = ARCHIVE_COMPRESSION_BZIP2;
+	self->code = ARCHIVE_FILTER_BZIP2;
 	self->name = "bzip2";
 	self->name = "bzip2";
 
 
 	state = (struct private_data *)calloc(sizeof(*state), 1);
 	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);
 		return (ARCHIVE_FATAL);
 
 
 	bidder->data = NULL;
 	bidder->data = NULL;
+	bidder->name = "compress (.Z)";
 	bidder->bid = compress_bidder_bid;
 	bidder->bid = compress_bidder_bid;
 	bidder->init = compress_bidder_init;
 	bidder->init = compress_bidder_init;
 	bidder->options = NULL;
 	bidder->options = NULL;
@@ -212,7 +213,7 @@ compress_bidder_init(struct archive_read_filter *self)
 	void *out_block;
 	void *out_block;
 	int code;
 	int code;
 
 
-	self->code = ARCHIVE_COMPRESSION_COMPRESS;
+	self->code = ARCHIVE_FILTER_COMPRESS;
 	self->name = "compress (.Z)";
 	self->name = "compress (.Z)";
 
 
 	state = (struct private_data *)calloc(sizeof(*state), 1);
 	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
  * TODO: If zlib is unavailable, gzip_bidder_init() should
  * use the compress_program framework to try to fire up an external
  * 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 *,
 static int	gzip_bidder_bid(struct archive_read_filter_bidder *,
 		    struct archive_read_filter *);
 		    struct archive_read_filter *);
@@ -100,6 +100,7 @@ archive_read_support_filter_gzip(struct archive *_a)
 		return (ARCHIVE_FATAL);
 		return (ARCHIVE_FATAL);
 
 
 	bidder->data = NULL;
 	bidder->data = NULL;
+	bidder->name = "gzip";
 	bidder->bid = gzip_bidder_bid;
 	bidder->bid = gzip_bidder_bid;
 	bidder->init = gzip_bidder_init;
 	bidder->init = gzip_bidder_init;
 	bidder->options = NULL;
 	bidder->options = NULL;
@@ -109,7 +110,7 @@ archive_read_support_filter_gzip(struct archive *_a)
 	return (ARCHIVE_OK);
 	return (ARCHIVE_OK);
 #else
 #else
 	archive_set_error(_a, ARCHIVE_ERRNO_MISC,
 	archive_set_error(_a, ARCHIVE_ERRNO_MISC,
-	    "Using external gunzip program");
+	    "Using external gzip program");
 	return (ARCHIVE_WARN);
 	return (ARCHIVE_WARN);
 #endif
 #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
  * number of bytes in header.  If pbits is non-NULL, it receives a
  * count of bits verified, suitable for use by bidder.
  * count of bits verified, suitable for use by bidder.
  */
  */
-static int
+static ssize_t
 peek_at_header(struct archive_read_filter *filter, int *pbits)
 peek_at_header(struct archive_read_filter *filter, int *pbits)
 {
 {
 	const unsigned char *p;
 	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
  * 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.
  * in case that's available.
  */
  */
 static int
 static int
@@ -231,11 +232,11 @@ gzip_bidder_init(struct archive_read_filter *self)
 {
 {
 	int r;
 	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()
 	/* Note: We set the format here even if __archive_read_program()
 	 * above fails.  We do, after all, know what the format is
 	 * above fails.  We do, after all, know what the format is
 	 * even if we weren't able to read it. */
 	 * even if we weren't able to read it. */
-	self->code = ARCHIVE_COMPRESSION_GZIP;
+	self->code = ARCHIVE_FILTER_GZIP;
 	self->name = "gzip";
 	self->name = "gzip";
 	return (r);
 	return (r);
 }
 }
@@ -252,7 +253,7 @@ gzip_bidder_init(struct archive_read_filter *self)
 	static const size_t out_block_size = 64 * 1024;
 	static const size_t out_block_size = 64 * 1024;
 	void *out_block;
 	void *out_block;
 
 
-	self->code = ARCHIVE_COMPRESSION_GZIP;
+	self->code = ARCHIVE_FILTER_GZIP;
 	self->name = "gzip";
 	self->name = "gzip";
 
 
 	state = (struct private_data *)calloc(sizeof(*state), 1);
 	state = (struct private_data *)calloc(sizeof(*state), 1);
@@ -299,7 +300,7 @@ consume_header(struct archive_read_filter *self)
 	/* Initialize compression library. */
 	/* Initialize compression library. */
 	state->stream.next_in = (unsigned char *)(uintptr_t)
 	state->stream.next_in = (unsigned char *)(uintptr_t)
 	    __archive_read_filter_ahead(self->upstream, 1, &avail);
 	    __archive_read_filter_ahead(self->upstream, 1, &avail);
-	state->stream.avail_in = avail;
+	state->stream.avail_in = (uInt)avail;
 	ret = inflateInit2(&(state->stream),
 	ret = inflateInit2(&(state->stream),
 	    -15 /* Don't check for zlib header */);
 	    -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. */
 	/* Empty our output buffer. */
 	state->stream.next_out = state->out_block;
 	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. */
 	/* Try to fill the output buffer. */
 	while (state->stream.avail_out > 0 && !state->eof) {
 	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");
 			    "truncated gzip input");
 			return (ARCHIVE_FATAL);
 			return (ARCHIVE_FATAL);
 		}
 		}
-		state->stream.avail_in = avail_in;
+		state->stream.avail_in = (uInt)avail_in;
 
 
 		/* Decompress and consume some of that data. */
 		/* Decompress and consume some of that data. */
 		ret = inflate(&(state->stream), 0);
 		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 <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) 2007 Joerg Sonnenberger
+ * Copyright (c) 2012 Michihiro NAKAJIMA
  * All rights reserved.
  * All rights reserved.
  *
  *
  * Redistribution and use in source and binary forms, with or without
  * Redistribution and use in source and binary forms, with or without
@@ -53,7 +54,9 @@ __FBSDID("$FreeBSD$");
 
 
 #include "archive.h"
 #include "archive.h"
 #include "archive_private.h"
 #include "archive_private.h"
+#include "archive_string.h"
 #include "archive_read_private.h"
 #include "archive_read_private.h"
+#include "filter_fork.h"
 
 
 
 
 #if ARCHIVE_VERSION_NUMBER < 4000000
 #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));
 	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 bidder object stores the command and the signature to watch for.
  * The 'inhibit' entry here is used to ensure that unchecked filters never
  * The 'inhibit' entry here is used to ensure that unchecked filters never
  * bid twice in the same pipeline.
  * bid twice in the same pipeline.
  */
  */
 struct program_bidder {
 struct program_bidder {
+	char *description;
 	char *cmd;
 	char *cmd;
 	void *signature;
 	void *signature;
 	size_t signature_len;
 	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.
  * The actual filter needs to track input and output data.
  */
  */
 struct program_filter {
 struct program_filter {
-	char		*description;
+	struct archive_string description;
+#if defined(_WIN32) && !defined(__CYGWIN__)
+	HANDLE		 child;
+#else
 	pid_t		 child;
 	pid_t		 child;
+#endif
 	int		 exit_status;
 	int		 exit_status;
 	int		 waitpid_return;
 	int		 waitpid_return;
 	int		 child_stdin, child_stdout;
 	int		 child_stdin, child_stdout;
@@ -151,6 +121,29 @@ struct program_filter {
 static ssize_t	program_filter_read(struct archive_read_filter *,
 static ssize_t	program_filter_read(struct archive_read_filter *,
 		    const void **);
 		    const void **);
 static int	program_filter_close(struct archive_read_filter *);
 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
 int
 archive_read_support_filter_program_signature(struct archive *_a,
 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.
 	 * Allocate our private state.
 	 */
 	 */
-	state = (struct program_bidder *)calloc(sizeof (*state), 1);
+	state = (struct program_bidder *)calloc(1, sizeof (*state));
 	if (state == NULL)
 	if (state == NULL)
-		return (ARCHIVE_FATAL);
+		goto memerr;
 	state->cmd = strdup(cmd);
 	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
 static int
 program_bidder_free(struct archive_read_filter_bidder *self)
 program_bidder_free(struct archive_read_filter_bidder *self)
 {
 {
 	struct program_bidder *state = (struct program_bidder *)self->data;
 	struct program_bidder *state = (struct program_bidder *)self->data;
-	free(state->cmd);
-	free(state->signature);
-	free(self->data);
+
+	free_state(state);
 	return (ARCHIVE_OK);
 	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.
  * 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
 			state->waitpid_return
 			    = waitpid(state->child, &state->exit_status, 0);
 			    = waitpid(state->child, &state->exit_status, 0);
 		} while (state->waitpid_return == -1 && errno == EINTR);
 		} while (state->waitpid_return == -1 && errno == EINTR);
+#if defined(_WIN32) && !defined(__CYGWIN__)
+		CloseHandle(state->child);
+#endif
 		state->child = 0;
 		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;
 	struct program_filter *state = self->data;
 	ssize_t ret, requested, avail;
 	ssize_t ret, requested, avail;
 	const char *p;
 	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;
 	requested = buf_len > SSIZE_MAX ? SSIZE_MAX : buf_len;
 
 
 	for (;;) {
 	for (;;) {
 		do {
 		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);
 			ret = read(state->child_stdout, buf, requested);
 		} while (ret == -1 && errno == EINTR);
 		} while (ret == -1 && errno == EINTR);
 
 
@@ -376,38 +399,57 @@ __archive_read_program(struct archive_read_filter *self, const char *cmd)
 	struct program_filter	*state;
 	struct program_filter	*state;
 	static const size_t out_buf_len = 65536;
 	static const size_t out_buf_len = 65536;
 	char *out_buf;
 	char *out_buf;
-	char *description;
 	const char *prefix = "Program: ";
 	const char *prefix = "Program: ";
+	pid_t child;
+	size_t l;
 
 
+	l = strlen(prefix) + strlen(cmd) + 1;
 	state = (struct program_filter *)calloc(1, sizeof(*state));
 	state = (struct program_filter *)calloc(1, sizeof(*state));
 	out_buf = (char *)malloc(out_buf_len);
 	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,
 		archive_set_error(&self->archive->archive, ENOMEM,
 		    "Can't allocate input data");
 		    "Can't allocate input data");
-		free(state);
+		if (state != NULL) {
+			archive_string_free(&state->description);
+			free(state);
+		}
 		free(out_buf);
 		free(out_buf);
-		free(description);
 		return (ARCHIVE_FATAL);
 		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 = out_buf;
 	state->out_buf_len = out_buf_len;
 	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->out_buf);
 		free(state);
 		free(state);
 		archive_set_error(&self->archive->archive, EINVAL,
 		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);
 		return (ARCHIVE_FATAL);
 	}
 	}
+#else
+	state->child = child;
+#endif
 
 
 	self->data = state;
 	self->data = state;
 	self->read = program_filter_read;
 	self->read = program_filter_read;
@@ -467,10 +509,8 @@ program_filter_close(struct archive_read_filter *self)
 
 
 	/* Release our private data. */
 	/* Release our private data. */
 	free(state->out_buf);
 	free(state->out_buf);
-	free(state->description);
+	archive_string_free(&state->description);
 	free(state);
 	free(state);
 
 
 	return (e);
 	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);
 		return (ARCHIVE_FATAL);
 
 
 	bidder->data = NULL;
 	bidder->data = NULL;
+	bidder->name = "rpm";
 	bidder->bid = rpm_bidder_bid;
 	bidder->bid = rpm_bidder_bid;
 	bidder->init = rpm_bidder_init;
 	bidder->init = rpm_bidder_init;
 	bidder->options = NULL;
 	bidder->options = NULL;
@@ -137,7 +138,7 @@ rpm_bidder_init(struct archive_read_filter *self)
 {
 {
 	struct rpm   *rpm;
 	struct rpm   *rpm;
 
 
-	self->code = ARCHIVE_COMPRESSION_RPM;
+	self->code = ARCHIVE_FILTER_RPM;
 	self->name = "rpm";
 	self->name = "rpm";
 	self->read = rpm_filter_read;
 	self->read = rpm_filter_read;
 	self->skip = NULL; /* not supported */
 	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)
 			if (rpm->total_in + avail_in < RPM_LEAD_SIZE)
 				used += avail_in;
 				used += avail_in;
 			else {
 			else {
-				n = RPM_LEAD_SIZE - rpm->total_in;
+				n = (size_t)(RPM_LEAD_SIZE - rpm->total_in);
 				used += n;
 				used += n;
 				b += n;
 				b += n;
 				rpm->state = ST_HEADER;
 				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_READ_UU	1
 #define ST_UUEND	2
 #define ST_UUEND	2
 #define ST_READ_BASE64	3
 #define ST_READ_BASE64	3
+#define ST_IGNORE	4
 };
 };
 
 
 static int	uudecode_bidder_bid(struct archive_read_filter_bidder *,
 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);
 		return (ARCHIVE_FATAL);
 
 
 	bidder->data = NULL;
 	bidder->data = NULL;
+	bidder->name = "uu";
 	bidder->bid = uudecode_bidder_bid;
 	bidder->bid = uudecode_bidder_bid;
 	bidder->init = uudecode_bidder_init;
 	bidder->init = uudecode_bidder_init;
 	bidder->options = NULL;
 	bidder->options = NULL;
@@ -377,7 +379,7 @@ uudecode_bidder_init(struct archive_read_filter *self)
 	void *out_buff;
 	void *out_buff;
 	void *in_buff;
 	void *in_buff;
 
 
-	self->code = ARCHIVE_COMPRESSION_UU;
+	self->code = ARCHIVE_FILTER_UU;
 	self->name = "uu";
 	self->name = "uu";
 	self->read = uudecode_filter_read;
 	self->read = uudecode_filter_read;
 	self->skip = NULL; /* not supported */
 	self->skip = NULL; /* not supported */
@@ -470,6 +472,10 @@ read_more:
 	total = 0;
 	total = 0;
 	out = uudecode->out_buff;
 	out = uudecode->out_buff;
 	ravail = avail_in;
 	ravail = avail_in;
+	if (uudecode->state == ST_IGNORE) {
+		used = avail_in;
+		goto finish;
+	}
 	if (uudecode->in_cnt) {
 	if (uudecode->in_cnt) {
 		/*
 		/*
 		 * If there is remaining data which is saved by
 		 * If there is remaining data which is saved by
@@ -485,12 +491,18 @@ read_more:
 		uudecode->in_cnt = 0;
 		uudecode->in_cnt = 0;
 	}
 	}
 	for (;used < avail_in; d += llen, used += llen) {
 	for (;used < avail_in; d += llen, used += llen) {
-		int l, body;
+		int64_t l, body;
 
 
 		b = d;
 		b = d;
 		len = get_line(b, avail_in - used, &nl);
 		len = get_line(b, avail_in - used, &nl);
 		if (len < 0) {
 		if (len < 0) {
 			/* Non-ascii character is found. */
 			/* 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_set_error(&self->archive->archive,
 			    ARCHIVE_ERRNO_MISC,
 			    ARCHIVE_ERRNO_MISC,
 			    "Insufficient compressed data");
 			    "Insufficient compressed data");
@@ -507,7 +519,7 @@ read_more:
 				return (ARCHIVE_FATAL);
 				return (ARCHIVE_FATAL);
 			if (uudecode->in_buff != b)
 			if (uudecode->in_buff != b)
 				memmove(uudecode->in_buff, b, len);
 				memmove(uudecode->in_buff, b, len);
-			uudecode->in_cnt = len;
+			uudecode->in_cnt = (int)len;
 			if (total == 0) {
 			if (total == 0) {
 				/* Do not return 0; it means end-of-file.
 				/* Do not return 0; it means end-of-file.
 				 * We should try to read bytes more. */
 				 * We should try to read bytes more. */
@@ -545,7 +557,7 @@ read_more:
 			break;
 			break;
 		case ST_READ_UU:
 		case ST_READ_UU:
 			if (total + len * 2 > OUT_BUFF_SIZE)
 			if (total + len * 2 > OUT_BUFF_SIZE)
-				break;
+				goto finish;
 			body = len - nl;
 			body = len - nl;
 			if (!uuchar[*b] || body <= 0) {
 			if (!uuchar[*b] || body <= 0) {
 				archive_set_error(&self->archive->archive,
 				archive_set_error(&self->archive->archive,
@@ -611,7 +623,7 @@ read_more:
 			break;
 			break;
 		case ST_READ_BASE64:
 		case ST_READ_BASE64:
 			if (total + len * 2 > OUT_BUFF_SIZE)
 			if (total + len * 2 > OUT_BUFF_SIZE)
-				break;
+				goto finish;
 			l = len - nl;
 			l = len - nl;
 			if (l >= 3 && b[0] == '=' && b[1] == '=' &&
 			if (l >= 3 && b[0] == '=' && b[1] == '=' &&
 			    b[2] == '=') {
 			    b[2] == '=') {
@@ -657,8 +669,10 @@ read_more:
 			break;
 			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;
 	*buff = uudecode->out_buff;
 	uudecode->total += total;
 	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);
 		return (ARCHIVE_FATAL);
 
 
 	bidder->data = NULL;
 	bidder->data = NULL;
+	bidder->name = "xz";
 	bidder->bid = xz_bidder_bid;
 	bidder->bid = xz_bidder_bid;
 	bidder->init = xz_bidder_init;
 	bidder->init = xz_bidder_init;
 	bidder->options = NULL;
 	bidder->options = NULL;
@@ -144,7 +145,7 @@ archive_read_support_filter_xz(struct archive *_a)
 	return (ARCHIVE_OK);
 	return (ARCHIVE_OK);
 #else
 #else
 	archive_set_error(_a, ARCHIVE_ERRNO_MISC,
 	archive_set_error(_a, ARCHIVE_ERRNO_MISC,
-	    "Using external unxz program for xz decompression");
+	    "Using external xz program for xz decompression");
 	return (ARCHIVE_WARN);
 	return (ARCHIVE_WARN);
 #endif
 #endif
 }
 }
@@ -170,6 +171,7 @@ archive_read_support_filter_lzma(struct archive *_a)
 		return (ARCHIVE_FATAL);
 		return (ARCHIVE_FATAL);
 
 
 	bidder->data = NULL;
 	bidder->data = NULL;
+	bidder->name = "lzma";
 	bidder->bid = lzma_bidder_bid;
 	bidder->bid = lzma_bidder_bid;
 	bidder->init = lzma_bidder_init;
 	bidder->init = lzma_bidder_init;
 	bidder->options = NULL;
 	bidder->options = NULL;
@@ -180,7 +182,7 @@ archive_read_support_filter_lzma(struct archive *_a)
 	return (ARCHIVE_OK);
 	return (ARCHIVE_OK);
 #else
 #else
 	archive_set_error(_a, ARCHIVE_ERRNO_MISC,
 	archive_set_error(_a, ARCHIVE_ERRNO_MISC,
-	    "Using external unlzma program for lzma decompression");
+	    "Using external lzma program for lzma decompression");
 	return (ARCHIVE_WARN);
 	return (ARCHIVE_WARN);
 #endif
 #endif
 }
 }
@@ -207,6 +209,7 @@ archive_read_support_filter_lzip(struct archive *_a)
 		return (ARCHIVE_FATAL);
 		return (ARCHIVE_FATAL);
 
 
 	bidder->data = NULL;
 	bidder->data = NULL;
+	bidder->name = "lzip";
 	bidder->bid = lzip_bidder_bid;
 	bidder->bid = lzip_bidder_bid;
 	bidder->init = lzip_bidder_init;
 	bidder->init = lzip_bidder_init;
 	bidder->options = NULL;
 	bidder->options = NULL;
@@ -415,7 +418,7 @@ lzip_bidder_bid(struct archive_read_filter_bidder *self,
 static int
 static int
 xz_bidder_init(struct archive_read_filter *self)
 xz_bidder_init(struct archive_read_filter *self)
 {
 {
-	self->code = ARCHIVE_COMPRESSION_XZ;
+	self->code = ARCHIVE_FILTER_XZ;
 	self->name = "xz";
 	self->name = "xz";
 	return (xz_lzma_bidder_init(self));
 	return (xz_lzma_bidder_init(self));
 }
 }
@@ -423,7 +426,7 @@ xz_bidder_init(struct archive_read_filter *self)
 static int
 static int
 lzma_bidder_init(struct archive_read_filter *self)
 lzma_bidder_init(struct archive_read_filter *self)
 {
 {
-	self->code = ARCHIVE_COMPRESSION_LZMA;
+	self->code = ARCHIVE_FILTER_LZMA;
 	self->name = "lzma";
 	self->name = "lzma";
 	return (xz_lzma_bidder_init(self));
 	return (xz_lzma_bidder_init(self));
 }
 }
@@ -431,7 +434,7 @@ lzma_bidder_init(struct archive_read_filter *self)
 static int
 static int
 lzip_bidder_init(struct archive_read_filter *self)
 lzip_bidder_init(struct archive_read_filter *self)
 {
 {
-	self->code = ARCHIVE_COMPRESSION_LZIP;
+	self->code = ARCHIVE_FILTER_LZIP;
 	self->name = "lzip";
 	self->name = "lzip";
 	return (xz_lzma_bidder_init(self));
 	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->stream.avail_out = state->out_block_size;
 
 
 	state->crc32 = 0;
 	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
 		 * We have to read a lzip header and use it to initialize
 		 * compression library, thus we cannot initialize the
 		 * compression library, thus we cannot initialize the
@@ -530,7 +533,7 @@ xz_lzma_bidder_init(struct archive_read_filter *self)
 		state->in_stream = 1;
 		state->in_stream = 1;
 
 
 	/* Initialize compression library. */
 	/* Initialize compression library. */
-	if (self->code == ARCHIVE_COMPRESSION_XZ)
+	if (self->code == ARCHIVE_FILTER_XZ)
 		ret = lzma_stream_decoder(&(state->stream),
 		ret = lzma_stream_decoder(&(state->stream),
 		    LZMA_MEMLIMIT,/* memlimit */
 		    LZMA_MEMLIMIT,/* memlimit */
 		    LZMA_CONCATENATED);
 		    LZMA_CONCATENATED);
@@ -730,7 +733,7 @@ xz_filter_read(struct archive_read_filter *self, const void **p)
 		*p = NULL;
 		*p = NULL;
 	else {
 	else {
 		*p = state->out_block;
 		*p = state->out_block;
-		if (self->code == ARCHIVE_COMPRESSION_LZIP) {
+		if (self->code == ARCHIVE_FILTER_LZIP) {
 			state->crc32 = lzma_crc32(state->out_block,
 			state->crc32 = lzma_crc32(state->out_block,
 			    decompressed, state->crc32);
 			    decompressed, state->crc32);
 			if (state->eof) {
 			if (state->eof) {
@@ -778,7 +781,7 @@ lzma_bidder_init(struct archive_read_filter *self)
 	struct private_data *state;
 	struct private_data *state;
 	ssize_t ret, avail_in;
 	ssize_t ret, avail_in;
 
 
-	self->code = ARCHIVE_COMPRESSION_LZMA;
+	self->code = ARCHIVE_FILTER_LZMA;
 	self->name = "lzma";
 	self->name = "lzma";
 
 
 	state = (struct private_data *)calloc(sizeof(*state), 1);
 	state = (struct private_data *)calloc(sizeof(*state), 1);
@@ -941,11 +944,11 @@ lzma_bidder_init(struct archive_read_filter *self)
 {
 {
 	int r;
 	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()
 	/* Note: We set the format here even if __archive_read_program()
 	 * above fails.  We do, after all, know what the format is
 	 * above fails.  We do, after all, know what the format is
 	 * even if we weren't able to read it. */
 	 * even if we weren't able to read it. */
-	self->code = ARCHIVE_COMPRESSION_LZMA;
+	self->code = ARCHIVE_FILTER_LZMA;
 	self->name = "lzma";
 	self->name = "lzma";
 	return (r);
 	return (r);
 }
 }
@@ -958,11 +961,11 @@ xz_bidder_init(struct archive_read_filter *self)
 {
 {
 	int r;
 	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()
 	/* Note: We set the format here even if __archive_read_program()
 	 * above fails.  We do, after all, know what the format is
 	 * above fails.  We do, after all, know what the format is
 	 * even if we weren't able to read it. */
 	 * even if we weren't able to read it. */
-	self->code = ARCHIVE_COMPRESSION_XZ;
+	self->code = ARCHIVE_FILTER_XZ;
 	self->name = "xz";
 	self->name = "xz";
 	return (r);
 	return (r);
 }
 }
@@ -972,11 +975,11 @@ lzip_bidder_init(struct archive_read_filter *self)
 {
 {
 	int r;
 	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()
 	/* Note: We set the format here even if __archive_read_program()
 	 * above fails.  We do, after all, know what the format is
 	 * above fails.  We do, after all, know what the format is
 	 * even if we weren't able to read it. */
 	 * even if we weren't able to read it. */
-	self->code = ARCHIVE_COMPRESSION_LZIP;
+	self->code = ARCHIVE_FILTER_LZIP;
 	self->name = "lzip";
 	self->name = "lzip";
 	return (r);
 	return (r);
 }
 }

+ 151 - 109
Utilities/cmlibarchive/libarchive/archive_read_support_format_7zip.c

@@ -318,7 +318,7 @@ struct _7zip {
 	uint32_t		 bcj2_code;
 	uint32_t		 bcj2_code;
 	uint64_t		 bcj2_outPos;
 	uint64_t		 bcj2_outPos;
 
 
-	/* Filename character-set convertion data. */
+	/* Filename character-set conversion data. */
 	struct archive_string_conv *sconv;
 	struct archive_string_conv *sconv;
 
 
 	char			 format_name[64];
 	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_header,
 	    archive_read_format_7zip_read_data,
 	    archive_read_format_7zip_read_data,
 	    archive_read_format_7zip_read_data_skip,
 	    archive_read_format_7zip_read_data_skip,
+	    NULL,
 	    archive_read_format_7zip_cleanup);
 	    archive_read_format_7zip_cleanup);
 
 
 	if (r != ARCHIVE_OK)
 	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
 		 * Magic Code, so we should do this in order not to
 		 * make a mis-detection.
 		 * 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))
 			!= archive_le32dec(p + 8))
 			return (6); 
 			return (6); 
 		/* Hit the header! */
 		/* Hit the header! */
@@ -580,7 +581,7 @@ archive_read_format_7zip_read_header(struct archive_read *a,
 		free_Header(&header);
 		free_Header(&header);
 		if (r != ARCHIVE_OK)
 		if (r != ARCHIVE_OK)
 			return (r);
 			return (r);
-		zip->entries_remaining = zip->numFiles;
+		zip->entries_remaining = (size_t)zip->numFiles;
 		zip->entry = zip->entries;
 		zip->entry = zip->entries;
 	} else {
 	} else {
 		++zip->entry;
 		++zip->entry;
@@ -630,7 +631,7 @@ archive_read_format_7zip_read_header(struct archive_read *a,
 	if (zip_entry->flg & ATIME_IS_SET)
 	if (zip_entry->flg & ATIME_IS_SET)
 		archive_entry_set_atime(entry, zip_entry->atime,
 		archive_entry_set_atime(entry, zip_entry->atime,
 		    zip_entry->atime_ns);
 		    zip_entry->atime_ns);
-	if (zip_entry->ssIndex != -1) {
+	if (zip_entry->ssIndex != (uint32_t)-1) {
 		zip->entry_bytes_remaining =
 		zip->entry_bytes_remaining =
 		    zip->si.ss.unpackSizes[zip_entry->ssIndex];
 		    zip->si.ss.unpackSizes[zip_entry->ssIndex];
 		archive_entry_set_size(entry, zip->entry_bytes_remaining);
 		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) {
 	if ((zip_entry->mode & AE_IFMT) == AE_IFLNK) {
 		unsigned char *symname = NULL;
 		unsigned char *symname = NULL;
 		size_t symsize = 0;
 		size_t symsize = 0;
-		int r;
 
 
 		/*
 		/*
 		 * Symbolic-name is recorded as its contents. We have to
 		 * 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) {
 		while (zip->entry_bytes_remaining > 0) {
 			const void *buff;
 			const void *buff;
+			unsigned char *mem;
 			size_t size;
 			size_t size;
 			int64_t offset;
 			int64_t offset;
 
 
 			r = archive_read_format_7zip_read_data(a, &buff,
 			r = archive_read_format_7zip_read_data(a, &buff,
 				&size, &offset);
 				&size, &offset);
-			if (r < ARCHIVE_WARN)
+			if (r < ARCHIVE_WARN) {
+				free(symname);
 				return (r);
 				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,
 				archive_set_error(&a->archive, ENOMEM,
 				    "Can't allocate memory for Symname");
 				    "Can't allocate memory for Symname");
 				return (ARCHIVE_FATAL);
 				return (ARCHIVE_FATAL);
 			}
 			}
+			symname = mem;
 			memcpy(symname+symsize, buff, size);
 			memcpy(symname+symsize, buff, size);
 			symsize += size;
 			symsize += size;
 		}
 		}
@@ -680,8 +685,8 @@ archive_read_format_7zip_read_header(struct archive_read *a,
 			symname[symsize] = '\0';
 			symname[symsize] = '\0';
 			archive_entry_copy_symlink(entry,
 			archive_entry_copy_symlink(entry,
 			    (const char *)symname);
 			    (const char *)symname);
-			free(symname);
 		}
 		}
+		free(symname);
 		archive_entry_set_size(entry, 0);
 		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)
 	if (zip->pack_stream_bytes_unconsumed)
 		read_consume(a);
 		read_consume(a);
 
 
+	*offset = zip->entry_offset;
+	*size = 0;
+	*buff = NULL;
 	/*
 	/*
 	 * If we hit end-of-entry last time, clean up and return
 	 * If we hit end-of-entry last time, clean up and return
 	 * ARCHIVE_EOF this time.
 	 * 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);
 		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)
 	if (bytes < 0)
 		return ((int)bytes);
 		return ((int)bytes);
 	if (bytes == 0) {
 	if (bytes == 0) {
@@ -731,7 +736,8 @@ archive_read_format_7zip_read_data(struct archive_read *a,
 
 
 	/* Update checksum */
 	/* Update checksum */
 	if ((zip->entry->flg & CRC32_IS_SET) && bytes)
 	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 we hit the end, swallow any end-of-data marker. */
 	if (zip->end_of_entry) {
 	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
 	 * If the length is at the beginning, we can skip the
 	 * compressed data much more quickly.
 	 * 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)
 	if (bytes_skipped < 0)
 		return (ARCHIVE_FATAL);
 		return (ARCHIVE_FATAL);
 	zip->entry_bytes_remaining = 0;
 	zip->entry_bytes_remaining = 0;
@@ -1054,7 +1060,7 @@ init_decompression(struct archive_read *a, struct _7zip *zip,
 		ff = &filters[fi];
 		ff = &filters[fi];
 #endif
 #endif
 		r = lzma_properties_decode(&filters[fi], NULL,
 		r = lzma_properties_decode(&filters[fi], NULL,
-		    coder1->properties, coder1->propertiesSize);
+		    coder1->properties, (size_t)coder1->propertiesSize);
 		if (r != LZMA_OK) {
 		if (r != LZMA_OK) {
 			set_error(a, r);
 			set_error(a, r);
 			return (ARCHIVE_FAILED);
 			return (ARCHIVE_FAILED);
@@ -1358,9 +1364,9 @@ decompress(struct archive_read *a, struct _7zip *zip,
 #ifdef HAVE_ZLIB_H
 #ifdef HAVE_ZLIB_H
 	case _7Z_DEFLATE:
 	case _7Z_DEFLATE:
 		zip->stream.next_in = (Bytef *)(uintptr_t)t_next_in;
 		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.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);
 		r = inflate(&(zip->stream), 0);
 		switch (r) {
 		switch (r) {
 		case Z_STREAM_END: /* Found end of stream. */
 		case Z_STREAM_END: /* Found end of stream. */
@@ -1382,7 +1388,7 @@ decompress(struct archive_read *a, struct _7zip *zip,
 		uint64_t flush_bytes;
 		uint64_t flush_bytes;
 
 
 		if (!zip->ppmd7_valid || zip->ppmd7_stat < 0 ||
 		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_set_error(&(a->archive),
 			    ARCHIVE_ERRNO_MISC,
 			    ARCHIVE_ERRNO_MISC,
 			    "Decompression internal error");
 			    "Decompression internal error");
@@ -1442,8 +1448,8 @@ decompress(struct archive_read *a, struct _7zip *zip,
 		} while (zip->ppstream.avail_out &&
 		} while (zip->ppstream.avail_out &&
 			(zip->ppstream.avail_in || flush_bytes));
 			(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;
 		break;
 	}
 	}
 	default:
 	default:
@@ -1506,6 +1512,10 @@ free_decompression(struct archive_read *a, struct _7zip *zip)
 {
 {
 	int r = ARCHIVE_OK;
 	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
 #ifdef HAVE_LZMA_H
 	if (zip->lzstream_valid)
 	if (zip->lzstream_valid)
 		lzma_end(&(zip->lzstream));
 		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;
 	const unsigned char *p;
 	unsigned i;
 	unsigned i;
 
 
+	if (num == 0)
+		return (-1);
 	memset(d, 0, sizeof(*d));
 	memset(d, 0, sizeof(*d));
 
 
-
 	d->defineds = malloc(num);
 	d->defineds = malloc(num);
 	if (d->defineds == NULL)
 	if (d->defineds == NULL)
 		return (-1);
 		return (-1);
@@ -1672,8 +1683,8 @@ read_PackInfo(struct archive_read *a, struct _7z_pack_info *pi)
 		return (0);
 		return (0);
 	if (*p != kSize)
 	if (*p != kSize)
 		return (-1);
 		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)
 	if (pi->sizes == NULL || pi->positions == NULL)
 		return (-1);
 		return (-1);
 
 
@@ -1690,9 +1701,9 @@ read_PackInfo(struct archive_read *a, struct _7z_pack_info *pi)
 	if (*p == kEnd) {
 	if (*p == kEnd) {
 		/* PackStreamDigests[num] are not present. */
 		/* PackStreamDigests[num] are not present. */
 		pi->digest.defineds =
 		pi->digest.defineds =
-		    calloc(pi->numPackStreams, sizeof(*pi->digest.defineds));
+		    calloc((size_t)pi->numPackStreams, sizeof(*pi->digest.defineds));
 		pi->digest.digests =
 		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)
 		if (pi->digest.defineds == NULL || pi->digest.digests == NULL)
 			return (-1);
 			return (-1);
 		return (0);
 		return (0);
@@ -1701,7 +1712,7 @@ read_PackInfo(struct archive_read *a, struct _7z_pack_info *pi)
 	if (*p != kSize)
 	if (*p != kSize)
 		return (-1);
 		return (-1);
 
 
-	if (read_Digests(a, &(pi->digest), pi->numPackStreams) < 0)
+	if (read_Digests(a, &(pi->digest), (size_t)pi->numPackStreams) < 0)
 		return (-1);
 		return (-1);
 
 
 	/*
 	/*
@@ -1750,7 +1761,7 @@ read_Folder(struct archive_read *a, struct _7z_folder *f)
 		/* Too many coders. */
 		/* Too many coders. */
 		return (-1);
 		return (-1);
 
 
-	f->coders = calloc(f->numCoders, sizeof(*f->coders));
+	f->coders = calloc((size_t)f->numCoders, sizeof(*f->coders));
 	if (f->coders == NULL)
 	if (f->coders == NULL)
 		return (-1);
 		return (-1);
 	for (i = 0; i< f->numCoders; i++) {
 	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)
 			    a, &(f->coders[i].propertiesSize)) < 0)
 				return (-1);
 				return (-1);
 			if ((p = header_bytes(
 			if ((p = header_bytes(
-			    a, f->coders[i].propertiesSize)) == NULL)
+			    a, (size_t)f->coders[i].propertiesSize)) == NULL)
 				return (-1);
 				return (-1);
 			f->coders[i].properties =
 			f->coders[i].properties =
-			    malloc(f->coders[i].propertiesSize);
+			    malloc((size_t)f->coders[i].propertiesSize);
 			if (f->coders[i].properties == NULL)
 			if (f->coders[i].properties == NULL)
 				return (-1);
 				return (-1);
 			memcpy(f->coders[i].properties, p,
 			memcpy(f->coders[i].properties, p,
-			    f->coders[i].propertiesSize);
+			    (size_t)f->coders[i].propertiesSize);
 		}
 		}
 
 
 		numInStreamsTotal += f->coders[i].numInStreams;
 		numInStreamsTotal += f->coders[i].numInStreams;
@@ -1823,9 +1834,13 @@ read_Folder(struct archive_read *a, struct _7z_folder *f)
 	f->numBindPairs = numOutStreamsTotal - 1;
 	f->numBindPairs = numOutStreamsTotal - 1;
 	if (zip->header_bytes_remaining < f->numBindPairs)
 	if (zip->header_bytes_remaining < f->numBindPairs)
 			return (-1);
 			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++) {
 	for (i = 0; i < f->numBindPairs; i++) {
 		if (parse_7zip_uint64(a, &(f->bindPairs[i].inIndex)) < 0)
 		if (parse_7zip_uint64(a, &(f->bindPairs[i].inIndex)) < 0)
 			return (-1);
 			return (-1);
@@ -1839,7 +1854,7 @@ read_Folder(struct archive_read *a, struct _7z_folder *f)
 
 
 	f->numPackedStreams = numInStreamsTotal - f->numBindPairs;
 	f->numPackedStreams = numInStreamsTotal - f->numBindPairs;
 	f->packedStreams =
 	f->packedStreams =
-	    calloc(f->numPackedStreams, sizeof(*f->packedStreams));
+	    calloc((size_t)f->numPackedStreams, sizeof(*f->packedStreams));
 	if (f->packedStreams == NULL)
 	if (f->packedStreams == NULL)
 		return (-1);
 		return (-1);
 	if (f->numPackedStreams == 1) {
 	if (f->numPackedStreams == 1) {
@@ -1911,7 +1926,8 @@ read_CodersInfo(struct archive_read *a, struct _7z_coders_info *ci)
 		goto failed;
 		goto failed;
 	switch (*p) {
 	switch (*p) {
 	case 0:
 	case 0:
-		ci->folders = calloc(ci->numFolders, sizeof(*ci->folders));
+		ci->folders =
+			calloc((size_t)ci->numFolders, sizeof(*ci->folders));
 		if (ci->folders == NULL)
 		if (ci->folders == NULL)
 			return (-1);
 			return (-1);
 		for (i = 0; i < ci->numFolders; i++) {
 		for (i = 0; i < ci->numFolders; i++) {
@@ -1937,7 +1953,7 @@ read_CodersInfo(struct archive_read *a, struct _7z_coders_info *ci)
 		unsigned j;
 		unsigned j;
 
 
 		folder->unPackSize =
 		folder->unPackSize =
-		    calloc(folder->numOutStreams, sizeof(*folder->unPackSize));
+		    calloc((size_t)folder->numOutStreams, sizeof(*folder->unPackSize));
 		if (folder->unPackSize == NULL)
 		if (folder->unPackSize == NULL)
 			goto failed;
 			goto failed;
 		for (j = 0; j < folder->numOutStreams; j++) {
 		for (j = 0; j < folder->numOutStreams; j++) {
@@ -1955,7 +1971,7 @@ read_CodersInfo(struct archive_read *a, struct _7z_coders_info *ci)
 		return (0);
 		return (0);
 	if (*p != kCRC)
 	if (*p != kCRC)
 		goto failed;
 		goto failed;
-	if (read_Digests(a, &digest, ci->numFolders) < 0)
+	if (read_Digests(a, &digest, (size_t)ci->numFolders) < 0)
 		goto failed;
 		goto failed;
 	for (i = 0; i < ci->numFolders; i++) {
 	for (i = 0; i < ci->numFolders; i++) {
 		ci->folders[i].digest_defined = digest.defineds[i];
 		ci->folders[i].digest_defined = digest.defineds[i];
@@ -1979,13 +1995,13 @@ failed:
 static uint64_t
 static uint64_t
 folder_uncompressed_size(struct _7z_folder *f)
 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) {
 	while (--n >= 0) {
 		unsigned i;
 		unsigned i;
 		for (i = 0; i < pairs; i++) {
 		for (i = 0; i < pairs; i++) {
-			if (f->bindPairs[i].outIndex == n)
+			if (f->bindPairs[i].outIndex == (uint64_t)n)
 				break;
 				break;
 		}
 		}
 		if (i >= pairs)
 		if (i >= pairs)
@@ -2029,7 +2045,7 @@ read_SubStreamsInfo(struct archive_read *a, struct _7z_substream_info *ss,
 				return (-1);
 				return (-1);
 			if (1000000 < f[i].numUnpackStreams)
 			if (1000000 < f[i].numUnpackStreams)
 				return (-1);
 				return (-1);
-			unpack_streams += f[i].numUnpackStreams;
+			unpack_streams += (size_t)f[i].numUnpackStreams;
 		}
 		}
 		if ((p = header_bytes(a, 1)) == NULL)
 		if ((p = header_bytes(a, 1)) == NULL)
 			return (-1);
 			return (-1);
@@ -2083,7 +2099,7 @@ read_SubStreamsInfo(struct archive_read *a, struct _7z_substream_info *ss,
 	numDigests = 0;
 	numDigests = 0;
 	for (i = 0; i < numFolders; i++) {
 	for (i = 0; i < numFolders; i++) {
 		if (f[i].numUnpackStreams != 1 || !f[i].digest_defined)
 		if (f[i].numUnpackStreams != 1 || !f[i].digest_defined)
-			numDigests += f[i].numUnpackStreams;
+			numDigests += (uint32_t)f[i].numUnpackStreams;
 	}
 	}
 
 
 	if (type == kCRC) {
 	if (type == kCRC) {
@@ -2181,7 +2197,7 @@ read_StreamsInfo(struct archive_read *a, struct _7z_stream_info *si)
 		f = si->ci.folders;
 		f = si->ci.folders;
 		for (i = 0; i < si->ci.numFolders; i++) {
 		for (i = 0; i < si->ci.numFolders; i++) {
 			f[i].packIndex = packIndex;
 			f[i].packIndex = packIndex;
-			packIndex += f[i].numPackedStreams;
+			packIndex += (uint32_t)f[i].numPackedStreams;
 			if (packIndex > si->pi.numPackStreams)
 			if (packIndex > si->pi.numPackStreams)
 				return (-1);
 				return (-1);
 		}
 		}
@@ -2191,7 +2207,7 @@ read_StreamsInfo(struct archive_read *a, struct _7z_stream_info *si)
 
 
 	if (*p == kSubStreamsInfo) {
 	if (*p == kSubStreamsInfo) {
 		if (read_SubStreamsInfo(a, &(si->ss),
 		if (read_SubStreamsInfo(a, &(si->ss),
-		    si->ci.folders, si->ci.numFolders) < 0)
+		    si->ci.folders, (size_t)si->ci.numFolders) < 0)
 			return (-1);
 			return (-1);
 		if ((p = header_bytes(a, 1)) == NULL)
 		if ((p = header_bytes(a, 1)) == NULL)
 			return (-1);
 			return (-1);
@@ -2279,7 +2295,7 @@ read_Header(struct archive_read *a, struct _7z_header_info *h,
 	if (1000000 < zip->numFiles)
 	if (1000000 < zip->numFiles)
 			return (-1);
 			return (-1);
 
 
-	zip->entries = calloc(zip->numFiles, sizeof(*zip->entries));
+	zip->entries = calloc((size_t)zip->numFiles, sizeof(*zip->entries));
 	if (zip->entries == NULL)
 	if (zip->entries == NULL)
 		return (-1);
 		return (-1);
 	entries = zip->entries;
 	entries = zip->entries;
@@ -2304,12 +2320,12 @@ read_Header(struct archive_read *a, struct _7z_header_info *h,
 
 
 		switch (type) {
 		switch (type) {
 		case kEmptyStream:
 		case kEmptyStream:
-			h->emptyStreamBools = calloc(zip->numFiles,
+			h->emptyStreamBools = calloc((size_t)zip->numFiles,
 			    sizeof(*h->emptyStreamBools));
 			    sizeof(*h->emptyStreamBools));
 			if (h->emptyStreamBools == NULL)
 			if (h->emptyStreamBools == NULL)
 				return (-1);
 				return (-1);
 			if (read_Bools(
 			if (read_Bools(
-			    a, h->emptyStreamBools, zip->numFiles) < 0)
+			    a, h->emptyStreamBools, (size_t)zip->numFiles) < 0)
 				return (-1);
 				return (-1);
 			empty_streams = 0;
 			empty_streams = 0;
 			for (i = 0; i < zip->numFiles; i++) {
 			for (i = 0; i < zip->numFiles; i++) {
@@ -2318,6 +2334,12 @@ read_Header(struct archive_read *a, struct _7z_header_info *h,
 			}
 			}
 			break;
 			break;
 		case kEmptyFile:
 		case kEmptyFile:
+			if (empty_streams <= 0) {
+				/* Unexcepted sequence. Skip this. */
+				if (header_bytes(a, ll) == NULL)
+					return (-1);
+				break;
+			}
 			h->emptyFileBools = calloc(empty_streams,
 			h->emptyFileBools = calloc(empty_streams,
 			    sizeof(*h->emptyFileBools));
 			    sizeof(*h->emptyFileBools));
 			if (h->emptyFileBools == NULL)
 			if (h->emptyFileBools == NULL)
@@ -2326,6 +2348,12 @@ read_Header(struct archive_read *a, struct _7z_header_info *h,
 				return (-1);
 				return (-1);
 			break;
 			break;
 		case kAnti:
 		case kAnti:
+			if (empty_streams <= 0) {
+				/* Unexcepted sequence. Skip this. */
+				if (header_bytes(a, ll) == NULL)
+					return (-1);
+				break;
+			}
 			h->antiBools = calloc(empty_streams,
 			h->antiBools = calloc(empty_streams,
 			    sizeof(*h->antiBools));
 			    sizeof(*h->antiBools));
 			if (h->antiBools == NULL)
 			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)
 			if ((p = header_bytes(a, 2)) == NULL)
 				return (-1);
 				return (-1);
 			allAreDefined = *p;
 			allAreDefined = *p;
-			h->attrBools = calloc(zip->numFiles,
+			h->attrBools = calloc((size_t)zip->numFiles,
 			    sizeof(*h->attrBools));
 			    sizeof(*h->attrBools));
 			if (h->attrBools == NULL)
 			if (h->attrBools == NULL)
 				return (-1);
 				return (-1);
 			if (allAreDefined)
 			if (allAreDefined)
-				memset(h->attrBools, 1, zip->numFiles);
+				memset(h->attrBools, 1, (size_t)zip->numFiles);
 			else {
 			else {
 				if (read_Bools(a, h->attrBools,
 				if (read_Bools(a, h->attrBools,
-				      zip->numFiles) < 0)
+				      (size_t)zip->numFiles) < 0)
 					return (-1);
 					return (-1);
 			}
 			}
 			for (i = 0; i < zip->numFiles; i++) {
 			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)
 			if ((size_t)sindex >= si->ss.unpack_streams)
 				return (-1);
 				return (-1);
 			if (entries[i].mode == 0)
 			if (entries[i].mode == 0)
-				entries[i].mode = AE_IFREG | 0777;
+				entries[i].mode = AE_IFREG | 0666;
 			if (si->ss.digestsDefined[sindex])
 			if (si->ss.digestsDefined[sindex])
 				entries[i].flg |= CRC32_IS_SET;
 				entries[i].flg |= CRC32_IS_SET;
 			entries[i].ssIndex = sindex;
 			entries[i].ssIndex = sindex;
@@ -2466,7 +2494,7 @@ read_Header(struct archive_read *a, struct _7z_header_info *h,
 				if (dir)
 				if (dir)
 					entries[i].mode = AE_IFDIR | 0777;
 					entries[i].mode = AE_IFDIR | 0777;
 				else
 				else
-					entries[i].mode = AE_IFREG | 0777;
+					entries[i].mode = AE_IFREG | 0666;
 			} else if (dir &&
 			} else if (dir &&
 			    (entries[i].mode & AE_IFMT) != AE_IFDIR) {
 			    (entries[i].mode & AE_IFMT) != AE_IFDIR) {
 				entries[i].mode &= ~AE_IFMT;
 				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)
 #define EPOC_TIME ARCHIVE_LITERAL_ULL(116444736000000000)
 static void
 static void
-fileTimeToUtc(uint64_t fileTime, time_t *time, long *ns)
+fileTimeToUtc(uint64_t fileTime, time_t *timep, long *ns)
 {
 {
 
 
 	if (fileTime >= EPOC_TIME) {
 	if (fileTime >= EPOC_TIME) {
 		fileTime -= EPOC_TIME;
 		fileTime -= EPOC_TIME;
 		/* milli seconds base */
 		/* milli seconds base */
-		*time = (time_t)(fileTime / 10000000);
+		*timep = (time_t)(fileTime / 10000000);
 		/* nano seconds base */
 		/* nano seconds base */
 		*ns = (long)(fileTime % 10000000) * 100;
 		*ns = (long)(fileTime % 10000000) * 100;
 	} else {
 	} else {
-		*time = 0;
+		*timep = 0;
 		*ns = 0;
 		*ns = 0;
 	}
 	}
 }
 }
@@ -2542,7 +2570,7 @@ read_Times(struct archive_read *a, struct _7z_header_info *h, int type)
 	int allAreDefined;
 	int allAreDefined;
 	unsigned i;
 	unsigned i;
 
 
-	timeBools = calloc(zip->numFiles, sizeof(*timeBools));
+	timeBools = calloc((size_t)zip->numFiles, sizeof(*timeBools));
 	if (timeBools == NULL)
 	if (timeBools == NULL)
 		return (-1);
 		return (-1);
 
 
@@ -2551,9 +2579,9 @@ read_Times(struct archive_read *a, struct _7z_header_info *h, int type)
 		goto failed;
 		goto failed;
 	allAreDefined = *p;
 	allAreDefined = *p;
 	if (allAreDefined)
 	if (allAreDefined)
-		memset(timeBools, 1, zip->numFiles);
+		memset(timeBools, 1, (size_t)zip->numFiles);
 	else {
 	else {
-		if (read_Bools(a, timeBools, zip->numFiles) < 0)
+		if (read_Bools(a, timeBools, (size_t)zip->numFiles) < 0)
 			goto failed;
 			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)
 		if (parse_7zip_uint64(a, &(h->dataIndex)) < 0)
 			goto failed;
 			goto failed;
 		if (1000000 < h->dataIndex)
 		if (1000000 < h->dataIndex)
-			return (-1);
+			goto failed;
 	}
 	}
 
 
 	for (i = 0; i < zip->numFiles; i++) {
 	for (i = 0; i < zip->numFiles; i++) {
@@ -2661,7 +2689,7 @@ header_bytes(struct archive_read *a, size_t rbytes)
 	}
 	}
 
 
 	/* Update checksum */
 	/* Update checksum */
-	zip->header_crc32 = crc32(zip->header_crc32, p, rbytes);
+	zip->header_crc32 = crc32(zip->header_crc32, p, (unsigned)rbytes);
 	return (p);
 	return (p);
 }
 }
 
 
@@ -2695,7 +2723,8 @@ slurp_central_directory(struct archive_read *a, struct _7zip *zip,
 	}
 	}
 
 
 	/* CRC check. */
 	/* 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");
 		archive_set_error(&a->archive, -1, "Header CRC error");
 		return (ARCHIVE_FATAL);
 		return (ARCHIVE_FATAL);
 	}
 	}
@@ -2714,7 +2743,7 @@ slurp_central_directory(struct archive_read *a, struct _7zip *zip,
 	}
 	}
 	__archive_read_consume(a, 32);
 	__archive_read_consume(a, 32);
 	if (next_header_offset != 0) {
 	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);
 			__archive_read_consume(a, next_header_offset);
 		else if (__archive_read_seek(a,
 		else if (__archive_read_seek(a,
 		    next_header_offset + zip->seek_base, SEEK_SET) < 0)
 		    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;
 	struct _7zip *zip = (struct _7zip *)a->format->data;
 	ssize_t bytes_avail;
 	ssize_t bytes_avail;
 
 
-	if (zip->codec == _7Z_COPY && zip->codec2 == -1) {
+	if (zip->codec == _7Z_COPY && zip->codec2 == (unsigned long)-1) {
 		/* Copy mode. */
 		/* Copy mode. */
 
 
 		/*
 		/*
@@ -2886,7 +2915,7 @@ extract_pack_stream(struct archive_read *a, size_t minimum)
 	ssize_t bytes_avail;
 	ssize_t bytes_avail;
 	int r;
 	int r;
 
 
-	if (zip->codec == _7Z_COPY && zip->codec2 == -1) {
+	if (zip->codec == _7Z_COPY && zip->codec2 == (unsigned long)-1) {
 		if (minimum == 0)
 		if (minimum == 0)
 			minimum = 1;
 			minimum = 1;
 		if (__archive_read_ahead(a, minimum, &bytes_avail) == NULL
 		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");
 			    "Truncated 7-Zip file body");
 			return (ARCHIVE_FATAL);
 			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;
 		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->folder_outbytes_remaining -= bytes_avail;
 		zip->uncompressed_buffer_bytes_remaining = bytes_avail;
 		zip->uncompressed_buffer_bytes_remaining = bytes_avail;
 		return (ARCHIVE_OK);
 		return (ARCHIVE_OK);
@@ -2939,16 +2968,19 @@ extract_pack_stream(struct archive_read *a, size_t minimum)
 			 * Expand the uncompressed buffer up to
 			 * Expand the uncompressed buffer up to
 			 * the minimum size.
 			 * 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,
 				archive_set_error(&a->archive, ENOMEM,
 				    "No memory for 7-Zip decompression");
 				    "No memory for 7-Zip decompression");
 				return (ARCHIVE_FATAL);
 				return (ARCHIVE_FATAL);
 			}
 			}
+			zip->uncompressed_buffer = (unsigned char *)p;
+			zip->uncompressed_buffer_size = new_size;
 		}
 		}
 		/*
 		/*
 		 * Move unconsumed bytes to the head.
 		 * 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;
 		size_t bytes_in, bytes_out;
 		const void *buff_in;
 		const void *buff_in;
 		unsigned char *buff_out;
 		unsigned char *buff_out;
-		int eof;
+		int end_of_data;
 
 
 		/*
 		/*
 		 * Note: '1' here is a performance optimization.
 		 * 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;
 			- zip->uncompressed_buffer_bytes_remaining;
 		bytes_in = bytes_avail;
 		bytes_in = bytes_avail;
 		if (bytes_in > zip->pack_stream_inbytes_remaining)
 		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. */
 		/* Drive decompression. */
 		r = decompress(a, zip, buff_out, &bytes_out,
 		r = decompress(a, zip, buff_out, &bytes_out,
 			buff_in, &bytes_in);
 			buff_in, &bytes_in);
 		switch (r) {
 		switch (r) {
 		case ARCHIVE_OK:
 		case ARCHIVE_OK:
-			eof = 0;
+			end_of_data = 0;
 			break;
 			break;
 		case ARCHIVE_EOF:
 		case ARCHIVE_EOF:
-			eof = 1;
+			end_of_data = 1;
 			break;
 			break;
 		default:
 		default:
 			return (ARCHIVE_FATAL);
 			return (ARCHIVE_FATAL);
 		}
 		}
 		zip->pack_stream_inbytes_remaining -= bytes_in;
 		zip->pack_stream_inbytes_remaining -= bytes_in;
 		if (bytes_out > zip->folder_outbytes_remaining)
 		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->folder_outbytes_remaining -= bytes_out;
 		zip->uncompressed_buffer_bytes_remaining += bytes_out;
 		zip->uncompressed_buffer_bytes_remaining += bytes_out;
 		zip->pack_stream_bytes_unconsumed = bytes_in;
 		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 &&
 		if (zip->pack_stream_inbytes_remaining == 0 &&
 		    zip->folder_outbytes_remaining == 0)
 		    zip->folder_outbytes_remaining == 0)
 			break;
 			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_set_error(&(a->archive),
 			    ARCHIVE_ERRNO_MISC, "Damaged 7-Zip archive");
 			    ARCHIVE_ERRNO_MISC, "Damaged 7-Zip archive");
 			return (ARCHIVE_FATAL);
 			return (ARCHIVE_FATAL);
@@ -3041,7 +3073,7 @@ static int
 seek_pack(struct archive_read *a)
 seek_pack(struct archive_read *a)
 {
 {
 	struct _7zip *zip = (struct _7zip *)a->format->data;
 	struct _7zip *zip = (struct _7zip *)a->format->data;
-	uint64_t pack_offset;
+	int64_t pack_offset;
 
 
 	if (zip->pack_stream_remaining <= 0) {
 	if (zip->pack_stream_remaining <= 0) {
 		archive_set_error(&(a->archive),
 		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;
 	struct _7zip *zip = (struct _7zip *)a->format->data;
 	uint64_t skip_bytes = 0;
 	uint64_t skip_bytes = 0;
-	int r;
+	ssize_t r;
 
 
 	if (zip->uncompressed_buffer_bytes_remaining == 0) {
 	if (zip->uncompressed_buffer_bytes_remaining == 0) {
 		if (zip->pack_stream_inbytes_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);
 				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)
 		if (skipped < 0)
 			return (skipped);
 			return (skipped);
 		skip_bytes -= skipped;
 		skip_bytes -= skipped;
@@ -3292,13 +3325,13 @@ setup_decode_folder(struct archive_read *a, struct _7z_folder *folder,
 			}
 			}
 			coder2 = &(fc[3]);
 			coder2 = &(fc[3]);
 			zip->main_stream_bytes_remaining =
 			zip->main_stream_bytes_remaining =
-				folder->unPackSize[2];
+				(size_t)folder->unPackSize[2];
 		} else if (coder2 != NULL && coder2->codec == _7Z_X86_BCJ2 &&
 		} else if (coder2 != NULL && coder2->codec == _7Z_X86_BCJ2 &&
 		    zip->pack_stream_remaining == 4 &&
 		    zip->pack_stream_remaining == 4 &&
 		    folder->numInStreams == 5 && folder->numOutStreams == 2) {
 		    folder->numInStreams == 5 && folder->numOutStreams == 2) {
 			/* Source type 0 made by 7z */
 			/* Source type 0 made by 7z */
 			zip->main_stream_bytes_remaining =
 			zip->main_stream_bytes_remaining =
-				folder->unPackSize[0];
+				(size_t)folder->unPackSize[0];
 		} else {
 		} else {
 			/* We got an unexpected form. */
 			/* We got an unexpected form. */
 			archive_set_error(&(a->archive),
 			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)
 		if ((r = seek_pack(a)) < 0)
 			return (r);
 			return (r);
 		zip->pack_stream_bytes_unconsumed =
 		zip->pack_stream_bytes_unconsumed =
-		    zip->pack_stream_inbytes_remaining;
+		    (size_t)zip->pack_stream_inbytes_remaining;
 		read_consume(a);
 		read_consume(a);
 
 
 		/* Read following three sub streams. */
 		/* Read following three sub streams. */
 		for (i = 0; i < 3; i++) {
 		for (i = 0; i < 3; i++) {
 			const struct _7z_coder *coder = scoder[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);
 				return (r);
+			}
 
 
-			if (sunpack[i] == -1)
+			if (sunpack[i] == (uint64_t)-1)
 				zip->folder_outbytes_remaining =
 				zip->folder_outbytes_remaining =
 				    zip->pack_stream_inbytes_remaining;
 				    zip->pack_stream_inbytes_remaining;
 			else
 			else
 				zip->folder_outbytes_remaining = sunpack[i];
 				zip->folder_outbytes_remaining = sunpack[i];
 
 
 			r = init_decompression(a, zip, coder, NULL);
 			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);
 				return (ARCHIVE_FATAL);
+			}
 
 
 			/* Allocate memory for the decorded data of a sub
 			/* Allocate memory for the decorded data of a sub
 			 * stream. */
 			 * stream. */
-			b[i] = malloc(zip->folder_outbytes_remaining);
+			b[i] = malloc((size_t)zip->folder_outbytes_remaining);
 			if (b[i] == NULL) {
 			if (b[i] == NULL) {
+				free(b[0]); free(b[1]); free(b[2]);
 				archive_set_error(&a->archive, ENOMEM,
 				archive_set_error(&a->archive, ENOMEM,
 				    "No memory for 7-Zip decompression");
 				    "No memory for 7-Zip decompression");
 				return (ARCHIVE_FATAL);
 				return (ARCHIVE_FATAL);
@@ -3342,14 +3380,18 @@ setup_decode_folder(struct archive_read *a, struct _7z_folder *folder,
 
 
 			/* Extract a sub stream. */
 			/* Extract a sub stream. */
 			while (zip->pack_stream_inbytes_remaining > 0) {
 			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);
 					return (r);
+				}
 				bytes = get_uncompressed_data(a, &buff,
 				bytes = get_uncompressed_data(a, &buff,
 				    zip->uncompressed_buffer_bytes_remaining,
 				    zip->uncompressed_buffer_bytes_remaining,
 				    0);
 				    0);
-				if (bytes < 0)
+				if (bytes < 0) {
+					free(b[0]); free(b[1]); free(b[2]);
 					return ((int)bytes);
 					return ((int)bytes);
+				}
 				memcpy(b[i]+s[i], buff, bytes);
 				memcpy(b[i]+s[i], buff, bytes);
 				s[i] += bytes;
 				s[i] += bytes;
 				if (zip->pack_stream_bytes_unconsumed)
 				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");
 			    "Truncated 7-Zip file body");
 			return (ARCHIVE_FATAL);
 			return (ARCHIVE_FATAL);
 		}
 		}
-		bytes -= skipped_bytes;
+		bytes -= (size_t)skipped_bytes;
 		if (zip->pack_stream_bytes_unconsumed)
 		if (zip->pack_stream_bytes_unconsumed)
 			read_consume(a);
 			read_consume(a);
 	}
 	}
@@ -3506,16 +3548,16 @@ x86_Convert(struct _7zip *zip, uint8_t *data, size_t size)
 			uint32_t dest;
 			uint32_t dest;
 			for (;;) {
 			for (;;) {
 				uint8_t b;
 				uint8_t b;
-				int index;
+				int b_index;
 
 
 				dest = src - (ip + (uint32_t)bufferPos);
 				dest = src - (ip + (uint32_t)bufferPos);
 				if (prevMask == 0)
 				if (prevMask == 0)
 					break;
 					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))
 				if (!Test86MSByte(b))
 					break;
 					break;
-				src = dest ^ ((1 << (32 - index)) - 1);
+				src = dest ^ ((1 << (32 - b_index)) - 1);
 			}
 			}
 			p[4] = (uint8_t)(~(((dest >> 24) & 1) - 1));
 			p[4] = (uint8_t)(~(((dest >> 24) & 1) - 1));
 			p[3] = (uint8_t)(dest >> 16);
 			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_prevPosT = prevPosT;
 	zip->bcj_prevMask = prevMask;
 	zip->bcj_prevMask = prevMask;
-	zip->bcj_ip += bufferPos;
+	zip->bcj_ip += (uint32_t)bufferPos;
 	return (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_READ_BYTE (*buffer++)
 #define RC_TEST { if (buffer == bufferLim) return SZ_ERROR_DATA; }
 #define RC_TEST { if (buffer == bufferLim) return SZ_ERROR_DATA; }
 #define RC_INIT2 zip->bcj2_code = 0; zip->bcj2_range = 0xFFFFFFFF; \
 #define RC_INIT2 zip->bcj2_code = 0; zip->bcj2_range = 0xFFFFFFFF; \
-  { int i; for (i = 0; i < 5; i++) { RC_TEST; zip->bcj2_code = (zip->bcj2_code << 8) | RC_READ_BYTE; }}
+  { int ii; for (ii = 0; ii < 5; ii++) { RC_TEST; zip->bcj2_code = (zip->bcj2_code << 8) | RC_READ_BYTE; }}
 
 
 #define NORMALIZE if (zip->bcj2_range < kTopValue) { RC_TEST; zip->bcj2_range <<= 8; zip->bcj2_code = (zip->bcj2_code << 8) | RC_READ_BYTE; }
 #define 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) {
 		if (zip->bcj_state == 1) {
 			while (limit != 0) {
 			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;
 					zip->bcj_state = 2;
 					break;
 					break;
 				}
 				}
 				inPos++;
 				inPos++;
-				zip->bcj2_prevByte = b;
+				zip->bcj2_prevByte = bb;
 				limit--;
 				limit--;
 			}
 			}
 		}
 		}
@@ -3673,7 +3715,7 @@ Bcj2_Decode(struct _7zip *zip, uint8_t *outBuf, size_t outSize)
 			    ((uint32_t)v[1] << 16) |
 			    ((uint32_t)v[1] << 16) |
 			    ((uint32_t)v[2] << 8) |
 			    ((uint32_t)v[2] << 8) |
 			    ((uint32_t)v[3])) -
 			    ((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[0] = (uint8_t)dest;
 			out[1] = (uint8_t)(dest >> 8);
 			out[1] = (uint8_t)(dest >> 8);
 			out[2] = (uint8_t)(dest >> 16);
 			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;
 				zip->odd_bcj_size = 4 -i;
 				for (; i < 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];
 					zip->odd_bcj[j] = out[i];
 				}
 				}
 				break;
 				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_header,
 	    archive_read_format_ar_read_data,
 	    archive_read_format_ar_read_data,
 	    archive_read_format_ar_skip,
 	    archive_read_format_ar_skip,
+	    NULL,
 	    archive_read_format_ar_cleanup);
 	    archive_read_format_ar_cleanup);
 
 
 	if (r != ARCHIVE_OK) {
 	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.
  * All rights reserved.
  *
  *
  * Redistribution and use in source and binary forms, with or without
  * Redistribution and use in source and binary forms, with or without
@@ -292,6 +292,8 @@ struct cab {
 	char			 end_of_archive;
 	char			 end_of_archive;
 	char			 end_of_entry;
 	char			 end_of_entry;
 	char			 end_of_entry_cleanup;
 	char			 end_of_entry_cleanup;
+	char			 read_data_invoked;
+	int64_t			 bytes_skipped;
 
 
 	unsigned char		*uncompressed_buffer;
 	unsigned char		*uncompressed_buffer;
 	size_t			 uncompressed_buffer_size;
 	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 int	lzx_huffman_init(struct huffman *, size_t, int);
 static void	lzx_huffman_free(struct huffman *);
 static void	lzx_huffman_free(struct huffman *);
 static int	lzx_make_huffman_table(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);
 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_header,
 	    archive_read_format_cab_read_data,
 	    archive_read_format_cab_read_data,
 	    archive_read_format_cab_read_data_skip,
 	    archive_read_format_cab_read_data_skip,
+	    NULL,
 	    archive_read_format_cab_cleanup);
 	    archive_read_format_cab_cleanup);
 
 
 	if (r != ARCHIVE_OK)
 	if (r != ARCHIVE_OK)
@@ -478,11 +481,13 @@ archive_read_format_cab_options(struct archive_read *a,
 			else
 			else
 				ret = ARCHIVE_FATAL;
 				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
 static int
@@ -535,7 +540,7 @@ truncated_error(struct archive_read *a)
 	return (ARCHIVE_FATAL);
 	return (ARCHIVE_FATAL);
 }
 }
 
 
-static int
+static ssize_t
 cab_strnlen(const unsigned char *p, size_t maxlen)
 cab_strnlen(const unsigned char *p, size_t maxlen)
 {
 {
 	size_t i;
 	size_t i;
@@ -546,7 +551,7 @@ cab_strnlen(const unsigned char *p, size_t maxlen)
 	}
 	}
 	if (i > maxlen)
 	if (i > maxlen)
 		return (-1);/* invalid */
 		return (-1);/* invalid */
-	return (i);
+	return ((ssize_t)i);
 }
 }
 
 
 /* Read bytes as much as remaining. */
 /* Read bytes as much as remaining. */
@@ -622,8 +627,9 @@ cab_read_header(struct archive_read *a)
 	struct cab *cab;
 	struct cab *cab;
 	struct cfheader *hd;
 	struct cfheader *hd;
 	size_t bytes, used;
 	size_t bytes, used;
+	ssize_t len;
 	int64_t skip;
 	int64_t skip;
-	int err, i, len;
+	int err, i;
 	int cur_folder, prev_folder;
 	int cur_folder, prev_folder;
 	uint32_t offset32;
 	uint32_t offset32;
 	
 	
@@ -796,7 +802,7 @@ cab_read_header(struct archive_read *a)
 		file->offset = archive_le32dec(p + CFFILE_uoffFolderStart);
 		file->offset = archive_le32dec(p + CFFILE_uoffFolderStart);
 		file->folder = archive_le16dec(p + CFFILE_iFolder);
 		file->folder = archive_le16dec(p + CFFILE_iFolder);
 		file->mtime = cab_dos_time(p + CFFILE_date_time);
 		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);
 		__archive_read_consume(a, 16);
 
 
 		cab->cab_offset += 16;
 		cab->cab_offset += 16;
@@ -986,7 +992,7 @@ archive_read_format_cab_read_header(struct archive_read *a,
 	if (file->attr & ATTR_RDONLY)
 	if (file->attr & ATTR_RDONLY)
 		archive_entry_set_mode(entry, AE_IFREG | 0555);
 		archive_entry_set_mode(entry, AE_IFREG | 0555);
 	else
 	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);
 	archive_entry_set_mtime(entry, file->mtime, 0);
 
 
 	cab->entry_bytes_remaining = file->uncompressed_size;
 	cab->entry_bytes_remaining = file->uncompressed_size;
@@ -1024,9 +1030,22 @@ archive_read_format_cab_read_data(struct archive_read *a,
 	default:
 	default:
 		break;
 		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) {
 	if (cab->entry_unconsumed) {
 		/* Consume as much as the compressor actually used. */
 		/* 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;
 		cab->entry_unconsumed = 0;
 		if (r < 0)
 		if (r < 0)
 			return (r);
 			return (r);
@@ -1049,13 +1068,13 @@ static uint32_t
 cab_checksum_cfdata_4(const void *p, size_t bytes, uint32_t seed)
 cab_checksum_cfdata_4(const void *p, size_t bytes, uint32_t seed)
 {
 {
 	const unsigned char *b;
 	const unsigned char *b;
-	int u32num;
+	unsigned u32num;
 	uint32_t sum;
 	uint32_t sum;
 
 
-	u32num = bytes / 4;
+	u32num = (unsigned)bytes / 4;
 	sum = seed;
 	sum = seed;
 	b = p;
 	b = p;
-	while (--u32num >= 0) {
+	for (;u32num > 0; --u32num) {
 		sum ^= archive_le32dec(b);
 		sum ^= archive_le32dec(b);
 		b += 4;
 		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 cab *cab = (struct cab *)(a->format->data);
 	struct cfdata *cfdata;
 	struct cfdata *cfdata;
 	const void *d;
 	const void *d;
-	int64_t skipped_bytes;
 
 
 	cfdata = cab->entry_cfdata;
 	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);
 	return (d);
 }
 }
 
 
@@ -1489,7 +1487,7 @@ cab_read_ahead_cfdata_deflate(struct archive_read *a, ssize_t *avail)
 		 * cast to remove 'const'.
 		 * cast to remove 'const'.
 		 */
 		 */
 		cab->stream.next_in = (Bytef *)(uintptr_t)d;
 		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;
 		cab->stream.total_in = 0;
 
 
 		/* Cut out a tow-byte MSZIP signature(0x43, 0x4b). */
 		/* 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;
 					*avail = ARCHIVE_FATAL;
 					return (NULL);
 					return (NULL);
 				}
 				}
-				mszip -= bytes_avail;
+				mszip -= (int)bytes_avail;
 				continue;
 				continue;
 			}
 			}
 			if (mszip == 1 && cab->stream.next_in[0] != 0x4b)
 			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);
 			return (NULL);
 		}
 		}
 	}
 	}
-	uavail = cab->stream.total_out;
+	uavail = (uint16_t)cab->stream.total_out;
 
 
 	if (uavail < cfdata->uncompressed_size) {
 	if (uavail < cfdata->uncompressed_size) {
 		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 		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.
 	 * 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;
 		rbytes -= cbytes;
 
 
 		if (cfdata->uncompressed_avail == 0 &&
 		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. */
 			/* We have not read any data yet. */
 			if (cbytes == cfdata->uncompressed_bytes_remaining) {
 			if (cbytes == cfdata->uncompressed_bytes_remaining) {
 				/* Skip whole current CFDATA. */
 				/* Skip whole current CFDATA. */
@@ -1819,8 +1816,8 @@ cab_consume_cfdata(struct archive_read *a, int64_t consumed_bytes)
 				}
 				}
 				continue;
 				continue;
 			}
 			}
-			cfdata->read_offset += cbytes;
-			cfdata->uncompressed_bytes_remaining -= cbytes;
+			cfdata->read_offset += (uint16_t)cbytes;
+			cfdata->uncompressed_bytes_remaining -= (uint16_t)cbytes;
 			break;
 			break;
 		} else if (cbytes == 0) {
 		} else if (cbytes == 0) {
 			err = cab_next_cfdata(a);
 			err = cab_next_cfdata(a);
@@ -1844,7 +1841,7 @@ cab_consume_cfdata(struct archive_read *a, int64_t consumed_bytes)
 			if (avail <= 0)
 			if (avail <= 0)
 				return (ARCHIVE_FATAL);
 				return (ARCHIVE_FATAL);
 			if (avail > cbytes)
 			if (avail > cbytes)
-				avail = cbytes;
+				avail = (ssize_t)cbytes;
 			if (cab_minimum_consume_cfdata(a, avail) < 0)
 			if (cab_minimum_consume_cfdata(a, avail) < 0)
 				return (ARCHIVE_FATAL);
 				return (ARCHIVE_FATAL);
 			cbytes -= avail;
 			cbytes -= avail;
@@ -1873,8 +1870,8 @@ cab_minimum_consume_cfdata(struct archive_read *a, int64_t consumed_bytes)
 		else
 		else
 			cbytes = cfdata->unconsumed;
 			cbytes = cfdata->unconsumed;
 		rbytes -= cbytes; 
 		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;
 		cfdata->unconsumed -= cbytes;
 	} else {
 	} else {
 		cbytes = cfdata->uncompressed_avail - cfdata->read_offset;
 		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)
 			if (consumed_bytes < cbytes)
 				cbytes = consumed_bytes;
 				cbytes = consumed_bytes;
 			rbytes -= cbytes;
 			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) {
 		if (cfdata->unconsumed) {
@@ -1894,12 +1891,12 @@ cab_minimum_consume_cfdata(struct archive_read *a, int64_t consumed_bytes)
 	}
 	}
 	if (cbytes) {
 	if (cbytes) {
 		/* Compute the sum. */
 		/* Compute the sum. */
-		cab_checksum_update(a, cbytes);
+		cab_checksum_update(a, (size_t)cbytes);
 
 
 		/* Consume as much as the compressor actually used. */
 		/* Consume as much as the compressor actually used. */
 		__archive_read_consume(a, cbytes);
 		__archive_read_consume(a, cbytes);
 		cab->cab_offset += cbytes;
 		cab->cab_offset += cbytes;
-		cfdata->compressed_bytes_remaining -= cbytes;
+		cfdata->compressed_bytes_remaining -= (uint16_t)cbytes;
 		if (cfdata->compressed_bytes_remaining == 0) {
 		if (cfdata->compressed_bytes_remaining == 0) {
 			err = cab_checksum_finish(a);
 			err = cab_checksum_finish(a);
 			if (err < 0)
 			if (err < 0)
@@ -1940,10 +1937,10 @@ cab_read_data(struct archive_read *a, const void **buff,
 			    ARCHIVE_ERRNO_FILE_FORMAT, "Invalid CFDATA");
 			    ARCHIVE_ERRNO_FILE_FORMAT, "Invalid CFDATA");
 			return (ARCHIVE_FATAL);
 			return (ARCHIVE_FATAL);
 		} else
 		} else
-			return (bytes_avail);
+			return ((int)bytes_avail);
 	}
 	}
 	if (bytes_avail > cab->entry_bytes_remaining)
 	if (bytes_avail > cab->entry_bytes_remaining)
-		bytes_avail = cab->entry_bytes_remaining;
+		bytes_avail = (ssize_t)cab->entry_bytes_remaining;
 
 
 	*size = bytes_avail;
 	*size = bytes_avail;
 	*offset = cab->entry_offset;
 	*offset = cab->entry_offset;
@@ -1952,6 +1949,11 @@ cab_read_data(struct archive_read *a, const void **buff,
 	if (cab->entry_bytes_remaining == 0)
 	if (cab->entry_bytes_remaining == 0)
 		cab->end_of_entry = 1;
 		cab->end_of_entry = 1;
 	cab->entry_unconsumed = bytes_avail;
 	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);
 	return (ARCHIVE_OK);
 }
 }
 
 
@@ -1967,9 +1969,17 @@ archive_read_format_cab_read_data_skip(struct archive_read *a)
 	if (cab->end_of_archive)
 	if (cab->end_of_archive)
 		return (ARCHIVE_EOF);
 		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) {
 	if (cab->entry_unconsumed) {
 		/* Consume as much as the compressor actually used. */
 		/* 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;
 		cab->entry_unconsumed = 0;
 		if (r < 0)
 		if (r < 0)
 			return (r);
 			return (r);
@@ -1991,6 +2001,12 @@ archive_read_format_cab_read_data_skip(struct archive_read *a)
 	if (bytes_skipped < 0)
 	if (bytes_skipped < 0)
 		return (ARCHIVE_FATAL);
 		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. */
 	/* This entry is finished and done. */
 	cab->end_of_entry_cleanup = cab->end_of_entry = 1;
 	cab->end_of_entry_cleanup = cab->end_of_entry = 1;
 	return (ARCHIVE_OK);
 	return (ARCHIVE_OK);
@@ -2066,6 +2082,7 @@ lzx_decode_init(struct lzx_stream *strm, int w_bits)
 	struct lzx_dec *ds;
 	struct lzx_dec *ds;
 	int slot, w_size, w_slot;
 	int slot, w_size, w_slot;
 	int base, footer;
 	int base, footer;
+	int base_inc[18];
 
 
 	if (strm->ds == NULL) {
 	if (strm->ds == NULL) {
 		strm->ds = calloc(1, sizeof(*strm->ds));
 		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));
 		lzx_huffman_free(&(ds->mt));
 	}
 	}
 
 
+	for (footer = 0; footer < 18; footer++)
+		base_inc[footer] = 1 << footer;
 	base = footer = 0;
 	base = footer = 0;
 	for (slot = 0; slot < w_slot; slot++) {
 	for (slot = 0; slot < w_slot; slot++) {
 		int n;
 		int n;
 		if (footer == 0)
 		if (footer == 0)
 			base = slot;
 			base = slot;
 		else
 		else
-			base += 1 << footer;
+			base += base_inc[footer];
 		if (footer < 17) {
 		if (footer < 17) {
 			footer = -2;
 			footer = -2;
 			for (n = base; n; n >>= 1)
 			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;
 	end = b + size - 10;
 	while (b < end && (b = memchr(b, 0xE8, end - b)) != NULL) {
 	while (b < end && (b = memchr(b, 0xE8, end - b)) != NULL) {
 		size_t i = b - (unsigned char *)p;
 		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]);
 		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)
 			if (value >= 0)
 				displacement = value - cp;
 				displacement = value - cp;
 			else
 			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. */
 /* Notify how many bits we consumed. */
 #define lzx_br_consume(br, n)	((br)->cache_avail -= (n))
 #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[] = {
 static const uint32_t cache_masks[] = {
 	0x00000000, 0x00000001, 0x00000003, 0x00000007,
 	0x00000000, 0x00000001, 0x00000003, 0x00000007,
@@ -2349,24 +2370,25 @@ lzx_cleanup_bitstream(struct lzx_stream *strm)
 #define ST_RD_TRANSLATION_SIZE	1
 #define ST_RD_TRANSLATION_SIZE	1
 #define ST_RD_BLOCK_TYPE	2
 #define ST_RD_BLOCK_TYPE	2
 #define ST_RD_BLOCK_SIZE	3
 #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
 static int
 lzx_decode(struct lzx_stream *strm, int last)
 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;
 					ds->state = ST_RD_ALIGNED_OFFSET;
 				break;
 				break;
 			}
 			}
+			/* FALL THROUGH */
+		case ST_RD_ALIGNMENT:
 			/*
 			/*
 			 * Handle an Uncompressed Block.
 			 * Handle an Uncompressed Block.
 			 */
 			 */
 			/* Skip padding to align following field on
 			/* Skip padding to align following field on
 			 * 16-bit boundary. */
 			 * 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. */
 			/* Preparation to read repeated offsets R0,R1 and R2. */
 			ds->rbytes_avail = 0;
 			ds->rbytes_avail = 0;
 			ds->state = ST_RD_R0;
 			ds->state = ST_RD_R0;
@@ -2500,8 +2535,7 @@ lzx_read_blocks(struct lzx_stream *strm, int last)
 					lzx_br_consume(br, 16);
 					lzx_br_consume(br, 16);
 					archive_le16enc(ds->rbytes, u16);
 					archive_le16enc(ds->rbytes, u16);
 					ds->rbytes_avail = 2;
 					ds->rbytes_avail = 2;
-				} else
-					ds->rbytes_avail = 0;
+				}
 				if (ds->rbytes_avail < 4 && ds->br.have_odd) {
 				if (ds->rbytes_avail < 4 && ds->br.have_odd) {
 					ds->rbytes[ds->rbytes_avail++] =
 					ds->rbytes[ds->rbytes_avail++] =
 					    ds->br.odd;
 					    ds->br.odd;
@@ -2517,6 +2551,7 @@ lzx_read_blocks(struct lzx_stream *strm, int last)
 					    *strm->next_in++;
 					    *strm->next_in++;
 					strm->avail_in--;
 					strm->avail_in--;
 				}
 				}
+				ds->rbytes_avail = 0;
 				if (ds->state == ST_RD_R0) {
 				if (ds->state == ST_RD_R0) {
 					ds->r0 = archive_le32dec(ds->rbytes);
 					ds->r0 = archive_le32dec(ds->rbytes);
 					if (ds->r0 < 0)
 					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.
 			 * Copy bytes form next_in to next_out directly.
 			 */
 			 */
 			while (ds->block_bytes_avail) {
 			while (ds->block_bytes_avail) {
-				unsigned char *d;
-				int l,ll;
+				int l;
 
 
 				if (strm->avail_out <= 0)
 				if (strm->avail_out <= 0)
 					/* Output buffer is empty. */
 					/* Output buffer is empty. */
@@ -2553,24 +2587,23 @@ lzx_read_blocks(struct lzx_stream *strm, int last)
 						goto failed;
 						goto failed;
 					return (ARCHIVE_OK);
 					return (ARCHIVE_OK);
 				}
 				}
-				l = ds->block_bytes_avail;
+				l = (int)ds->block_bytes_avail;
 				if (l > ds->w_size - ds->w_pos)
 				if (l > ds->w_size - ds->w_pos)
 					l = ds->w_size - ds->w_pos;
 					l = ds->w_size - ds->w_pos;
 				if (l > strm->avail_out)
 				if (l > strm->avail_out)
 					l = (int)strm->avail_out;
 					l = (int)strm->avail_out;
 				if (l > strm->avail_in)
 				if (l > strm->avail_in)
 					l = (int)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 */
 			/* FALL THROUGH */
 		case ST_COPY_UNCOMP2:
 		case ST_COPY_UNCOMP2:
@@ -2716,8 +2749,8 @@ lzx_decode_blocks(struct lzx_stream *strm, int last)
 	struct lzx_br bre = ds->br;
 	struct lzx_br bre = ds->br;
 	struct huffman *at = &(ds->at), *lt = &(ds->lt), *mt = &(ds->mt);
 	struct huffman *at = &(ds->at), *lt = &(ds->lt), *mt = &(ds->mt);
 	const struct lzx_pos_tbl *pos_tbl = ds->pos_tbl;
 	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 *w_buff = ds->w_buff;
 	unsigned char *at_bitlen = at->bitlen;
 	unsigned char *at_bitlen = at->bitlen;
 	unsigned char *lt_bitlen = lt->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->position_slot = position_slot;
 					ds->r0 = r0; ds->r1 = r1; ds->r2 = r2;
 					ds->r0 = r0; ds->r1 = r1; ds->r2 = r2;
 					ds->w_pos = w_pos;
 					ds->w_pos = w_pos;
-					strm->avail_out = endp - outp;
+					strm->avail_out = endp - noutp;
 					return (ARCHIVE_EOF);
 					return (ARCHIVE_EOF);
 				}
 				}
-				if (outp >= endp)
+				if (noutp >= endp)
 					/* Output buffer is empty. */
 					/* Output buffer is empty. */
 					goto next_data;
 					goto next_data;
 
 
@@ -2788,7 +2821,7 @@ lzx_decode_blocks(struct lzx_stream *strm, int last)
 				w_buff[w_pos] = c;
 				w_buff[w_pos] = c;
 				w_pos = (w_pos + 1) & w_mask;
 				w_pos = (w_pos + 1) & w_mask;
 				/* Store the decoded code to output buffer. */
 				/* Store the decoded code to output buffer. */
-				*outp++ = c;
+				*noutp++ = c;
 				block_bytes_avail--;
 				block_bytes_avail--;
 			}
 			}
 			/*
 			/*
@@ -2933,22 +2966,22 @@ lzx_decode_blocks(struct lzx_stream *strm, int last)
 					if (l > w_size - w_pos)
 					if (l > w_size - w_pos)
 						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;
 				s = w_buff + copy_pos;
 				if (l >= 8 && ((copy_pos + l < w_pos)
 				if (l >= 8 && ((copy_pos + l < w_pos)
 				  || (w_pos + l < copy_pos))) {
 				  || (w_pos + l < copy_pos))) {
 					memcpy(w_buff + w_pos, s, l);
 					memcpy(w_buff + w_pos, s, l);
-					memcpy(outp, s, l);
+					memcpy(noutp, s, l);
 				} else {
 				} else {
 					unsigned char *d;
 					unsigned char *d;
 					int li;
 					int li;
 
 
 					d = w_buff + w_pos;
 					d = w_buff + w_pos;
 					for (li = 0; li < l; li++)
 					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;
 				copy_pos = (copy_pos + l) & w_mask;
 				w_pos = (w_pos + l) & w_mask;
 				w_pos = (w_pos + l) & w_mask;
 				block_bytes_avail -= l;
 				block_bytes_avail -= l;
@@ -2956,7 +2989,7 @@ lzx_decode_blocks(struct lzx_stream *strm, int last)
 					/* A copy of current pattern ended. */
 					/* A copy of current pattern ended. */
 					break;
 					break;
 				copy_len -= l;
 				copy_len -= l;
-				if (outp >= endp) {
+				if (noutp >= endp) {
 					/* Output buffer is empty. */
 					/* Output buffer is empty. */
 					state = ST_COPY;
 					state = ST_COPY;
 					goto next_data;
 					goto next_data;
@@ -2979,7 +3012,7 @@ next_data:
 	ds->r0 = r0; ds->r1 = r1; ds->r2 = r2;
 	ds->r0 = r0; ds->r1 = r1; ds->r2 = r2;
 	ds->state = state;
 	ds->state = state;
 	ds->w_pos = w_pos;
 	ds->w_pos = w_pos;
-	strm->avail_out = endp - outp;
+	strm->avail_out = endp - noutp;
 	return (ARCHIVE_OK);
 	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]));
 		hf->bitlen = calloc(len_size,  sizeof(hf->bitlen[0]));
 		if (hf->bitlen == NULL)
 		if (hf->bitlen == NULL)
 			return (ARCHIVE_FATAL);
 			return (ARCHIVE_FATAL);
-		hf->len_size = len_size;
+		hf->len_size = (int)len_size;
 	} else
 	} else
 		memset(hf->bitlen, 0, len_size *  sizeof(hf->bitlen[0]));
 		memset(hf->bitlen, 0, len_size *  sizeof(hf->bitlen[0]));
 	if (hf->tbl == NULL) {
 	if (hf->tbl == NULL) {
@@ -3104,7 +3137,7 @@ lzx_huffman_init(struct huffman *hf, size_t len_size, int tbl_bits)
 			bits = tbl_bits;
 			bits = tbl_bits;
 		else
 		else
 			bits = HTBL_BITS;
 			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)
 		if (hf->tbl == NULL)
 			return (ARCHIVE_FATAL);
 			return (ARCHIVE_FATAL);
 		hf->tbl_bits = tbl_bits;
 		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) 2003-2007 Tim Kientzle
- * Copyright (c) 2010-2011 Michihiro NAKAJIMA
+ * Copyright (c) 2010-2012 Michihiro NAKAJIMA
  * All rights reserved.
  * All rights reserved.
  *
  *
  * Redistribution and use in source and binary forms, with or without
  * 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_header,
 	    archive_read_format_cpio_read_data,
 	    archive_read_format_cpio_read_data,
 	    archive_read_format_cpio_skip,
 	    archive_read_format_cpio_skip,
+	    NULL,
 	    archive_read_format_cpio_cleanup);
 	    archive_read_format_cpio_cleanup);
 
 
 	if (r != ARCHIVE_OK)
 	if (r != ARCHIVE_OK)
@@ -325,7 +326,7 @@ archive_read_format_cpio_options(struct archive_read *a,
 	if (strcmp(key, "compat-2x")  == 0) {
 	if (strcmp(key, "compat-2x")  == 0) {
 		/* Handle filnames as libarchive 2.x */
 		/* Handle filnames as libarchive 2.x */
 		cpio->init_default_conversion = (val != NULL)?1:0;
 		cpio->init_default_conversion = (val != NULL)?1:0;
-		ret = ARCHIVE_OK;
+		return (ARCHIVE_OK);
 	} else if (strcmp(key, "hdrcharset")  == 0) {
 	} else if (strcmp(key, "hdrcharset")  == 0) {
 		if (val == NULL || val[0] == 0)
 		if (val == NULL || val[0] == 0)
 			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
@@ -339,11 +340,13 @@ archive_read_format_cpio_options(struct archive_read *a,
 			else
 			else
 				ret = ARCHIVE_FATAL;
 				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
 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 this is a symlink, read the link contents. */
 	if (archive_entry_filetype(entry) == AE_IFLNK) {
 	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)
 		if (h == NULL)
 			return (ARCHIVE_FATAL);
 			return (ARCHIVE_FATAL);
 		if (archive_entry_copy_symlink_l(entry, (const char *)h,
 		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) {
 			if (errno == ENOMEM) {
 				archive_set_error(&a->archive, ENOMEM,
 				archive_set_error(&a->archive, ENOMEM,
 				    "Can't allocate memory for Linkname");
 				    "Can't allocate memory for Linkname");
@@ -456,7 +460,7 @@ archive_read_format_cpio_read_data(struct archive_read *a,
 		if (bytes_read <= 0)
 		if (bytes_read <= 0)
 			return (ARCHIVE_FATAL);
 			return (ARCHIVE_FATAL);
 		if (bytes_read > cpio->entry_bytes_remaining)
 		if (bytes_read > cpio->entry_bytes_remaining)
-			bytes_read = cpio->entry_bytes_remaining;
+			bytes_read = (ssize_t)cpio->entry_bytes_remaining;
 		*size = bytes_read;
 		*size = bytes_read;
 		cpio->entry_bytes_unconsumed = bytes_read;
 		cpio->entry_bytes_unconsumed = bytes_read;
 		*offset = cpio->entry_offset;
 		*offset = cpio->entry_offset;
@@ -601,17 +605,23 @@ header_newc(struct archive_read *a, struct cpio *cpio,
 		/* TODO: Abort here? */
 		/* 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_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_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_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);
 	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. */
 	/* Pad name to 2 more than a multiple of 4. */
 	*name_pad = (2 - *namelength) & 3;
 	*name_pad = (2 - *namelength) & 3;
 
 
@@ -765,15 +775,19 @@ header_odc(struct archive_read *a, struct cpio *cpio,
 	/* Parse out octal fields. */
 	/* Parse out octal fields. */
 	header = (const char *)h;
 	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_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_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_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);
 	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. */
 	*name_pad = 0; /* No padding of filename. */
 
 
 	/*
 	/*
@@ -814,15 +828,19 @@ header_afiol(struct archive_read *a, struct cpio *cpio,
 	/* Parse out octal fields. */
 	/* Parse out octal fields. */
 	header = (const char *)h;
 	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_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_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_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);
 	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. */
 	*name_pad = 0; /* No padding of filename. */
 
 
 	cpio->entry_bytes_remaining =
 	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_header,
 	    archive_read_format_empty_read_data,
 	    archive_read_format_empty_read_data,
 	    NULL,
 	    NULL,
+	    NULL,
 	    NULL);
 	    NULL);
 
 
 	return (r);
 	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) 2003-2007 Tim Kientzle
  * Copyright (c) 2009 Andreas Henriksson <[email protected]>
  * Copyright (c) 2009 Andreas Henriksson <[email protected]>
- * Copyright (c) 2009-2011 Michihiro NAKAJIMA
+ * Copyright (c) 2009-2012 Michihiro NAKAJIMA
  * All rights reserved.
  * All rights reserved.
  *
  *
  * Redistribution and use in source and binary forms, with or without
  * Redistribution and use in source and binary forms, with or without
@@ -374,6 +374,8 @@ struct iso9660 {
 	size_t		 utf16be_path_len;
 	size_t		 utf16be_path_len;
 	unsigned char *utf16be_previous_path;
 	unsigned char *utf16be_previous_path;
 	size_t		 utf16be_previous_path_len;
 	size_t		 utf16be_previous_path_len;
+	/* Null buufer used in bidder to improve its performance. */
+	unsigned char	 null[2048];
 };
 };
 
 
 static int	archive_read_format_iso9660_bid(struct archive_read *, int);
 static int	archive_read_format_iso9660_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_header,
 	    archive_read_format_iso9660_read_data,
 	    archive_read_format_iso9660_read_data,
 	    archive_read_format_iso9660_read_data_skip,
 	    archive_read_format_iso9660_read_data_skip,
+	    NULL,
 	    archive_read_format_iso9660_cleanup);
 	    archive_read_format_iso9660_cleanup);
 
 
 	if (r != ARCHIVE_OK) {
 	if (r != ARCHIVE_OK) {
@@ -587,6 +590,23 @@ archive_read_format_iso9660_options(struct archive_read *a,
 	return (ARCHIVE_WARN);
 	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
 static int
 isBootRecord(struct iso9660 *iso9660, const unsigned char *h)
 isBootRecord(struct iso9660 *iso9660, const unsigned char *h)
 {
 {
@@ -632,8 +652,6 @@ isVolumePartition(struct iso9660 *iso9660, const unsigned char *h)
 static int
 static int
 isVDSetTerminator(struct iso9660 *iso9660, const unsigned char *h)
 isVDSetTerminator(struct iso9660 *iso9660, const unsigned char *h)
 {
 {
-	int i;
-
 	(void)iso9660; /* UNUSED */
 	(void)iso9660; /* UNUSED */
 
 
 	/* Type of the Volume Descriptor Set Terminator must be 255. */
 	/* Type of the Volume Descriptor Set Terminator must be 255. */
@@ -645,9 +663,8 @@ isVDSetTerminator(struct iso9660 *iso9660, const unsigned char *h)
 		return (0);
 		return (0);
 
 
 	/* Reserved field must be 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);
 	return (1);
 }
 }
@@ -708,7 +725,6 @@ isSVD(struct iso9660 *iso9660, const unsigned char *h)
 	ssize_t logical_block_size;
 	ssize_t logical_block_size;
 	int32_t volume_block;
 	int32_t volume_block;
 	int32_t location;
 	int32_t location;
-	int i;
 
 
 	(void)iso9660; /* UNUSED */
 	(void)iso9660; /* UNUSED */
 
 
@@ -717,15 +733,12 @@ isSVD(struct iso9660 *iso9660, const unsigned char *h)
 		return (0);
 		return (0);
 
 
 	/* Reserved field must be 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. */
 	/* File structure version must be 1 for ISO9660/ECMA119. */
 	if (h[SVD_file_structure_version_offset] != 1)
 	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;
 	ssize_t logical_block_size;
 	int32_t volume_block;
 	int32_t volume_block;
 	int32_t location;
 	int32_t location;
-	int i;
 
 
 	(void)iso9660; /* UNUSED */
 	(void)iso9660; /* UNUSED */
 
 
@@ -788,14 +800,12 @@ isEVD(struct iso9660 *iso9660, const unsigned char *h)
 		return (0);
 		return (0);
 
 
 	/* Reserved field must be 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. */
 	/* 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. */
 	/* Logical block size must be > 0. */
 	/* I've looked at Ecma 119 and can't find any stronger
 	/* 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);
 		return (0);
 
 
 	/* Reserved field must be 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. */
 	/* 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. */
 	/* Read Root Directory Record in Volume Descriptor. */
 	p = h + PVD_root_directory_record_offset;
 	p = h + PVD_root_directory_record_offset;
@@ -869,14 +877,12 @@ isPVD(struct iso9660 *iso9660, const unsigned char *h)
 		return (0);
 		return (0);
 
 
 	/* Reserved field must be 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. */
 	/* 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. */
 	/* Logical block size must be > 0. */
 	/* I've looked at Ecma 119 and can't find any stronger
 	/* 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);
 			return (0);
 
 
 	/* Reserved field must be 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
 	/* XXX TODO: Check other values for sanity; reject more
 	 * malformed PVDs. XXX */
 	 * malformed PVDs. XXX */
@@ -934,8 +939,10 @@ isPVD(struct iso9660 *iso9660, const unsigned char *h)
 	if (!iso9660->primary.location) {
 	if (!iso9660->primary.location) {
 		iso9660->logical_block_size = logical_block_size;
 		iso9660->logical_block_size = logical_block_size;
 		iso9660->volume_block = volume_block;
 		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);
 		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;
 	size_t step, skip_size;
 
 
 	iso9660 = (struct iso9660 *)(a->format->data);
 	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) {
 	if (iso9660->current_position > parent->offset) {
 		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 		    "Ignoring out-of-order directory (%s) %jd > %jd",
 		    "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;
 		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);
 	b = __archive_read_ahead(a, step, NULL);
 	if (b == NULL) {
 	if (b == NULL) {
 		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
@@ -1060,101 +1073,112 @@ read_children(struct archive_read *a, struct file_info *parent)
 }
 }
 
 
 static int
 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;
 	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 = LOGICAL_BLOCK_SIZE * vd->location;
+		skipsize -= iso9660->current_position;
 		skipsize = __archive_read_consume(a, skipsize);
 		skipsize = __archive_read_consume(a, skipsize);
 		if (skipsize < 0)
 		if (skipsize < 0)
 			return ((int)skipsize);
 			return ((int)skipsize);
-		iso9660->current_position = skipsize;
+		iso9660->current_position += skipsize;
 
 
 		block = __archive_read_ahead(a, vd->size, NULL);
 		block = __archive_read_ahead(a, vd->size, NULL);
 		if (block == 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 "
 			    "Failed to read full block when scanning "
 			    "ISO9660 directory list");
 			    "ISO9660 directory list");
 			return (ARCHIVE_FATAL);
 			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;
 		iso9660->seenJoliet = 0;
 		file = parse_file_info(a, NULL, block);
 		file = parse_file_info(a, NULL, block);
 		if (file == NULL)
 		if (file == NULL)
 			return (ARCHIVE_FATAL);
 			return (ARCHIVE_FATAL);
 		iso9660->seenJoliet = seenJoliet;
 		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. */
 	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_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) {
 	if (file->offset + file->size > iso9660->volume_size) {
 		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 		    "File is beyond end-of-media: %s",
 		    "File is beyond end-of-media: %s",
 		    archive_entry_pathname(entry));
 		    archive_entry_pathname(entry));
 		iso9660->entry_bytes_remaining = 0;
 		iso9660->entry_bytes_remaining = 0;
-		iso9660->entry_sparse_offset = 0;
 		return (ARCHIVE_WARN);
 		return (ARCHIVE_WARN);
 	}
 	}
 
 
@@ -1286,36 +1310,33 @@ archive_read_format_iso9660_read_header(struct archive_read *a,
 			    iso9660->previous_pathname.s);
 			    iso9660->previous_pathname.s);
 		archive_entry_unset_size(entry);
 		archive_entry_unset_size(entry);
 		iso9660->entry_bytes_remaining = 0;
 		iso9660->entry_bytes_remaining = 0;
-		iso9660->entry_sparse_offset = 0;
 		return (rd_r);
 		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 &&
 	if ((file->mode & AE_IFMT) != AE_IFDIR &&
 	    file->offset < iso9660->current_position) {
 	    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. */
 	/* 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);
 		archive_entry_set_nlink(entry, 2 + file->subdirs);
 		/* Directory data has been read completely. */
 		/* Directory data has been read completely. */
 		iso9660->entry_bytes_remaining = 0;
 		iso9660->entry_bytes_remaining = 0;
-		iso9660->entry_sparse_offset = 0;
 	}
 	}
 
 
 	if (rd_r != ARCHIVE_OK)
 	if (rd_r != ARCHIVE_OK)
@@ -1397,7 +1417,7 @@ zisofs_read_data(struct archive_read *a,
 		return (ARCHIVE_FATAL);
 		return (ARCHIVE_FATAL);
 	}
 	}
 	if (bytes_read > iso9660->entry_bytes_remaining)
 	if (bytes_read > iso9660->entry_bytes_remaining)
-		bytes_read = iso9660->entry_bytes_remaining;
+		bytes_read = (ssize_t)iso9660->entry_bytes_remaining;
 	avail = bytes_read;
 	avail = bytes_read;
 	uncompressed_size = 0;
 	uncompressed_size = 0;
 
 
@@ -1405,9 +1425,9 @@ zisofs_read_data(struct archive_read *a,
 		size_t ceil, xsize;
 		size_t ceil, xsize;
 
 
 		/* Allocate block pointers buffer. */
 		/* Allocate block pointers buffer. */
-		ceil = (zisofs->pz_uncompressed_size +
+		ceil = (size_t)((zisofs->pz_uncompressed_size +
 			(((int64_t)1) << zisofs->pz_log2_bs) - 1)
 			(((int64_t)1) << zisofs->pz_log2_bs) - 1)
-			>> zisofs->pz_log2_bs;
+			>> zisofs->pz_log2_bs);
 		xsize = (ceil + 1) * 4;
 		xsize = (ceil + 1) * 4;
 		if (zisofs->block_pointers_alloc < xsize) {
 		if (zisofs->block_pointers_alloc < xsize) {
 			size_t alloc;
 			size_t alloc;
@@ -1426,7 +1446,7 @@ zisofs_read_data(struct archive_read *a,
 		zisofs->block_pointers_size = xsize;
 		zisofs->block_pointers_size = xsize;
 
 
 		/* Allocate uncompressed data buffer. */
 		/* 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_size < xsize) {
 			if (zisofs->uncompressed_buffer != NULL)
 			if (zisofs->uncompressed_buffer != NULL)
 				free(zisofs->uncompressed_buffer);
 				free(zisofs->uncompressed_buffer);
@@ -1563,9 +1583,10 @@ zisofs_read_data(struct archive_read *a,
 		if (avail > zisofs->block_avail)
 		if (avail > zisofs->block_avail)
 			zisofs->stream.avail_in = zisofs->block_avail;
 			zisofs->stream.avail_in = zisofs->block_avail;
 		else
 		else
-			zisofs->stream.avail_in = avail;
+			zisofs->stream.avail_in = (uInt)avail;
 		zisofs->stream.next_out = zisofs->uncompressed_buffer;
 		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);
 		r = inflate(&zisofs->stream, 0);
 		switch (r) {
 		switch (r) {
@@ -1580,7 +1601,7 @@ zisofs_read_data(struct archive_read *a,
 		uncompressed_size =
 		uncompressed_size =
 		    zisofs->uncompressed_buffer_size - zisofs->stream.avail_out;
 		    zisofs->uncompressed_buffer_size - zisofs->stream.avail_out;
 		avail -= zisofs->stream.next_in - p;
 		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:
 next_data:
 	bytes_read -= avail;
 	bytes_read -= avail;
@@ -1590,7 +1611,7 @@ next_data:
 	iso9660->entry_sparse_offset += uncompressed_size;
 	iso9660->entry_sparse_offset += uncompressed_size;
 	iso9660->entry_bytes_remaining -= bytes_read;
 	iso9660->entry_bytes_remaining -= bytes_read;
 	iso9660->current_position += 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;
 	iso9660->entry_bytes_unconsumed += bytes_read;
 
 
 	return (ARCHIVE_OK);
 	return (ARCHIVE_OK);
@@ -1671,7 +1692,7 @@ archive_read_format_iso9660_read_data(struct archive_read *a,
 	if (*buff == NULL)
 	if (*buff == NULL)
 		return (ARCHIVE_FATAL);
 		return (ARCHIVE_FATAL);
 	if (bytes_read > iso9660->entry_bytes_remaining)
 	if (bytes_read > iso9660->entry_bytes_remaining)
-		bytes_read = iso9660->entry_bytes_remaining;
+		bytes_read = (ssize_t)iso9660->entry_bytes_remaining;
 	*size = bytes_read;
 	*size = bytes_read;
 	*offset = iso9660->entry_sparse_offset;
 	*offset = iso9660->entry_sparse_offset;
 	iso9660->entry_sparse_offset += bytes_read;
 	iso9660->entry_sparse_offset += bytes_read;
@@ -1756,7 +1777,8 @@ parse_file_info(struct archive_read *a, struct file_info *parent,
 	 */
 	 */
 	if (location > 0 &&
 	if (location > 0 &&
 	    (location + ((fsize + iso9660->logical_block_size -1)
 	    (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,
 		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 		    "Invalid location of extent of file");
 		    "Invalid location of extent of file");
 		return (NULL);
 		return (NULL);
@@ -1872,9 +1894,7 @@ parse_file_info(struct archive_read *a, struct file_info *parent,
 	if (iso9660->opt_support_rockridge) {
 	if (iso9660->opt_support_rockridge) {
 		if (parent == NULL && rr_end - rr_start >= 7) {
 		if (parent == NULL && rr_end - rr_start >= 7) {
 			p = rr_start;
 			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
 				 * SP extension stores the suspOffset
 				 * (Number of bytes to skip between
 				 * (Number of bytes to skip between
@@ -1907,6 +1927,19 @@ parse_file_info(struct archive_read *a, struct file_info *parent,
 				free(file);
 				free(file);
 				return (NULL);
 				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
 		} else
 			/* If there isn't SUSP, disable parsing
 			/* If there isn't SUSP, disable parsing
 			 * rock ridge extensions. */
 			 * rock ridge extensions. */
@@ -1921,6 +1954,7 @@ parse_file_info(struct archive_read *a, struct file_info *parent,
 	if (iso9660->seenRockridge) {
 	if (iso9660->seenRockridge) {
 		if (parent != NULL && parent->parent == NULL &&
 		if (parent != NULL && parent->parent == NULL &&
 		    (flags & 0x02) && iso9660->rr_moved == NULL &&
 		    (flags & 0x02) && iso9660->rr_moved == NULL &&
+		    file->name.s &&
 		    (strcmp(file->name.s, "rr_moved") == 0 ||
 		    (strcmp(file->name.s, "rr_moved") == 0 ||
 		     strcmp(file->name.s, ".rr_moved") == 0)) {
 		     strcmp(file->name.s, ".rr_moved") == 0)) {
 			iso9660->rr_moved = file;
 			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 data_length = p[2] - 4;
 		int version = p[3];
 		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]) {
 		switch(p[0]) {
 		case 'C':
 		case 'C':
-			if (p[0] == 'C' && p[1] == 'E') {
+			if (p[1] == 'E') {
 				if (version == 1 && data_length == 24) {
 				if (version == 1 && data_length == 24) {
 					/*
 					/*
 					 * CE extension comprises:
 					 * CE extension comprises:
@@ -2078,53 +2107,42 @@ parse_rockridge(struct archive_read *a, struct file_info *file,
 					    != ARCHIVE_OK)
 					    != ARCHIVE_OK)
 						return (ARCHIVE_FATAL);
 						return (ARCHIVE_FATAL);
 				}
 				}
-				break;
 			}
 			}
-			if (p[0] == 'C' && p[1] == 'L') {
+			else if (p[1] == 'L') {
 				if (version == 1 && data_length == 8) {
 				if (version == 1 && data_length == 8) {
 					file->cl_offset = (uint64_t)
 					file->cl_offset = (uint64_t)
 					    iso9660->logical_block_size *
 					    iso9660->logical_block_size *
 					    (uint64_t)archive_le32dec(data);
 					    (uint64_t)archive_le32dec(data);
 					iso9660->seenRockridge = 1;
 					iso9660->seenRockridge = 1;
 				}
 				}
-				break;
 			}
 			}
-			/* FALLTHROUGH */
+			break;
 		case 'N':
 		case 'N':
-			if (p[0] == 'N' && p[1] == 'M') {
+			if (p[1] == 'M') {
 				if (version == 1) {
 				if (version == 1) {
 					parse_rockridge_NM1(file,
 					parse_rockridge_NM1(file,
 					    data, data_length);
 					    data, data_length);
 					iso9660->seenRockridge = 1;
 					iso9660->seenRockridge = 1;
 				}
 				}
-				break;
 			}
 			}
-			/* FALLTHROUGH */
+			break;
 		case 'P':
 		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) {
 				if (version == 1 && data_length == 16) {
 					file->rdev = toi(data,4);
 					file->rdev = toi(data,4);
 					file->rdev <<= 32;
 					file->rdev <<= 32;
 					file->rdev |= toi(data + 8, 4);
 					file->rdev |= toi(data + 8, 4);
 					iso9660->seenRockridge = 1;
 					iso9660->seenRockridge = 1;
 				}
 				}
-				break;
 			}
 			}
-			if (p[0] == 'P' && p[1] == 'X') {
+			else if (p[1] == 'X') {
 				/*
 				/*
 				 * PX extension comprises:
 				 * PX extension comprises:
 				 *   8 bytes for mode,
 				 *   8 bytes for mode,
@@ -2151,35 +2169,31 @@ parse_rockridge(struct archive_read *a, struct file_info *file,
 						    = toi(data + 32, 4);
 						    = toi(data + 32, 4);
 					iso9660->seenRockridge = 1;
 					iso9660->seenRockridge = 1;
 				}
 				}
-				break;
 			}
 			}
-			/* FALLTHROUGH */
+			break;
 		case 'R':
 		case 'R':
-			if (p[0] == 'R' && p[1] == 'E' && version == 1) {
+			if (p[1] == 'E' && version == 1) {
 				file->re = 1;
 				file->re = 1;
 				iso9660->seenRockridge = 1;
 				iso9660->seenRockridge = 1;
-				break;
 			}
 			}
-			if (p[0] == 'R' && p[1] == 'R' && version == 1) {
+			else if (p[1] == 'R' && version == 1) {
 				/*
 				/*
 				 * RR extension comprises:
 				 * RR extension comprises:
 				 *    one byte flag value
 				 *    one byte flag value
 				 * This extension is obsolete,
 				 * This extension is obsolete,
 				 * so contents are always ignored.
 				 * so contents are always ignored.
 				 */
 				 */
-				break;
 			}
 			}
-			/* FALLTHROUGH */
+			break;
 		case 'S':
 		case 'S':
-			if (p[0] == 'S' && p[1] == 'L') {
+			if (p[1] == 'L') {
 				if (version == 1) {
 				if (version == 1) {
 					parse_rockridge_SL1(file,
 					parse_rockridge_SL1(file,
 					    data, data_length);
 					    data, data_length);
 					iso9660->seenRockridge = 1;
 					iso9660->seenRockridge = 1;
 				}
 				}
-				break;
 			}
 			}
-			if (p[0] == 'S' && p[1] == 'T'
+			else if (p[1] == 'T'
 			    && data_length == 0 && version == 1) {
 			    && data_length == 0 && version == 1) {
 				/*
 				/*
 				 * ST extension marks end of this
 				 * ST extension marks end of this
@@ -2194,32 +2208,27 @@ parse_rockridge(struct archive_read *a, struct file_info *file,
 				iso9660->seenRockridge = 0;
 				iso9660->seenRockridge = 0;
 				return (ARCHIVE_OK);
 				return (ARCHIVE_OK);
 			}
 			}
+			break;
 		case 'T':
 		case 'T':
-			if (p[0] == 'T' && p[1] == 'F') {
+			if (p[1] == 'F') {
 				if (version == 1) {
 				if (version == 1) {
 					parse_rockridge_TF1(file,
 					parse_rockridge_TF1(file,
 					    data, data_length);
 					    data, data_length);
 					iso9660->seenRockridge = 1;
 					iso9660->seenRockridge = 1;
 				}
 				}
-				break;
 			}
 			}
-			/* FALLTHROUGH */
+			break;
 		case 'Z':
 		case 'Z':
-			if (p[0] == 'Z' && p[1] == 'F') {
+			if (p[1] == 'F') {
 				if (version == 1)
 				if (version == 1)
 					parse_rockridge_ZF1(file,
 					parse_rockridge_ZF1(file,
 					    data, data_length);
 					    data, data_length);
-				break;
 			}
 			}
-			/* FALLTHROUGH */
+			break;
 		default:
 		default:
-			/* The FALLTHROUGHs above leave us here for
-			 * any unsupported extension. */
 			break;
 			break;
 		}
 		}
 
 
-
-
 		p += p[2];
 		p += p[2];
 	}
 	}
 	return (ARCHIVE_OK);
 	return (ARCHIVE_OK);
@@ -2241,7 +2250,7 @@ register_CE(struct archive_read *a, int32_t location,
 	    offset >= file->offset) ||
 	    offset >= file->offset) ||
 	    offset < iso9660->current_position ||
 	    offset < iso9660->current_position ||
 	    (((uint64_t)file->ce_offset) + file->ce_size)
 	    (((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
 	    offset + file->ce_offset + file->ce_size
 		  > iso9660->volume_size) {
 		  > iso9660->volume_size) {
 		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 		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");
 			archive_set_error(&a->archive, ENOMEM, "Out of memory");
 			return (ARCHIVE_FATAL);
 			return (ARCHIVE_FATAL);
 		}
 		}
-		p = malloc(new_size * sizeof(p[0]));
+		p = calloc(new_size, sizeof(p[0]));
 		if (p == NULL) {
 		if (p == NULL) {
 			archive_set_error(&a->archive, ENOMEM, "Out of memory");
 			archive_set_error(&a->archive, ENOMEM, "Out of memory");
 			return (ARCHIVE_FATAL);
 			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)
 	if (!file->symlink_continues || file->symlink.length < 1)
 		archive_string_empty(&file->symlink);
 		archive_string_empty(&file->symlink);
-	else if (!file->symlink_continues &&
-	    file->symlink.s[file->symlink.length - 1] != '/')
-		separator = "/";
 	file->symlink_continues = 0;
 	file->symlink_continues = 0;
 
 
 	/*
 	/*
@@ -2882,8 +2888,9 @@ next_cache_entry(struct archive_read *a, struct iso9660 *iso9660,
 
 
 fatal_rr:
 fatal_rr:
 	archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 	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);
 	return (ARCHIVE_FATAL);
 }
 }
 
 
@@ -3085,6 +3092,8 @@ isodate7(const unsigned char *v)
 {
 {
 	struct tm tm;
 	struct tm tm;
 	int offset;
 	int offset;
+	time_t t;
+
 	memset(&tm, 0, sizeof(tm));
 	memset(&tm, 0, sizeof(tm));
 	tm.tm_year = v[0];
 	tm.tm_year = v[0];
 	tm.tm_mon = v[1] - 1;
 	tm.tm_mon = v[1] - 1;
@@ -3098,7 +3107,10 @@ isodate7(const unsigned char *v)
 		tm.tm_hour -= offset / 4;
 		tm.tm_hour -= offset / 4;
 		tm.tm_min -= (offset % 4) * 15;
 		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
 static time_t
@@ -3106,6 +3118,8 @@ isodate17(const unsigned char *v)
 {
 {
 	struct tm tm;
 	struct tm tm;
 	int offset;
 	int offset;
+	time_t t;
+
 	memset(&tm, 0, sizeof(tm));
 	memset(&tm, 0, sizeof(tm));
 	tm.tm_year = (v[0] - '0') * 1000 + (v[1] - '0') * 100
 	tm.tm_year = (v[0] - '0') * 1000 + (v[1] - '0') * 100
 	    + (v[2] - '0') * 10 + (v[3] - '0')
 	    + (v[2] - '0') * 10 + (v[3] - '0')
@@ -3121,7 +3135,10 @@ isodate17(const unsigned char *v)
 		tm.tm_hour -= offset / 4;
 		tm.tm_hour -= offset / 4;
 		tm.tm_min -= (offset % 4) * 15;
 		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
 static time_t
@@ -3135,7 +3152,8 @@ time_from_tm(struct tm *t)
 #else
 #else
 	/* Else use direct calculation using POSIX assumptions. */
 	/* Else use direct calculation using POSIX assumptions. */
 	/* First, fix up tm_yday based on the year/month/day. */
 	/* 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. */
 	/* Then we can compute timegm() from first principles. */
 	return (t->tm_sec + t->tm_min * 60 + t->tm_hour * 3600
 	return (t->tm_sec + t->tm_min * 60 + t->tm_hour * 3600
 	    + t->tm_yday * 86400 + (t->tm_year - 70) * 31536000
 	    + 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,",
 	fprintf(out, " ilv %d,",
 	    toi(isodirrec + DR_interleave_offset, DR_interleave_size));
 	    toi(isodirrec + DR_interleave_offset, DR_interleave_size));
 	fprintf(out, " seq %d,",
 	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:",
 	fprintf(out, " nl %d:",
 	    toi(isodirrec + DR_name_len_offset, DR_name_len_size));
 	    toi(isodirrec + DR_name_len_offset, DR_name_len_size));
 	fprintf(out, " `%.*s'",
 	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
 #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.
  * All rights reserved.
  *
  *
  * Redistribution and use in source and binary forms, with or without
  * 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_dos_time(const unsigned char *);
 static time_t	lha_win_time(uint64_t, long *);
 static time_t	lha_win_time(uint64_t, long *);
 static unsigned char	lha_calcsum(unsigned char, const void *,
 static unsigned char	lha_calcsum(unsigned char, const void *,
-		    int, int);
+		    int, size_t);
 static int	lha_parse_linkname(struct archive_string *,
 static int	lha_parse_linkname(struct archive_string *,
 		    struct archive_string *);
 		    struct archive_string *);
 static int	lha_read_data_none(struct archive_read *, const void **,
 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_read_pt_bitlen(struct lzh_stream *, int start, int end);
 static int	lzh_make_fake_table(struct huffman *, uint16_t);
 static int	lzh_make_fake_table(struct huffman *, uint16_t);
 static int	lzh_make_huffman_table(struct huffman *);
 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);
 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_header,
 	    archive_read_format_lha_read_data,
 	    archive_read_format_lha_read_data,
 	    archive_read_format_lha_read_data_skip,
 	    archive_read_format_lha_read_data_skip,
+	    NULL,
 	    archive_read_format_lha_cleanup);
 	    archive_read_format_lha_cleanup);
 
 
 	if (r != ARCHIVE_OK)
 	if (r != ARCHIVE_OK)
@@ -445,11 +446,13 @@ archive_read_format_lha_options(struct archive_read *a,
 			else
 			else
 				ret = ARCHIVE_FATAL;
 				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
 static int
@@ -696,7 +699,7 @@ archive_read_format_lha_read_header(struct archive_read *a,
 		archive_entry_set_symlink(entry, NULL);
 		archive_entry_set_symlink(entry, NULL);
 	archive_string_free(&linkname);
 	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
 	 * a pathname and a symlink has '\' character, a directory
 	 * separator in DOS/Windows. So we should convert it to '/'.
 	 * 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 */
 	/* Read extended headers */
 	err2 = lha_read_file_extended_header(a, lha, NULL, 2,
 	err2 = lha_read_file_extended_header(a, lha, NULL, 2,
-	    lha->compsize + 2, &extdsize);
+	    (size_t)(lha->compsize + 2), &extdsize);
 	if (err2 < ARCHIVE_WARN)
 	if (err2 < ARCHIVE_WARN)
 		return (err2);
 		return (err2);
 	if (err2 < err)
 	if (err2 < err)
@@ -1444,7 +1447,7 @@ lha_read_data_none(struct archive_read *a, const void **buff,
 		return (ARCHIVE_FATAL);
 		return (ARCHIVE_FATAL);
 	}
 	}
 	if (bytes_avail > lha->entry_bytes_remaining)
 	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->entry_crc_calculated =
 	    lha_crc16(lha->entry_crc_calculated, *buff, bytes_avail);
 	    lha_crc16(lha->entry_crc_calculated, *buff, bytes_avail);
 	*size = bytes_avail;
 	*size = bytes_avail;
@@ -1527,7 +1530,7 @@ lha_read_data_lzh(struct archive_read *a, const void **buff,
 		return (ARCHIVE_FATAL);
 		return (ARCHIVE_FATAL);
 	}
 	}
 	if (bytes_avail > lha->entry_bytes_remaining)
 	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.avail_in = bytes_avail;
 	lha->strm.total_in = 0;
 	lha->strm.total_in = 0;
@@ -1573,7 +1576,7 @@ static int
 archive_read_format_lha_read_data_skip(struct archive_read *a)
 archive_read_format_lha_read_data_skip(struct archive_read *a)
 {
 {
 	struct lha *lha;
 	struct lha *lha;
-	off_t bytes_skipped;
+	int64_t bytes_skipped;
 
 
 	lha = (struct lha *)(a->format->data);
 	lha = (struct lha *)(a->format->data);
 
 
@@ -1632,7 +1635,7 @@ lha_parse_linkname(struct archive_string *linkname,
     struct archive_string *pathname)
     struct archive_string *pathname)
 {
 {
 	char *	linkptr;
 	char *	linkptr;
-	int 	symlen;
+	size_t 	symlen;
 
 
 	linkptr = strchr(pathname->s, '|');
 	linkptr = strchr(pathname->s, '|');
 	if (linkptr != NULL) {
 	if (linkptr != NULL) {
@@ -1687,12 +1690,12 @@ lha_win_time(uint64_t wintime, long *ns)
 }
 }
 
 
 static unsigned char
 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;
 	unsigned char const *p = (unsigned char const *)pp;
 
 
 	p += offset;
 	p += offset;
-	while (--size >= 0)
+	for (;size > 0; --size)
 		sum += *p++;
 		sum += *p++;
 	return (sum);
 	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)
 		if (ds->w_pos - ds->copy_pos <= strm->avail_out)
 			copy_bytes = ds->w_pos - ds->copy_pos;
 			copy_bytes = ds->w_pos - ds->copy_pos;
 		else
 		else
-			copy_bytes = strm->avail_out;
+			copy_bytes = (size_t)strm->avail_out;
 		memcpy(strm->next_out,
 		memcpy(strm->next_out,
 		    ds->w_buff + ds->copy_pos, copy_bytes);
 		    ds->w_buff + ds->copy_pos, copy_bytes);
-		ds->copy_pos += copy_bytes;
+		ds->copy_pos += (int)copy_bytes;
 	} else {
 	} else {
 		if (ds->w_remaining <= strm->avail_out)
 		if (ds->w_remaining <= strm->avail_out)
 			copy_bytes = ds->w_remaining;
 			copy_bytes = ds->w_remaining;
 		else
 		else
-			copy_bytes = strm->avail_out;
+			copy_bytes = (size_t)strm->avail_out;
 		memcpy(strm->next_out,
 		memcpy(strm->next_out,
 		    ds->w_buff + ds->w_size - ds->w_remaining, copy_bytes);
 		    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->next_out += copy_bytes;
 	strm->avail_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;
 			bits = tbl_bits;
 		else
 		else
 			bits = HTBL_BITS;
 			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)
 		if (hf->tbl == NULL)
 			return (ARCHIVE_FATAL);
 			return (ARCHIVE_FATAL);
 	}
 	}
@@ -2489,7 +2492,7 @@ lzh_huffman_init(struct huffman *hf, size_t len_size, int tbl_bits)
 		if (hf->tree == NULL)
 		if (hf->tree == NULL)
 			return (ARCHIVE_FATAL);
 			return (ARCHIVE_FATAL);
 	}
 	}
-	hf->len_size = len_size;
+	hf->len_size = (int)len_size;
 	hf->tbl_bits = tbl_bits;
 	hf->tbl_bits = tbl_bits;
 	return (ARCHIVE_OK);
 	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) 2003-2007 Tim Kientzle
  * Copyright (c) 2008 Joerg Sonnenberger
  * Copyright (c) 2008 Joerg Sonnenberger
- * Copyright (c) 2011 Michihiro NAKAJIMA
+ * Copyright (c) 2011-2012 Michihiro NAKAJIMA
  * All rights reserved.
  * All rights reserved.
  *
  *
  * Redistribution and use in source and binary forms, with or without
  * 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
 #ifndef O_BINARY
 #define	O_BINARY 0
 #define	O_BINARY 0
 #endif
 #endif
+#ifndef O_CLOEXEC
+#define O_CLOEXEC	0
+#endif
 
 
 #define	MTREE_HAS_DEVICE	0x0001
 #define	MTREE_HAS_DEVICE	0x0001
 #define	MTREE_HAS_FFLAGS	0x0002
 #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_UNAME		0x0400
 
 
 #define	MTREE_HAS_OPTIONAL	0x0800
 #define	MTREE_HAS_OPTIONAL	0x0800
+#define	MTREE_HAS_NOCHANGE	0x1000 /* FreeBSD specific */
 
 
 struct mtree_option {
 struct mtree_option {
 	struct mtree_option *next;
 	struct mtree_option *next;
@@ -101,7 +105,9 @@ struct mtree {
 	int64_t			 cur_size;
 	int64_t			 cur_size;
 };
 };
 
 
+static int	bid_keycmp(const char *, const char *, ssize_t);
 static int	cleanup(struct archive_read *);
 static int	cleanup(struct archive_read *);
+static int	detect_form(struct archive_read *, int *);
 static int	mtree_bid(struct archive_read *, int);
 static int	mtree_bid(struct archive_read *, int);
 static int	parse_file(struct archive_read *, struct archive_entry *,
 static int	parse_file(struct archive_read *, struct archive_entry *,
 		    struct mtree *, struct mtree_entry *, int *);
 		    struct mtree *, struct mtree_entry *, int *);
@@ -199,7 +205,7 @@ archive_read_support_format_mtree(struct archive *_a)
 	mtree->fd = -1;
 	mtree->fd = -1;
 
 
 	r = __archive_read_register_format(a, mtree, "mtree",
 	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)
 	if (r != ARCHIVE_OK)
 		free(mtree);
 		free(mtree);
@@ -317,7 +323,7 @@ next_line(struct archive_read *a,
  * Returns the length of a mtree keyword if matched.
  * Returns the length of a mtree keyword if matched.
  * Returns 0 if not matched.
  * Returns 0 if not matched.
  */
  */
-int
+static int
 bid_keycmp(const char *p, const char *key, ssize_t len)
 bid_keycmp(const char *p, const char *key, ssize_t len)
 {
 {
 	int match_len = 0;
 	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 the length of a detected keyword.
  * Returns 0 if any keywords were not found.
  * Returns 0 if any keywords were not found.
  */
  */
-static ssize_t
+static int
 bid_keyword(const char *p,  ssize_t len)
 bid_keyword(const char *p,  ssize_t len)
 {
 {
 	static const char *keys_c[] = {
 	static const char *keys_c[] = {
@@ -367,7 +373,7 @@ bid_keyword(const char *p,  ssize_t len)
 		"md5", "md5digest", "mode", NULL
 		"md5", "md5digest", "mode", NULL
 	};
 	};
 	static const char *keys_no[] = {
 	static const char *keys_no[] = {
-		"nlink", "optional", NULL
+		"nlink", "nochange", "optional", NULL
 	};
 	};
 	static const char *keys_r[] = {
 	static const char *keys_r[] = {
 		"rmd160", "rmd160digest", NULL
 		"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".
  * When "unset" is specified, expects a set of "<space characters>keyword".
  */
  */
 static int
 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 l;
 	int keycnt = 0;
 	int keycnt = 0;
@@ -436,8 +442,10 @@ bid_keyword_list(const char *p,  ssize_t len, int unset)
 			break;
 			break;
 		if (p[0] == '\\' && (p[1] == '\n' || p[1] == '\r'))
 		if (p[0] == '\\' && (p[1] == '\n' || p[1] == '\r'))
 			break;
 			break;
-		if (!blank) /* No blank character. */
+		if (!blank && !last_is_path) /* No blank character. */
 			return (-1);
 			return (-1);
+		if (last_is_path && len == 0)
+				return (keycnt);
 
 
 		if (unset) {
 		if (unset) {
 			l = bid_keycmp(p, "all", len);
 			l = bid_keycmp(p, "all", len);
@@ -472,7 +480,7 @@ bid_keyword_list(const char *p,  ssize_t len, int unset)
 }
 }
 
 
 static int
 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;
 	int f = 0;
 	static const unsigned char safe_char[256] = {
 	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, /* E0 - EF */
 		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* F0 - FF */
 		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.
 	 * 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;
 		++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
 #define MAX_BID_ENTRY	3
@@ -524,14 +570,11 @@ mtree_bid(struct archive_read *a, int best_bid)
 {
 {
 	const char *signature = "#mtree";
 	const char *signature = "#mtree";
 	const char *p;
 	const char *p;
-	ssize_t avail, ravail;
-	ssize_t len, nl;
-	int detected_bytes = 0, entry_cnt = 0, multiline = 0;
 
 
 	(void)best_bid; /* UNUSED */
 	(void)best_bid; /* UNUSED */
 
 
 	/* Now let's look at the actual header and see if it matches. */
 	/* 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)
 	if (p == NULL)
 		return (-1);
 		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.
 	 * 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;
 	ravail = avail;
 	for (;;) {
 	for (;;) {
 		len = next_line(a, &p, &avail, &ravail, &nl);
 		len = next_line(a, &p, &avail, &ravail, &nl);
@@ -565,7 +626,7 @@ mtree_bid(struct archive_read *a, int best_bid)
 		} else {
 		} else {
 			/* A continuance line; the terminal
 			/* A continuance line; the terminal
 			 * character of previous line was '\' character. */
 			 * character of previous line was '\' character. */
-			if (bid_keyword_list(p, len, 0) <= 0)
+			if (bid_keyword_list(p, len, 0, 0) <= 0)
 				break;
 				break;
 			if (multiline == 1)
 			if (multiline == 1)
 				detected_bytes += len;
 				detected_bytes += len;
@@ -580,9 +641,25 @@ mtree_bid(struct archive_read *a, int best_bid)
 			continue;
 			continue;
 		}
 		}
 		if (p[0] != '/') {
 		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;
 				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. */
 					/* This line continues. */
 					multiline = 1;
 					multiline = 1;
 				else {
 				else {
@@ -595,13 +672,13 @@ mtree_bid(struct archive_read *a, int best_bid)
 			} else
 			} else
 				break;
 				break;
 		} else if (strncmp(p, "/set", 4) == 0) {
 		} 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;
 				break;
 			/* This line continues. */
 			/* This line continues. */
 			if (p[len-nl-1] == '\\')
 			if (p[len-nl-1] == '\\')
 				multiline = 2;
 				multiline = 2;
 		} else if (strncmp(p, "/unset", 6) == 0) {
 		} 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;
 				break;
 			/* This line continues. */
 			/* This line continues. */
 			if (p[len-nl-1] == '\\')
 			if (p[len-nl-1] == '\\')
@@ -613,8 +690,13 @@ mtree_bid(struct archive_read *a, int best_bid)
 		p += len;
 		p += len;
 		avail -= 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 (32);
+	}
 
 
 	return (0);
 	return (0);
 }
 }
@@ -738,12 +820,12 @@ process_global_unset(struct archive_read *a,
 
 
 static int
 static int
 process_add_entry(struct archive_read *a, struct mtree *mtree,
 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_entry *entry;
 	struct mtree_option *iter;
 	struct mtree_option *iter;
-	const char *next, *eq;
+	const char *next, *eq, *name, *end;
 	size_t len;
 	size_t len;
 	int r;
 	int r;
 
 
@@ -764,17 +846,46 @@ process_add_entry(struct archive_read *a, struct mtree *mtree,
 		(*last_entry)->next = entry;
 		(*last_entry)->next = entry;
 	*last_entry = 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) {
 	if ((entry->name = malloc(len + 1)) == NULL) {
 		archive_set_error(&a->archive, errno, "Can't allocate memory");
 		archive_set_error(&a->archive, errno, "Can't allocate memory");
 		return (ARCHIVE_FATAL);
 		return (ARCHIVE_FATAL);
 	}
 	}
 
 
-	memcpy(entry->name, line, len);
+	memcpy(entry->name, name, len);
 	entry->name[len] = '\0';
 	entry->name[len] = '\0';
 	parse_escapes(entry->name, entry);
 	parse_escapes(entry->name, entry);
 
 
-	line += len;
 	for (iter = *global; iter != NULL; iter = iter->next) {
 	for (iter = *global; iter != NULL; iter = iter->next) {
 		r = add_option(a, &entry->options, iter->value,
 		r = add_option(a, &entry->options, iter->value,
 		    strlen(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");
 		next = line + strspn(line, " \t\r\n");
 		if (*next == '\0')
 		if (*next == '\0')
 			return (ARCHIVE_OK);
 			return (ARCHIVE_OK);
+		if (next >= end)
+			return (ARCHIVE_OK);
 		line = next;
 		line = next;
 		next = line + strcspn(line, " \t\r\n");
 		next = line + strcspn(line, " \t\r\n");
 		eq = strchr(line, '=');
 		eq = strchr(line, '=');
@@ -810,7 +923,7 @@ read_mtree(struct archive_read *a, struct mtree *mtree)
 	char *p;
 	char *p;
 	struct mtree_option *global;
 	struct mtree_option *global;
 	struct mtree_entry *last_entry;
 	struct mtree_entry *last_entry;
-	int r;
+	int r, is_form_d;
 
 
 	mtree->archive_format = ARCHIVE_FORMAT_MTREE;
 	mtree->archive_format = ARCHIVE_FORMAT_MTREE;
 	mtree->archive_format_name = "mtree";
 	mtree->archive_format_name = "mtree";
@@ -818,6 +931,8 @@ read_mtree(struct archive_read *a, struct mtree *mtree)
 	global = NULL;
 	global = NULL;
 	last_entry = NULL;
 	last_entry = NULL;
 
 
+	(void)detect_form(a, &is_form_d);
+
 	for (counter = 1; ; ++counter) {
 	for (counter = 1; ; ++counter) {
 		len = readline(a, mtree, &p, 65536);
 		len = readline(a, mtree, &p, 65536);
 		if (len == 0) {
 		if (len == 0) {
@@ -827,7 +942,7 @@ read_mtree(struct archive_read *a, struct mtree *mtree)
 		}
 		}
 		if (len < 0) {
 		if (len < 0) {
 			free_options(global);
 			free_options(global);
-			return (len);
+			return ((int)len);
 		}
 		}
 		/* Leading whitespace is never significant, ignore it. */
 		/* Leading whitespace is never significant, ignore it. */
 		while (*p == ' ' || *p == '\t') {
 		while (*p == ' ' || *p == '\t') {
@@ -840,8 +955,8 @@ read_mtree(struct archive_read *a, struct mtree *mtree)
 		if (*p == '\r' || *p == '\n' || *p == '\0')
 		if (*p == '\r' || *p == '\n' || *p == '\0')
 			continue;
 			continue;
 		if (*p != '/') {
 		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) {
 		} else if (strncmp(p, "/set", 4) == 0) {
 			if (p[4] != ' ' && p[4] != '\t')
 			if (p[4] != ' ' && p[4] != '\t')
 				break;
 				break;
@@ -1007,7 +1122,8 @@ parse_file(struct archive_read *a, struct archive_entry *entry,
 
 
 	if (archive_entry_filetype(entry) == AE_IFREG ||
 	if (archive_entry_filetype(entry) == AE_IFREG ||
 	    archive_entry_filetype(entry) == AE_IFDIR) {
 	    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 &&
 		if (mtree->fd == -1 &&
 		    (errno != ENOENT ||
 		    (errno != ENOENT ||
 		     archive_strlen(&mtree->contents_name) > 0)) {
 		     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 it wasn't already parsed from the specification.
 	 */
 	 */
 	if (st != NULL) {
 	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_IFCHR ||
 		     archive_entry_filetype(entry) == AE_IFBLK))
 		     archive_entry_filetype(entry) == AE_IFBLK))
 			archive_entry_set_rdev(entry, st->st_rdev);
 			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);
 			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);
 			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
 #if HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC
 			archive_entry_set_mtime(entry, st->st_mtime,
 			archive_entry_set_mtime(entry, st->st_mtime,
 			    st->st_mtimespec.tv_nsec);
 			    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);
 			archive_entry_set_mtime(entry, st->st_mtime, 0);
 #endif
 #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);
 			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);
 			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_size(entry, st->st_size);
 		archive_entry_set_ino(entry, st->st_ino);
 		archive_entry_set_ino(entry, st->st_ino);
 		archive_entry_set_dev(entry, st->st_dev);
 		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, ',');
 	comma1 = strchr(val, ',');
 	if (comma1 == NULL) {
 	if (comma1 == NULL) {
-		archive_entry_set_dev(entry, mtree_atol10(&val));
+		archive_entry_set_dev(entry, (dev_t)mtree_atol10(&val));
 		return (ARCHIVE_OK);
 		return (ARCHIVE_OK);
 	}
 	}
 	++comma1;
 	++comma1;
@@ -1193,8 +1316,8 @@ parse_device(struct archive *a, struct archive_entry *entry, char *val)
 		return (ARCHIVE_WARN);
 		return (ARCHIVE_WARN);
 	}
 	}
 	++comma2;
 	++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);
 	return (ARCHIVE_OK);
 }
 }
 
 
@@ -1212,6 +1335,10 @@ parse_keyword(struct archive_read *a, struct mtree *mtree,
 	if (*key == '\0')
 	if (*key == '\0')
 		return (ARCHIVE_OK);
 		return (ARCHIVE_OK);
 
 
+	if (strcmp(key, "nochange") == 0) {
+		*parsed_kws |= MTREE_HAS_NOCHANGE;
+		return (ARCHIVE_OK);
+	}
 	if (strcmp(key, "optional") == 0) {
 	if (strcmp(key, "optional") == 0) {
 		*parsed_kws |= MTREE_HAS_OPTIONAL;
 		*parsed_kws |= MTREE_HAS_OPTIONAL;
 		return (ARCHIVE_OK);
 		return (ARCHIVE_OK);
@@ -1279,7 +1406,7 @@ parse_keyword(struct archive_read *a, struct mtree *mtree,
 			if (val[0] >= '0' && val[0] <= '9') {
 			if (val[0] >= '0' && val[0] <= '9') {
 				*parsed_kws |= MTREE_HAS_PERM;
 				*parsed_kws |= MTREE_HAS_PERM;
 				archive_entry_set_perm(entry,
 				archive_entry_set_perm(entry,
-				    mtree_atol8(&val));
+				    (mode_t)mtree_atol8(&val));
 			} else {
 			} else {
 				archive_set_error(&a->archive,
 				archive_set_error(&a->archive,
 				    ARCHIVE_ERRNO_FILE_FORMAT,
 				    ARCHIVE_ERRNO_FILE_FORMAT,
@@ -1291,7 +1418,8 @@ parse_keyword(struct archive_read *a, struct mtree *mtree,
 	case 'n':
 	case 'n':
 		if (strcmp(key, "nlink") == 0) {
 		if (strcmp(key, "nlink") == 0) {
 			*parsed_kws |= MTREE_HAS_NLINK;
 			*parsed_kws |= MTREE_HAS_NLINK;
-			archive_entry_set_nlink(entry, mtree_atol10(&val));
+			archive_entry_set_nlink(entry,
+				(unsigned int)mtree_atol10(&val));
 			break;
 			break;
 		}
 		}
 	case 'r':
 	case 'r':
@@ -1433,7 +1561,7 @@ read_data(struct archive_read *a, const void **buff, size_t *size, int64_t *offs
 	*buff = mtree->buff;
 	*buff = mtree->buff;
 	*offset = mtree->offset;
 	*offset = mtree->offset;
 	if ((int64_t)mtree->buffsize > mtree->cur_size - 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
 	else
 		bytes_to_read = mtree->buffsize;
 		bytes_to_read = mtree->buffsize;
 	bytes_read = read(mtree->fd, mtree->buff, bytes_to_read);
 	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
 #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.
  * the best size of the output buffer(uncompressed buffer) is 128K.
  * If the structure of extracting process is changed, this value
  * If the structure of extracting process is changed, this value
  * might be researched again.
  * might be researched again.
@@ -199,6 +199,13 @@ struct lzss
   int64_t position;
   int64_t position;
 };
 };
 
 
+struct data_block_offsets
+{
+  int64_t header_size;
+  int64_t start_offset;
+  int64_t end_offset;
+};
+
 struct rar
 struct rar
 {
 {
   /* Entries from main RAR header */
   /* Entries from main RAR header */
@@ -217,6 +224,7 @@ struct rar
   long mnsec;
   long mnsec;
   mode_t mode;
   mode_t mode;
   char *filename;
   char *filename;
+  char *filename_save;
   size_t filename_allocated;
   size_t filename_allocated;
 
 
   /* File header optional entries */
   /* File header optional entries */
@@ -234,6 +242,7 @@ struct rar
   int64_t bytes_uncopied;
   int64_t bytes_uncopied;
   int64_t offset;
   int64_t offset;
   int64_t offset_outgoing;
   int64_t offset_outgoing;
+  int64_t offset_seek;
   char valid;
   char valid;
   unsigned int unp_offset;
   unsigned int unp_offset;
   unsigned int unp_buffer_size;
   unsigned int unp_buffer_size;
@@ -243,6 +252,10 @@ struct rar
   char entry_eof;
   char entry_eof;
   unsigned long crc_calculated;
   unsigned long crc_calculated;
   int found_first_header;
   int found_first_header;
+  char has_endarc_header;
+  struct data_block_offsets *dbo;
+  unsigned int cursor;
+  unsigned int nodes;
 
 
   /* LZSS members */
   /* LZSS members */
   struct huffman_code maincode;
   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 *,
 static int archive_read_format_rar_read_data(struct archive_read *,
     const void **, size_t *, int64_t *);
     const void **, size_t *, int64_t *);
 static int archive_read_format_rar_read_data_skip(struct archive_read *a);
 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 *);
 static int archive_read_format_rar_cleanup(struct archive_read *);
 
 
 /* Support functions */
 /* Support functions */
 static int read_header(struct archive_read *, struct archive_entry *, char);
 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_exttime(const char *, struct rar *, const char *);
 static int read_symlink_stored(struct archive_read *, struct archive_entry *,
 static int read_symlink_stored(struct archive_read *, struct archive_entry *,
                                struct archive_string_conv *);
                                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 int64_t expand(struct archive_read *, int64_t);
 static int copy_from_lzss_window(struct archive_read *, const void **,
 static int copy_from_lzss_window(struct archive_read *, const void **,
                                    int64_t, int);
                                    int64_t, int);
+static const void *rar_read_ahead(struct archive_read *, size_t, ssize_t *);
 
 
 /*
 /*
  * Bit stream reader.
  * 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);
         __archive_read_consume(a, rar->bytes_unconsumed);
         rar->bytes_unconsumed = 0;
         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)
       if (br->next_in == NULL)
         return (0);
         return (0);
-      if (br->avail_in > rar->bytes_remaining)
-        br->avail_in = rar->bytes_remaining;
       if (br->avail_in == 0)
       if (br->avail_in == 0)
         return (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);
   struct rar *rar = (struct rar *)(a->format->data);
 
 
   if (rar->bytes_remaining > 0) {
   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) {
     if (br->next_in == NULL) {
       archive_set_error(&a->archive,
       archive_set_error(&a->archive,
           ARCHIVE_ERRNO_FILE_FORMAT,
           ARCHIVE_ERRNO_FILE_FORMAT,
           "Truncated RAR file data");
           "Truncated RAR file data");
       return (ARCHIVE_FATAL);
       return (ARCHIVE_FATAL);
     }
     }
-    if (br->avail_in > rar->bytes_remaining)
-      br->avail_in = rar->bytes_remaining;
     if (br->cache_avail == 0)
     if (br->cache_avail == 0)
       (void)rar_br_fillup(a, br);
       (void)rar_br_fillup(a, br);
   }
   }
@@ -522,7 +534,7 @@ lzss_size(struct lzss *lzss)
 static inline int
 static inline int
 lzss_offset_for_position(struct lzss *lzss, int64_t pos)
 lzss_offset_for_position(struct lzss *lzss, int64_t pos)
 {
 {
-  return pos & lzss->mask;
+  return (int)(pos & lzss->mask);
 }
 }
 
 
 static inline unsigned char *
 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_header,
                                      archive_read_format_rar_read_data,
                                      archive_read_format_rar_read_data,
                                      archive_read_format_rar_read_data_skip,
                                      archive_read_format_rar_read_data_skip,
+                                     archive_read_format_rar_seek_data,
                                      archive_read_format_rar_cleanup);
                                      archive_read_format_rar_cleanup);
 
 
   if (r != ARCHIVE_OK)
   if (r != ARCHIVE_OK)
@@ -757,11 +770,13 @@ archive_read_format_rar_options(struct archive_read *a,
       else
       else
         ret = ARCHIVE_FATAL;
         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
 static int
@@ -842,13 +857,6 @@ archive_read_format_rar_read_header(struct archive_read *a,
                             sizeof(rar->reserved2));
                             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)
       if (rar->main_flags & MHD_PASSWORD)
       {
       {
         archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
         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);
         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)) {
       if ((crc32_val & 0xffff) != archive_le16dec(p)) {
         archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
         archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
           "Header CRC error");
           "Header CRC error");
@@ -873,6 +881,7 @@ archive_read_format_rar_read_header(struct archive_read *a,
     case SUB_HEAD:
     case SUB_HEAD:
     case PROTECT_HEAD:
     case PROTECT_HEAD:
     case SIGN_HEAD:
     case SIGN_HEAD:
+    case ENDARC_HEAD:
       flags = archive_le16dec(p + 3);
       flags = archive_le16dec(p + 3);
       skip = archive_le16dec(p + 5);
       skip = archive_le16dec(p + 5);
       if (skip < 7) {
       if (skip < 7) {
@@ -898,13 +907,15 @@ archive_read_format_rar_read_header(struct archive_read *a,
         p = h;
         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)) {
       if ((crc32_val & 0xffff) != archive_le16dec(p)) {
         archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
         archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
           "Header CRC error");
           "Header CRC error");
         return (ARCHIVE_FATAL);
         return (ARCHIVE_FATAL);
       }
       }
       __archive_read_consume(a, skip);
       __archive_read_consume(a, skip);
+      if (head_type == ENDARC_HEAD)
+        return (ARCHIVE_EOF);
       break;
       break;
 
 
     case NEWSUB_HEAD:
     case NEWSUB_HEAD:
@@ -912,9 +923,6 @@ archive_read_format_rar_read_header(struct archive_read *a,
         return ret;
         return ret;
       break;
       break;
 
 
-    case ENDARC_HEAD:
-      return (ARCHIVE_EOF);
-
     default:
     default:
       archive_set_error(&a->archive,  ARCHIVE_ERRNO_FILE_FORMAT,
       archive_set_error(&a->archive,  ARCHIVE_ERRNO_FILE_FORMAT,
                         "Bad RAR file");
                         "Bad RAR file");
@@ -936,10 +944,12 @@ archive_read_format_rar_read_data(struct archive_read *a, const void **buff,
       rar->bytes_unconsumed = 0;
       rar->bytes_unconsumed = 0;
   }
   }
 
 
-  if (rar->entry_eof) {
+  if (rar->entry_eof || rar->offset_seek >= rar->unp_size) {
     *buff = NULL;
     *buff = NULL;
     *size = 0;
     *size = 0;
     *offset = rar->offset;
     *offset = rar->offset;
+    if (*offset < rar->unp_size)
+      *offset = rar->unp_size;
     return (ARCHIVE_EOF);
     return (ARCHIVE_EOF);
   }
   }
 
 
@@ -973,6 +983,7 @@ archive_read_format_rar_read_data_skip(struct archive_read *a)
 {
 {
   struct rar *rar;
   struct rar *rar;
   int64_t bytes_skipped;
   int64_t bytes_skipped;
+  int ret;
 
 
   rar = (struct rar *)(a->format->data);
   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)
     if (bytes_skipped < 0)
       return (ARCHIVE_FATAL);
       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);
   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
 static int
 archive_read_format_rar_cleanup(struct archive_read *a)
 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);
   rar = (struct rar *)(a->format->data);
   free_codes(a);
   free_codes(a);
   free(rar->filename);
   free(rar->filename);
+  free(rar->filename_save);
+  free(rar->dbo);
   free(rar->unp_buffer);
   free(rar->unp_buffer);
   free(rar->lzss.window);
   free(rar->lzss.window);
   __archive_ppmd7_functions.Ppmd7_Free(&rar->ppmd7_context, &g_szalloc);
   __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 *strp;
   char packed_size[8];
   char packed_size[8];
   char unp_size[8];
   char unp_size[8];
-  int time;
+  int ttime;
   struct archive_string_conv *sconv, *fn_sconv;
   struct archive_string_conv *sconv, *fn_sconv;
   unsigned long crc32_val;
   unsigned long crc32_val;
   int ret = (ARCHIVE_OK), ret2;
   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));
   memcpy(&rar_header, p, sizeof(rar_header));
   rar->file_flags = archive_le16dec(rar_header.flags);
   rar->file_flags = archive_le16dec(rar_header.flags);
   header_size = archive_le16dec(rar_header.size);
   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,
     archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
       "Invalid header size");
       "Invalid header size");
     return (ARCHIVE_FATAL);
     return (ARCHIVE_FATAL);
@@ -1082,11 +1265,11 @@ read_header(struct archive_read *a, struct archive_entry *entry,
     return (ARCHIVE_FATAL);
     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);
     return (ARCHIVE_FATAL);
 
 
   /* File Header CRC check. */
   /* 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)) {
   if ((crc32_val & 0xffff) != archive_le16dec(rar_header.crc)) {
     archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
     archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
       "Header CRC error");
       "Header CRC error");
@@ -1100,8 +1283,8 @@ read_header(struct archive_read *a, struct archive_entry *entry,
 
 
   rar->compression_method = file_header.method;
   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);
   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);
     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)
   if (rar->packed_size < 0 || rar->unp_size < 0)
   {
   {
     archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
     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);
     return (ARCHIVE_FATAL);
   }
   }
 
 
+  rar->bytes_remaining = rar->packed_size;
+
   /* TODO: RARv3 subblocks contain comments. For now the complete block is
   /* TODO: RARv3 subblocks contain comments. For now the complete block is
    * consumed at the end.
    * 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;
     size_t distance = p - (const char *)h;
     header_size += rar->packed_size;
     header_size += rar->packed_size;
     /* Make sure we have the extended data. */
     /* 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);
         return (ARCHIVE_FATAL);
     p = h;
     p = h;
     endp = p + header_size - 7;
     endp = p + header_size - 7;
@@ -1159,13 +1341,17 @@ read_header(struct archive_read *a, struct archive_entry *entry,
       "Invalid filename size");
       "Invalid filename size");
     return (ARCHIVE_FATAL);
     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,
       archive_set_error(&a->archive, ENOMEM,
                         "Couldn't allocate memory.");
                         "Couldn't allocate memory.");
       return (ARCHIVE_FATAL);
       return (ARCHIVE_FATAL);
     }
     }
+    rar->filename = newptr;
+    rar->filename_allocated = newsize;
   }
   }
   filename = rar->filename;
   filename = rar->filename;
   memcpy(filename, p, filename_size);
   memcpy(filename, p, filename_size);
@@ -1174,15 +1360,17 @@ read_header(struct archive_read *a, struct archive_entry *entry,
   {
   {
     if (filename_size != strlen(filename))
     if (filename_size != strlen(filename))
     {
     {
-      unsigned char highbyte, flagbits, flagbyte, length, offset;
+      unsigned char highbyte, flagbits, flagbyte;
+      unsigned fn_end, offset;
 
 
       end = filename_size;
       end = filename_size;
+      fn_end = filename_size * 2;
       filename_size = 0;
       filename_size = 0;
-      offset = strlen(filename) + 1;
+      offset = (unsigned)strlen(filename) + 1;
       highbyte = *(p + offset++);
       highbyte = *(p + offset++);
       flagbits = 0;
       flagbits = 0;
       flagbyte = 0;
       flagbyte = 0;
-      while (offset < end && filename_size < end)
+      while (offset < end && filename_size < fn_end)
       {
       {
         if (!flagbits)
         if (!flagbits)
         {
         {
@@ -1208,19 +1396,26 @@ read_header(struct archive_read *a, struct archive_entry *entry,
             break;
             break;
           case 3:
           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--;
               length--;
             }
             }
           }
           }
           break;
           break;
         }
         }
       }
       }
-      if (filename_size >= end) {
+      if (filename_size > fn_end) {
         archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
         archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
           "Invalid filename");
           "Invalid filename");
         return (ARCHIVE_FATAL);
         return (ARCHIVE_FATAL);
@@ -1272,6 +1467,51 @@ read_header(struct archive_read *a, struct archive_entry *entry,
     p += filename_size;
     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 (rar->file_flags & FHD_SALT)
   {
   {
     if (p + 8 > endp) {
     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);
   __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)
   switch(file_header.host_os)
   {
   {
@@ -1318,9 +1560,10 @@ read_header(struct archive_read *a, struct archive_entry *entry,
     return (ARCHIVE_FATAL);
     return (ARCHIVE_FATAL);
   }
   }
 
 
-  rar->bytes_remaining = rar->packed_size;
   rar->bytes_uncopied = rar->bytes_unconsumed = 0;
   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->offset_outgoing = 0;
   rar->br.cache_avail = 0;
   rar->br.cache_avail = 0;
   rar->br.avail_in = 0;
   rar->br.avail_in = 0;
@@ -1381,15 +1624,15 @@ read_header(struct archive_read *a, struct archive_entry *entry,
 }
 }
 
 
 static time_t
 static time_t
-get_time(int time)
+get_time(int ttime)
 {
 {
   struct tm tm;
   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;
   tm.tm_isdst = -1;
   return mktime(&tm);
   return mktime(&tm);
 }
 }
@@ -1398,7 +1641,7 @@ static int
 read_exttime(const char *p, struct rar *rar, const char *endp)
 read_exttime(const char *p, struct rar *rar, const char *endp)
 {
 {
   unsigned rmode, flags, rem, j, count;
   unsigned rmode, flags, rem, j, count;
-  int time, i;
+  int ttime, i;
   struct tm *tm;
   struct tm *tm;
   time_t t;
   time_t t;
   long nsec;
   long nsec;
@@ -1420,8 +1663,8 @@ read_exttime(const char *p, struct rar *rar, const char *endp)
       {
       {
         if (p + 4 > endp)
         if (p + 4 > endp)
           return (-1);
           return (-1);
-        time = archive_le32dec(p);
-        t = get_time(time);
+        ttime = archive_le32dec(p);
+        t = get_time(ttime);
         p += 4;
         p += 4;
       }
       }
       rem = 0;
       rem = 0;
@@ -1475,11 +1718,12 @@ read_symlink_stored(struct archive_read *a, struct archive_entry *entry,
   int ret = (ARCHIVE_OK);
   int ret = (ARCHIVE_OK);
 
 
   rar = (struct rar *)(a->format->data);
   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);
     return (ARCHIVE_FATAL);
   p = h;
   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)
     if (errno == ENOMEM)
     {
     {
@@ -1504,7 +1748,8 @@ read_data_stored(struct archive_read *a, const void **buff, size_t *size,
   ssize_t bytes_avail;
   ssize_t bytes_avail;
 
 
   rar = (struct rar *)(a->format->data);
   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;
     *buff = NULL;
     *size = 0;
     *size = 0;
@@ -1518,23 +1763,23 @@ read_data_stored(struct archive_read *a, const void **buff, size_t *size,
     return (ARCHIVE_EOF);
     return (ARCHIVE_EOF);
   }
   }
 
 
-  *buff = __archive_read_ahead(a, 1, &bytes_avail);
+  *buff = rar_read_ahead(a, 1, &bytes_avail);
   if (bytes_avail <= 0)
   if (bytes_avail <= 0)
   {
   {
     archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
     archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
                       "Truncated RAR file data");
                       "Truncated RAR file data");
     return (ARCHIVE_FATAL);
     return (ARCHIVE_FATAL);
   }
   }
-  if (bytes_avail > rar->bytes_remaining)
-    bytes_avail = rar->bytes_remaining;
 
 
   *size = bytes_avail;
   *size = bytes_avail;
   *offset = rar->offset;
   *offset = rar->offset;
   rar->offset += bytes_avail;
   rar->offset += bytes_avail;
+  rar->offset_seek += bytes_avail;
   rar->bytes_remaining -= bytes_avail;
   rar->bytes_remaining -= bytes_avail;
   rar->bytes_unconsumed = bytes_avail;
   rar->bytes_unconsumed = bytes_avail;
   /* Calculate File CRC. */
   /* 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);
   return (ARCHIVE_OK);
 }
 }
 
 
@@ -1564,7 +1809,8 @@ read_data_compressed(struct archive_read *a, const void **buff, size_t *size,
         *offset = rar->offset_outgoing;
         *offset = rar->offset_outgoing;
         rar->offset_outgoing += *size;
         rar->offset_outgoing += *size;
         /* Calculate File CRC. */
         /* 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;
         rar->unp_offset = 0;
         return (ARCHIVE_OK);
         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))
       if (rar->bytes_uncopied > (rar->unp_buffer_size - rar->unp_offset))
         bs = rar->unp_buffer_size - rar->unp_offset;
         bs = rar->unp_buffer_size - rar->unp_offset;
       else
       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)
       if (ret != ARCHIVE_OK)
         return (ret);
         return (ret);
       rar->offset += bs;
       rar->offset += bs;
@@ -1597,7 +1843,8 @@ read_data_compressed(struct archive_read *a, const void **buff, size_t *size,
         *offset = rar->offset_outgoing;
         *offset = rar->offset_outgoing;
         rar->offset_outgoing += *size;
         rar->offset_outgoing += *size;
         /* Calculate File CRC. */
         /* Calculate File CRC. */
-        rar->crc_calculated = crc32(rar->crc_calculated, *buff, *size);
+        rar->crc_calculated = crc32(rar->crc_calculated, *buff,
+          (unsigned)*size);
         return (ret);
         return (ret);
       }
       }
       continue;
       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))
     if (rar->bytes_uncopied > (rar->unp_buffer_size - rar->unp_offset))
       bs = rar->unp_buffer_size - rar->unp_offset;
       bs = rar->unp_buffer_size - rar->unp_offset;
     else
     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)
     if (ret != ARCHIVE_OK)
       return (ret);
       return (ret);
     rar->offset += bs;
     rar->offset += bs;
@@ -1730,7 +1977,7 @@ read_data_compressed(struct archive_read *a, const void **buff, size_t *size,
   *offset = rar->offset_outgoing;
   *offset = rar->offset_outgoing;
   rar->offset_outgoing += *size;
   rar->offset_outgoing += *size;
   /* Calculate File CRC. */
   /* Calculate File CRC. */
-  rar->crc_calculated = crc32(rar->crc_calculated, *buff, *size);
+  rar->crc_calculated = crc32(rar->crc_calculated, *buff, (unsigned)*size);
   return ret;
   return ret;
 }
 }
 
 
@@ -1973,17 +2220,21 @@ parse_codes(struct archive_read *a)
     /* Seems as though dictionary sizes are not used. Even so, minimize
     /* Seems as though dictionary sizes are not used. Even so, minimize
      * memory usage as much as possible.
      * memory usage as much as possible.
      */
      */
+    void *new_window;
+    unsigned int new_size;
+
     if (rar->unp_size >= DICTIONARY_MAX_SIZE)
     if (rar->unp_size >= DICTIONARY_MAX_SIZE)
-      rar->dictionary_size = DICTIONARY_MAX_SIZE;
+      new_size = DICTIONARY_MAX_SIZE;
     else
     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,
       archive_set_error(&a->archive, ENOMEM,
                         "Unable to allocate memory for uncompressed data.");
                         "Unable to allocate memory for uncompressed data.");
       return (ARCHIVE_FATAL);
       return (ARCHIVE_FATAL);
     }
     }
+    rar->lzss.window = (unsigned char *)new_window;
+    rar->dictionary_size = new_size;
     memset(rar->lzss.window, 0, rar->dictionary_size);
     memset(rar->lzss.window, 0, rar->dictionary_size);
     rar->lzss.mask = rar->dictionary_size - 1;
     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
 static int
 new_node(struct huffman_code *code)
 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);
     return (-1);
+  code->tree = (struct huffman_tree_node *)new_tree;
   code->tree[code->numentries].branches[0] = -1;
   code->tree[code->numentries].branches[0] = -1;
   code->tree[code->numentries].branches[1] = -2;
   code->tree[code->numentries].branches[1] = -2;
   return 1;
   return 1;
@@ -2239,8 +2492,8 @@ make_table(struct archive_read *a, struct huffman_code *code)
     code->tablesize = code->maxlength;
     code->tablesize = code->maxlength;
 
 
   code->table =
   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);
   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)
       if ((lensymbol = read_next_symbol(a, &rar->lengthcode)) < 0)
         goto bad_data;
         goto bad_data;
-      if (lensymbol > sizeof(lengthbases)/sizeof(lengthbases[0]))
+      if (lensymbol > (int)(sizeof(lengthbases)/sizeof(lengthbases[0])))
         goto bad_data;
         goto bad_data;
-      if (lensymbol > sizeof(lengthbits)/sizeof(lengthbits[0]))
+      if (lensymbol > (int)(sizeof(lengthbits)/sizeof(lengthbits[0])))
         goto bad_data;
         goto bad_data;
       len = lengthbases[lensymbol] + 2;
       len = lengthbases[lensymbol] + 2;
       if (lengthbits[lensymbol] > 0) {
       if (lengthbits[lensymbol] > 0) {
@@ -2442,9 +2695,9 @@ expand(struct archive_read *a, int64_t end)
     }
     }
     else
     else
     {
     {
-      if (symbol-271 > sizeof(lengthbases)/sizeof(lengthbases[0]))
+      if (symbol-271 > (int)(sizeof(lengthbases)/sizeof(lengthbases[0])))
         goto bad_data;
         goto bad_data;
-      if (symbol-271 > sizeof(lengthbits)/sizeof(lengthbits[0]))
+      if (symbol-271 > (int)(sizeof(lengthbits)/sizeof(lengthbits[0])))
         goto bad_data;
         goto bad_data;
       len = lengthbases[symbol-271]+3;
       len = lengthbases[symbol-271]+3;
       if(lengthbits[symbol-271] > 0) {
       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)
       if ((offssymbol = read_next_symbol(a, &rar->offsetcode)) < 0)
         goto bad_data;
         goto bad_data;
-      if (offssymbol > sizeof(offsetbases)/sizeof(offsetbases[0]))
+      if (offssymbol > (int)(sizeof(offsetbases)/sizeof(offsetbases[0])))
         goto bad_data;
         goto bad_data;
-      if (offssymbol > sizeof(offsetbits)/sizeof(offsetbits[0]))
+      if (offssymbol > (int)(sizeof(offsetbits)/sizeof(offsetbits[0])))
         goto bad_data;
         goto bad_data;
       offs = offsetbases[offssymbol]+1;
       offs = offsetbases[offssymbol]+1;
       if(offsetbits[offssymbol] > 0)
       if(offsetbits[offssymbol] > 0)
@@ -2572,3 +2825,34 @@ copy_from_lzss_window(struct archive_read *a, const void **buffer,
     *buffer = NULL;
     *buffer = NULL;
   return (ARCHIVE_OK);
   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_header,
 	    archive_read_format_raw_read_data,
 	    archive_read_format_raw_read_data,
 	    archive_read_format_raw_read_data_skip,
 	    archive_read_format_raw_read_data_skip,
+	    NULL,
 	    archive_read_format_raw_cleanup);
 	    archive_read_format_raw_cleanup);
 	if (r != ARCHIVE_OK)
 	if (r != ARCHIVE_OK)
 		free(info);
 		free(info);
@@ -157,7 +158,7 @@ archive_read_format_raw_read_data(struct archive_read *a,
 		/* Record and return an error. */
 		/* Record and return an error. */
 		*size = 0;
 		*size = 0;
 		*offset = info->offset;
 		*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) 2003-2007 Tim Kientzle
- * Copyright (c) 2011 Michihiro NAKAJIMA
+ * Copyright (c) 2011-2012 Michihiro NAKAJIMA
  * All rights reserved.
  * All rights reserved.
  *
  *
  * Redistribution and use in source and binary forms, with or without
  * 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 *);
 		    struct archive_string *, const void *h, size_t *);
 static int	solaris_sparse_parse(struct archive_read *, struct tar *,
 static int	solaris_sparse_parse(struct archive_read *, struct tar *,
 		    struct archive_entry *, const char *);
 		    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 *,
 static int	tar_read_header(struct archive_read *, struct tar *,
 		    struct archive_entry *, size_t *);
 		    struct archive_entry *, size_t *);
 static int	tohex(int c);
 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_header,
 	    archive_read_format_tar_read_data,
 	    archive_read_format_tar_read_data,
 	    archive_read_format_tar_skip,
 	    archive_read_format_tar_skip,
+	    NULL,
 	    archive_read_format_tar_cleanup);
 	    archive_read_format_tar_cleanup);
 
 
 	if (r != ARCHIVE_OK)
 	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 */
 		/* Handle UTF-8 filnames as libarchive 2.x */
 		tar->compat_2x = (val != NULL)?1:0;
 		tar->compat_2x = (val != NULL)?1:0;
 		tar->init_default_conversion = tar->compat_2x;
 		tar->init_default_conversion = tar->compat_2x;
-		ret = ARCHIVE_OK;
+		return (ARCHIVE_OK);
 	} else if (strcmp(key, "hdrcharset")  == 0) {
 	} else if (strcmp(key, "hdrcharset")  == 0) {
 		if (val == NULL || val[0] == 0)
 		if (val == NULL || val[0] == 0)
 			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
@@ -383,11 +384,13 @@ archive_read_format_tar_options(struct archive_read *a,
 			else
 			else
 				ret = ARCHIVE_FATAL;
 				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
 /* 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);
 	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
 static int
@@ -613,13 +617,14 @@ tar_read_header(struct archive_read *a, struct tar *tar,
 	int err;
 	int err;
 	const char *h;
 	const char *h;
 	const struct archive_entry_header_ustar *header;
 	const struct archive_entry_header_ustar *header;
+	const struct archive_entry_header_gnutar *gnuheader;
 
 
 	tar_flush_unconsumed(a, unconsumed);
 	tar_flush_unconsumed(a, unconsumed);
 
 
 	/* Read 512-byte header record */
 	/* Read 512-byte header record */
 	h = __archive_read_ahead(a, 512, &bytes);
 	h = __archive_read_ahead(a, 512, &bytes);
 	if (bytes < 0)
 	if (bytes < 0)
-		return (bytes);
+		return ((int)bytes);
 	if (bytes == 0) { /* EOF at a block boundary. */
 	if (bytes == 0) { /* EOF at a block boundary. */
 		/* Some writers do omit the block of nulls. <sigh> */
 		/* Some writers do omit the block of nulls. <sigh> */
 		return (ARCHIVE_EOF);
 		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);
 		err = header_pax_extensions(a, tar, entry, h, unconsumed);
 		break;
 		break;
 	default:
 	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 = ARCHIVE_FORMAT_TAR_GNUTAR;
 			a->archive.archive_format_name = "GNU tar format";
 			a->archive.archive_format_name = "GNU tar format";
 			err = header_gnutar(a, tar, entry, h, unconsumed);
 			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);
 				bytes_read = gnu_sparse_10_read(a, tar, unconsumed);
 				tar->entry_bytes_remaining -= bytes_read;
 				tar->entry_bytes_remaining -= bytes_read;
 				if (bytes_read < 0)
 				if (bytes_read < 0)
-					return (bytes_read);
+					return ((int)bytes_read);
 			} else {
 			} else {
 				archive_set_error(&a->archive,
 				archive_set_error(&a->archive,
 				    ARCHIVE_ERRNO_MISC,
 				    ARCHIVE_ERRNO_MISC,
@@ -784,7 +790,7 @@ checksum(struct archive_read *a, const void *h)
 	 * Test the checksum.  Note that POSIX specifies _unsigned_
 	 * Test the checksum.  Note that POSIX specifies _unsigned_
 	 * bytes for this calculation.
 	 * bytes for this calculation.
 	 */
 	 */
-	sum = tar_atol(header->checksum, sizeof(header->checksum));
+	sum = (int)tar_atol(header->checksum, sizeof(header->checksum));
 	check = 0;
 	check = 0;
 	for (i = 0; i < 148; i++)
 	for (i = 0; i < 148; i++)
 		check += (unsigned char)bytes[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.
 	 * more to make sure that we don't overrun acl_text later.
 	 */
 	 */
 	header = (const struct archive_entry_header_ustar *)h;
 	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);
 	err = read_body_to_string(a, tar, &(tar->acl_text), h, unconsumed);
 	if (err != ARCHIVE_OK)
 	if (err != ARCHIVE_OK)
 		return (err);
 		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. */
 	/* 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,
 		archive_set_error(&a->archive, ENOMEM,
 		    "No memory");
 		    "No memory");
 		return (ARCHIVE_FATAL);
 		return (ARCHIVE_FATAL);
@@ -1028,15 +1034,15 @@ read_body_to_string(struct archive_read *a, struct tar *tar,
 	tar_flush_unconsumed(a, unconsumed);
 	tar_flush_unconsumed(a, unconsumed);
 
 
 	/* Read the body into the string. */
 	/* Read the body into the string. */
-	*unconsumed = (size + 511) & ~ 511;
+	*unconsumed = (size_t)((size + 511) & ~ 511);
 	src = __archive_read_ahead(a, *unconsumed, NULL);
 	src = __archive_read_ahead(a, *unconsumed, NULL);
 	if (src == NULL) {
 	if (src == NULL) {
 		*unconsumed = 0;
 		*unconsumed = 0;
 		return (ARCHIVE_FATAL);
 		return (ARCHIVE_FATAL);
 	}
 	}
-	memcpy(as->s, src, size);
+	memcpy(as->s, src, (size_t)size);
 	as->s[size] = '\0';
 	as->s[size] = '\0';
-	as->length = size;
+	as->length = (size_t)size;
 	return (ARCHIVE_OK);
 	return (ARCHIVE_OK);
 }
 }
 
 
@@ -1066,7 +1072,8 @@ header_common(struct archive_read *a, struct tar *tar,
 		archive_string_empty(&(tar->entry_linkpath));
 		archive_string_empty(&(tar->entry_linkpath));
 
 
 	/* Parse out the numeric fields (all are octal) */
 	/* 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_uid(entry, tar_atol(header->uid, sizeof(header->uid)));
 	archive_entry_set_gid(entry, tar_atol(header->gid, sizeof(header->gid)));
 	archive_entry_set_gid(entry, tar_atol(header->gid, sizeof(header->gid)));
 	tar->entry_bytes_remaining = tar_atol(header->size, sizeof(header->size));
 	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
 	 * Q: Is the above idea really possible?  Even
 	 * when there are GNU or pax extension entries?
 	 * 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) {
 	if (data == NULL) {
 		*unconsumed = 0;
 		*unconsumed = 0;
 		return (ARCHIVE_FATAL);
 		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);
 	tar_flush_unconsumed(a, unconsumed);
 	return (tar_read_header(a, tar, entry, 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. */
 	/* Parse out device numbers only for char and block specials. */
 	if (header->typeflag[0] == '3' || header->typeflag[0] == '4') {
 	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)));
 		    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)));
 		    tar_atol(header->rdevminor, sizeof(header->rdevminor)));
 	}
 	}
 
 
@@ -1661,6 +1668,9 @@ pax_attribute(struct archive_read *a, struct tar *tar,
 	long n;
 	long n;
 	int err = ARCHIVE_OK, r;
 	int err = ARCHIVE_OK, r;
 
 
+	if (value == NULL)
+		value = "";	/* Disable compiler warning; do not pass
+				 * NULL pointer to strlen().  */
 	switch (key[0]) {
 	switch (key[0]) {
 	case 'G':
 	case 'G':
 		/* GNU "0.0" sparse pax format. */
 		/* 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 */
 		/* GNU "1.0" sparse pax format */
 		if (strcmp(key, "GNU.sparse.major") == 0) {
 		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;
 			tar->sparse_gnu_pending = 1;
 		}
 		}
 		if (strcmp(key, "GNU.sparse.minor") == 0) {
 		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;
 			tar->sparse_gnu_pending = 1;
 		}
 		}
 		if (strcmp(key, "GNU.sparse.name") == 0) {
 		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) {
 		} else if (strcmp(key, "SCHILY.devmajor") == 0) {
 			archive_entry_set_rdevmajor(entry,
 			archive_entry_set_rdevmajor(entry,
-			    tar_atol10(value, strlen(value)));
+			    (dev_t)tar_atol10(value, strlen(value)));
 		} else if (strcmp(key, "SCHILY.devminor") == 0) {
 		} else if (strcmp(key, "SCHILY.devminor") == 0) {
 			archive_entry_set_rdevminor(entry,
 			archive_entry_set_rdevminor(entry,
-			    tar_atol10(value, strlen(value)));
+			    (dev_t)tar_atol10(value, strlen(value)));
 		} else if (strcmp(key, "SCHILY.fflags") == 0) {
 		} else if (strcmp(key, "SCHILY.fflags") == 0) {
 			archive_entry_copy_fflags_text(entry, value);
 			archive_entry_copy_fflags_text(entry, value);
 		} else if (strcmp(key, "SCHILY.dev") == 0) {
 		} else if (strcmp(key, "SCHILY.dev") == 0) {
 			archive_entry_set_dev(entry,
 			archive_entry_set_dev(entry,
-			    tar_atol10(value, strlen(value)));
+			    (dev_t)tar_atol10(value, strlen(value)));
 		} else if (strcmp(key, "SCHILY.ino") == 0) {
 		} else if (strcmp(key, "SCHILY.ino") == 0) {
 			archive_entry_set_ino(entry,
 			archive_entry_set_ino(entry,
 			    tar_atol10(value, strlen(value)));
 			    tar_atol10(value, strlen(value)));
 		} else if (strcmp(key, "SCHILY.nlink") == 0) {
 		} else if (strcmp(key, "SCHILY.nlink") == 0) {
-			archive_entry_set_nlink(entry,
+			archive_entry_set_nlink(entry, (unsigned)
 			    tar_atol10(value, strlen(value)));
 			    tar_atol10(value, strlen(value)));
 		} else if (strcmp(key, "SCHILY.realsize") == 0) {
 		} else if (strcmp(key, "SCHILY.realsize") == 0) {
 			tar->realsize = tar_atol10(value, strlen(value));
 			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 */
 	/* Parse out device numbers only for char and block specials */
 	if (header->typeflag[0] == '3' || header->typeflag[0] == '4') {
 	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)));
 		    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)));
 		    tar_atol(header->rdevminor, sizeof(header->rdevminor)));
 	} else
 	} else
 		archive_entry_set_rdev(entry, 0);
 		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.
 	 * don't require this, but they should.
 	 */
 	 */
 	do {
 	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)
 		if (bytes_read <= 0)
 			return (ARCHIVE_FATAL);
 			return (ARCHIVE_FATAL);
 		*remaining -= bytes_read;
 		*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;
 	remaining = tar->entry_bytes_remaining;
 
 
 	/* Parse entries. */
 	/* Parse entries. */
-	entries = gnu_sparse_10_atol(a, tar, &remaining, unconsumed);
+	entries = (int)gnu_sparse_10_atol(a, tar, &remaining, unconsumed);
 	if (entries < 0)
 	if (entries < 0)
 		return (ARCHIVE_FATAL);
 		return (ARCHIVE_FATAL);
 	/* Parse the individual entries. */
 	/* 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... */
 	/* Skip rest of block... */
 	tar_flush_unconsumed(a, unconsumed);
 	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;
 	to_skip = 0x1ff & -bytes_read;
 	if (to_skip != __archive_read_consume(a, to_skip))
 	if (to_skip != __archive_read_consume(a, to_skip))
 		return (ARCHIVE_FATAL);
 		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
  * 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
  * pax simply indicates where data and sparse are, so the stored contents
  * consist of both data and hole.
  * consist of both data and hole.
  */
  */
@@ -2333,6 +2344,8 @@ solaris_sparse_parse(struct archive_read *a, struct tar *tar,
 	int64_t start, end;
 	int64_t start, end;
 	int hole = 1;
 	int hole = 1;
 
 
+	(void)entry; /* UNUSED */
+
 	end = 0;
 	end = 0;
 	if (*p == ' ')
 	if (*p == ' ')
 		p++;
 		p++;
@@ -2380,7 +2393,7 @@ solaris_sparse_parse(struct archive_read *a, struct tar *tar,
  * On read, this implementation supports both extensions.
  * On read, this implementation supports both extensions.
  */
  */
 static int64_t
 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
 	 * 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.
  * it does obey locale.
  */
  */
 static int64_t
 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;
 	int64_t	l, limit, last_digit_limit;
-	int digit, sign, base;
+	int digit, sign;
 
 
-	base = 8;
 	limit = INT64_MAX / base;
 	limit = INT64_MAX / base;
 	last_digit_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++;
 		p++;
-	if (*p == '-') {
+		char_cnt--;
+	}
+
+	sign = 1;
+	if (char_cnt != 0 && *p == '-') {
 		sign = -1;
 		sign = -1;
 		p++;
 		p++;
-	} else
-		sign = 1;
+		char_cnt--;
+	}
 
 
 	l = 0;
 	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;
 	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
 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.
  * ignored.
  */
  */
 static int64_t
 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;
 	int64_t	l, upper_limit, lower_limit;
 	const unsigned char *p = (const unsigned char *)_p;
 	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			 mtime;
 	time_t			 atime;
 	time_t			 atime;
 	struct archive_string	 uname;
 	struct archive_string	 uname;
-	uid_t			 uid;
+	int64_t			 uid;
 	struct archive_string	 gname;
 	struct archive_string	 gname;
-	gid_t			 gid;
+	int64_t			 gid;
 	mode_t			 mode;
 	mode_t			 mode;
 	dev_t			 dev;
 	dev_t			 dev;
 	dev_t			 devmajor;
 	dev_t			 devmajor;
@@ -467,6 +467,7 @@ archive_read_support_format_xar(struct archive *_a)
 	    xar_read_header,
 	    xar_read_header,
 	    xar_read_data,
 	    xar_read_data,
 	    xar_read_data_skip,
 	    xar_read_data_skip,
+	    NULL,
 	    xar_cleanup);
 	    xar_cleanup);
 	if (r != ARCHIVE_OK)
 	if (r != ARCHIVE_OK)
 		free(xar);
 		free(xar);
@@ -602,7 +603,8 @@ read_toc(struct archive_read *a)
 		r = move_reading_point(a, xar->toc_chksum_offset);
 		r = move_reading_point(a, xar->toc_chksum_offset);
 		if (r != ARCHIVE_OK)
 		if (r != ARCHIVE_OK)
 			return (r);
 			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)
 		if (bytes < 0)
 			return ((int)bytes);
 			return ((int)bytes);
 		if ((uint64_t)bytes < xar->toc_chksum_size) {
 		if ((uint64_t)bytes < xar->toc_chksum_size) {
@@ -611,7 +613,8 @@ read_toc(struct archive_read *a)
 			    "Truncated archive file");
 			    "Truncated archive file");
 			return (ARCHIVE_FATAL);
 			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);
 		__archive_read_consume(a, xar->toc_chksum_size);
 		xar->offset += xar->toc_chksum_size;
 		xar->offset += xar->toc_chksum_size;
 		if (r != ARCHIVE_OK)
 		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->file->hdnext = xar->hdlink_orgs;
 					xar->hdlink_orgs = xar->file;
 					xar->hdlink_orgs = xar->file;
 				} else {
 				} else {
-					xar->file->link = atol10(attr->value,
+					xar->file->link = (unsigned)atol10(attr->value,
 					    strlen(attr->value));
 					    strlen(attr->value));
 					if (xar->file->link > 0)
 					if (xar->file->link > 0)
 						if (add_link(a, xar, xar->file) != ARCHIVE_OK) {
 						if (add_link(a, xar, xar->file) != ARCHIVE_OK) {
@@ -2624,6 +2627,7 @@ strappend_base64(struct xar *xar,
 	const unsigned char *b;
 	const unsigned char *b;
 	size_t len;
 	size_t len;
 
 
+	(void)xar; /* UNUSED */
 	len = 0;
 	len = 0;
 	out = buff;
 	out = buff;
 	b = (const unsigned char *)s;
 	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->has |= HAS_MODE;
 		xar->file->mode =
 		xar->file->mode =
 		    (xar->file->mode & AE_IFMT) |
 		    (xar->file->mode & AE_IFMT) |
-		    (atol8(s, len) & ~AE_IFMT);
+		    ((mode_t)(atol8(s, len)) & ~AE_IFMT);
 		break;
 		break;
 	case FILE_GROUP:
 	case FILE_GROUP:
 		xar->file->has |= HAS_GID;
 		xar->file->has |= HAS_GID;
@@ -3075,12 +3079,15 @@ xml2_xmlattr_setup(struct archive_read *a,
 		attr->name = strdup(
 		attr->name = strdup(
 		    (const char *)xmlTextReaderConstLocalName(reader));
 		    (const char *)xmlTextReaderConstLocalName(reader));
 		if (attr->name == NULL) {
 		if (attr->name == NULL) {
+			free(attr);
 			archive_set_error(&a->archive, ENOMEM, "Out of memory");
 			archive_set_error(&a->archive, ENOMEM, "Out of memory");
 			return (ARCHIVE_FATAL);
 			return (ARCHIVE_FATAL);
 		}
 		}
 		attr->value = strdup(
 		attr->value = strdup(
 		    (const char *)xmlTextReaderConstValue(reader));
 		    (const char *)xmlTextReaderConstValue(reader));
 		if (attr->value == NULL) {
 		if (attr->value == NULL) {
+			free(attr->name);
+			free(attr);
 			archive_set_error(&a->archive, ENOMEM, "Out of memory");
 			archive_set_error(&a->archive, ENOMEM, "Out of memory");
 			return (ARCHIVE_FATAL);
 			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
 void
 archive_string_conversion_set_opt(struct archive_string_conv *, int);
 archive_string_conversion_set_opt(struct archive_string_conv *, int);
 #define SCONV_SET_OPT_UTF8_LIBARCHIVE2X	1
 #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.
 /* Copy one archive_string to another in locale conversion.
  * Return -1 if conversion failes. */
  * Return -1 if conversion failes. */
 int
 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 *);
     struct archive_string_conv *);
 
 
 /* Copy one archive_string to another in locale conversion.
 /* Copy one archive_string to another in locale conversion.
  * Return -1 if conversion failes. */
  * Return -1 if conversion failes. */
 int
 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 *);
     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)))
 	archive_strncpy((as), (p), ((p) == NULL ? 0 : strlen(p)))
 #define	archive_wstrcpy(as,p) \
 #define	archive_wstrcpy(as,p) \
 	archive_wstrncpy((as), (p), ((p) == NULL ? 0 : wcslen(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. */
 /* Copy a C string to an archive_string with limit, resizing as necessary. */
 #define	archive_strncpy(as,p,l) \
 #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.
  * All rights reserved.
  *
  *
  * Redistribution and use in source and binary forms, with or without
  * Redistribution and use in source and binary forms, with or without
@@ -29,7 +29,7 @@
 /*
 /*
  * ATTENTION!
  * ATTENTION!
  *  This file is generated by build/utils/gen_archive_string_composition_h.sh
  *  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/
  *  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, 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,};
   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 */
 #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
  * here.  This is only used to format error messages, so doesn't
  * require any floating-point support or field-width handling.
  * require any floating-point support or field-width handling.
  */
  */
-
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
 #include <stdio.h>
 #include <stdio.h>
 
 
 #include "archive_string.h"
 #include "archive_string.h"
@@ -129,7 +131,7 @@ archive_string_vsprintf(struct archive_string *as, const char *fmt,
 			break;
 			break;
 		case 'c':
 		case 'c':
 			s = va_arg(ap, int);
 			s = va_arg(ap, int);
-			archive_strappend_char(as, s);
+			archive_strappend_char(as, (char)s);
 			break;
 			break;
 		case 'd':
 		case 'd':
 			switch(long_flag) {
 			switch(long_flag) {
@@ -146,7 +148,9 @@ archive_string_vsprintf(struct archive_string *as, const char *fmt,
 				pw = va_arg(ap, wchar_t *);
 				pw = va_arg(ap, wchar_t *);
 				if (pw == NULL)
 				if (pw == NULL)
 					pw = L"(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;
 				break;
 			default:
 			default:
 				p2 = va_arg(ap, char *);
 				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 *);
 			pw = va_arg(ap, wchar_t *);
 			if (pw == NULL)
 			if (pw == NULL)
 				pw = L"(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;
 			break;
 		case 'o': case 'u': case 'x': case 'X':
 		case 'o': case 'u': case 'x': case 'X':
 			/* Common handling for unsigned integer formats. */
 			/* 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
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\" 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
 .Dt ARCHIVE_UTIL 3
 .Os
 .Os
 .Sh NAME
 .Sh NAME
@@ -43,6 +43,8 @@
 .Nm archive_position ,
 .Nm archive_position ,
 .Nm archive_set_error
 .Nm archive_set_error
 .Nd libarchive utility functions
 .Nd libarchive utility functions
+.Sh LIBRARY
+Streaming Archive Library (libarchive, -larchive)
 .Sh SYNOPSIS
 .Sh SYNOPSIS
 .In archive.h
 .In archive.h
 .Ft void
 .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
  * Copyright (c) 2003-2007 Tim Kientzle
  * All rights reserved.
  * 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_private.h"
 #include "archive_string.h"
 #include "archive_string.h"
 
 
+#ifndef O_CLOEXEC
+#define O_CLOEXEC	0
+#endif
+
 /* Generic initialization of 'struct archive' objects. */
 /* Generic initialization of 'struct archive' objects. */
 int
 int
 __archive_clean(struct archive *a)
 __archive_clean(struct archive *a)
@@ -239,12 +243,13 @@ __archive_mktemp(const char *tmpdir)
 			errno = ENOMEM;
 			errno = ENOMEM;
 			goto exit_tmpfile;
 			goto exit_tmpfile;
 		}
 		}
-		GetTempPathW(l, tmp);
+		GetTempPathW((DWORD)l, tmp);
 		archive_wstrcpy(&temp_name, tmp);
 		archive_wstrcpy(&temp_name, tmp);
 		free(tmp);
 		free(tmp);
 	} else {
 	} 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'/')
 		if (temp_name.s[temp_name.length-1] != L'/')
 			archive_wstrappend_wchar(&temp_name, L'/');
 			archive_wstrappend_wchar(&temp_name, L'/');
 	}
 	}
@@ -292,7 +297,8 @@ __archive_mktemp(const char *tmpdir)
 
 
 		/* Generate a random file name through CryptGenRandom(). */
 		/* Generate a random file name through CryptGenRandom(). */
 		p = xp;
 		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());
 			la_dosmaperr(GetLastError());
 			goto exit_tmpfile;
 			goto exit_tmpfile;
 		}
 		}
@@ -384,6 +390,7 @@ __archive_mktemp(const char *tmpdir)
 	fd = mkstemp(temp_name.s);
 	fd = mkstemp(temp_name.s);
 	if (fd < 0)
 	if (fd < 0)
 		goto exit_tmpfile;
 		goto exit_tmpfile;
+	__archive_ensure_cloexec_flag(fd);
 	unlink(temp_name.s);
 	unlink(temp_name.s);
 exit_tmpfile:
 exit_tmpfile:
 	archive_string_free(&temp_name);
 	archive_string_free(&temp_name);
@@ -437,7 +444,8 @@ __archive_mktemp(const char *tmpdir)
 	archive_strcat(&temp_name, "XXXXXXXXXX");
 	archive_strcat(&temp_name, "XXXXXXXXXX");
 	ep = temp_name.s + archive_strlen(&temp_name);
 	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)
 	if (fd < 0)
 		seed = time(NULL);
 		seed = time(NULL);
 	else {
 	else {
@@ -451,10 +459,12 @@ __archive_mktemp(const char *tmpdir)
 		p = tp;
 		p = tp;
 		while (p < ep)
 		while (p < ep)
 			*p++ = num[((unsigned)rand_r(&seed)) % sizeof(num)];
 			*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);
 	} while (fd < 0 && errno == EEXIST);
 	if (fd < 0)
 	if (fd < 0)
 		goto exit_tmpfile;
 		goto exit_tmpfile;
+	__archive_ensure_cloexec_flag(fd);
 	unlink(temp_name.s);
 	unlink(temp_name.s);
 exit_tmpfile:
 exit_tmpfile:
 	archive_string_free(&temp_name);
 	archive_string_free(&temp_name);
@@ -463,3 +473,29 @@ exit_tmpfile:
 
 
 #endif /* HAVE_MKSTEMP */
 #endif /* HAVE_MKSTEMP */
 #endif /* !_WIN32 || __CYGWIN__ */
 #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));
 	return ((a->vtable->archive_close)(a));
 }
 }
 
 
+int
+archive_write_fail(struct archive *a)
+{
+	a->state = ARCHIVE_STATE_FATAL;
+	return a->state;
+}
+
 int
 int
 archive_write_free(struct archive *a)
 archive_write_free(struct archive *a)
 {
 {
+	if (a == NULL)
+		return (ARCHIVE_OK);
 	return ((a->vtable->archive_free)(a));
 	return ((a->vtable->archive_free)(a));
 }
 }
 
 
@@ -77,13 +86,15 @@ archive_write_free(struct archive *a)
 int
 int
 archive_write_finish(struct archive *a)
 archive_write_finish(struct archive *a)
 {
 {
-	return ((a->vtable->archive_free)(a));
+	return archive_write_free(a);
 }
 }
 #endif
 #endif
 
 
 int
 int
 archive_read_free(struct archive *a)
 archive_read_free(struct archive *a)
 {
 {
+	if (a == NULL)
+		return (ARCHIVE_OK);
 	return ((a->vtable->archive_free)(a));
 	return ((a->vtable->archive_free)(a));
 }
 }
 
 
@@ -92,7 +103,7 @@ archive_read_free(struct archive *a)
 int
 int
 archive_read_finish(struct archive *a)
 archive_read_finish(struct archive *a)
 {
 {
-	return ((a->vtable->archive_free)(a));
+	return archive_read_free(a);
 }
 }
 #endif
 #endif
 
 

+ 135 - 40
Utilities/cmlibarchive/libarchive/archive_windows.c

@@ -48,6 +48,7 @@
 
 
 #include "archive_platform.h"
 #include "archive_platform.h"
 #include "archive_private.h"
 #include "archive_private.h"
+#include "archive_entry.h"
 #include <ctype.h>
 #include <ctype.h>
 #include <errno.h>
 #include <errno.h>
 #include <stddef.h>
 #include <stddef.h>
@@ -109,7 +110,7 @@ getino(struct ustat *ub)
 	ULARGE_INTEGER ino64;
 	ULARGE_INTEGER ino64;
 	ino64.QuadPart = ub->st_ino;
 	ino64.QuadPart = ub->st_ino;
 	/* I don't know this hashing is correct way */
 	/* 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)
 	if (l == 0)
 		return (NULL);
 		return (NULL);
 	/* NOTE: GetFullPathNameW has a bug that if the length of the file
 	/* 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
 	 * have to add three to the size to allocate a sufficient buffer
 	 * size for the full-pathname of the file name. */
 	 * size for the full-pathname of the file name. */
 	l += 3;
 	l += 3;
@@ -424,7 +425,7 @@ __la_read(int fd, void *buf, size_t nbytes)
 
 
 /* Convert Windows FILETIME to UTC */
 /* Convert Windows FILETIME to UTC */
 __inline static void
 __inline static void
-fileTimeToUTC(const FILETIME *filetime, time_t *time, long *ns)
+fileTimeToUTC(const FILETIME *filetime, time_t *t, long *ns)
 {
 {
 	ULARGE_INTEGER utc;
 	ULARGE_INTEGER utc;
 
 
@@ -432,10 +433,10 @@ fileTimeToUTC(const FILETIME *filetime, time_t *time, long *ns)
 	utc.LowPart  = filetime->dwLowDateTime;
 	utc.LowPart  = filetime->dwLowDateTime;
 	if (utc.QuadPart >= EPOC_TIME) {
 	if (utc.QuadPart >= EPOC_TIME) {
 		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 */
 		*ns = (long)(utc.QuadPart % 10000000) * 100;/* nano seconds base */
 	} else {
 	} else {
-		*time = 0;
+		*t = 0;
 		*ns = 0;
 		*ns = 0;
 	}
 	}
 }
 }
@@ -458,7 +459,7 @@ __hstat(HANDLE handle, struct ustat *st)
 	ULARGE_INTEGER ino64;
 	ULARGE_INTEGER ino64;
 	DWORD ftype;
 	DWORD ftype;
 	mode_t mode;
 	mode_t mode;
-	time_t time;
+	time_t t;
 	long ns;
 	long ns;
 
 
 	switch (ftype = GetFileType(handle)) {
 	switch (ftype = GetFileType(handle)) {
@@ -515,14 +516,14 @@ __hstat(HANDLE handle, struct ustat *st)
 		mode |= S_IFREG;
 		mode |= S_IFREG;
 	st->st_mode = mode;
 	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;
 	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;
 	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_ctime_nsec = ns;
 	st->st_size = 
 	st->st_size = 
 	    ((int64_t)(info.nFileSizeHigh) * ((int64_t)MAXDWORD + 1))
 	    ((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_ino = getino(us);
 	st->st_mode = us->st_mode;
 	st->st_mode = us->st_mode;
 	st->st_nlink = us->st_nlink;
 	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_uid = us->st_uid;
 	st->st_dev = us->st_dev;
 	st->st_dev = us->st_dev;
 	st->st_rdev = us->st_rdev;
 	st->st_rdev = us->st_rdev;
@@ -632,35 +633,22 @@ __la_stat(const char *path, struct stat *st)
  * This waitpid is limited implementation.
  * This waitpid is limited implementation.
  */
  */
 pid_t
 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 */
 	(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
 ssize_t
@@ -690,6 +678,113 @@ __la_write(int fd, const void *buf, size_t nbytes)
 	return (bytes_written);
 	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
  * The following function was modified from PostgreSQL sources and is
  * subject to the copyright below.
  * subject to the copyright below.
@@ -796,7 +891,7 @@ __la_dosmaperr(unsigned long e)
 		return;
 		return;
 	}
 	}
 
 
-	for (i = 0; i < sizeof(doserrors); i++)
+	for (i = 0; i < (int)sizeof(doserrors); i++)
 	{
 	{
 		if (doserrors[i].winerr == e)
 		if (doserrors[i].winerr == e)
 		{
 		{

+ 21 - 8
Utilities/cmlibarchive/libarchive/archive_windows.h

@@ -49,6 +49,9 @@
 #define	LIBARCHIVE_ARCHIVE_WINDOWS_H_INCLUDED
 #define	LIBARCHIVE_ARCHIVE_WINDOWS_H_INCLUDED
 
 
 /* Start of configuration for native Win32  */
 /* Start of configuration for native Win32  */
+#ifndef MINGW_HAS_SECURE_API
+#define MINGW_HAS_SECURE_API 1
+#endif
 
 
 #include <errno.h>
 #include <errno.h>
 #define	set_errno(val)	((errno)=val)
 #define	set_errno(val)	((errno)=val)
@@ -72,7 +75,6 @@
 //#define	EFTYPE 7
 //#define	EFTYPE 7
 
 
 #if defined(_MSC_VER)
 #if defined(_MSC_VER)
-/* TODO: Fix the code, don't suppress the warnings. */
 #pragma warning(push,1)
 #pragma warning(push,1)
 #pragma warning(disable:4761)   /* integral size mismatch in argument; conversion supplied */
 #pragma warning(disable:4761)   /* integral size mismatch in argument; conversion supplied */
 #endif
 #endif
@@ -95,8 +97,14 @@
 #ifndef fileno
 #ifndef fileno
 #define	fileno		_fileno
 #define	fileno		_fileno
 #endif
 #endif
+#ifdef fstat
+#undef fstat
+#endif
 #define	fstat		__la_fstat
 #define	fstat		__la_fstat
 #if !defined(__BORLANDC__)
 #if !defined(__BORLANDC__)
+#ifdef lseek
+#undef lseek
+#endif
 #define	lseek		_lseeki64
 #define	lseek		_lseeki64
 #else
 #else
 #define	lseek		__la_lseek
 #define	lseek		__la_lseek
@@ -108,6 +116,9 @@
 #if !defined(__BORLANDC__)
 #if !defined(__BORLANDC__)
 #define setmode		_setmode
 #define setmode		_setmode
 #endif
 #endif
+#ifdef stat
+#undef stat
+#endif
 #define	stat(path,stref)		__la_stat(path,stref)
 #define	stat(path,stref)		__la_stat(path,stref)
 #if !defined(__BORLANDC__)
 #if !defined(__BORLANDC__)
 #define	strdup		_strdup
 #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 int	 __la_open(const char *path, int flags, ...);
 extern ssize_t	 __la_read(int fd, void *buf, size_t nbytes);
 extern ssize_t	 __la_read(int fd, void *buf, size_t nbytes);
 extern int	 __la_stat(const char *path, struct stat *st);
 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);
 extern ssize_t	 __la_write(int fd, const void *buf, size_t nbytes);
 
 
 #define _stat64i32(path, st)	__la_stat(path, st)
 #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 wchar_t *__la_win_permissive_name_w(const wchar_t *wname);
 extern void __la_dosmaperr(unsigned long e);
 extern void __la_dosmaperr(unsigned long e);
 #define la_dosmaperr(e) __la_dosmaperr(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__)
 #if defined(HAVE_WCRTOMB) && defined(__BORLANDC__)
 typedef int mbstate_t;
 typedef int mbstate_t;
@@ -278,14 +291,14 @@ size_t wcrtomb(char *, wchar_t, mbstate_t *);
 
 
 #if defined(_MSC_VER) && _MSC_VER < 1300
 #if defined(_MSC_VER) && _MSC_VER < 1300
 WINBASEAPI BOOL WINAPI GetVolumePathNameW(
 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 */
 # if _WIN32_WINNT < 0x0500 /* windows.h not providing 0x500 API */
 typedef struct _FILE_ALLOCATED_RANGE_BUFFER {
 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;
 } FILE_ALLOCATED_RANGE_BUFFER, *PFILE_ALLOCATED_RANGE_BUFFER;
 #  define FSCTL_SET_SPARSE \
 #  define FSCTL_SET_SPARSE \
      CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 49, METHOD_BUFFERED, FILE_WRITE_DATA)
      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
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\" 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
 .Dt ARCHIVE_WRITE 3
 .Os
 .Os
 .Sh NAME
 .Sh NAME
 .Nm archive_write
 .Nm archive_write
 .Nd functions for creating archives
 .Nd functions for creating archives
+.Sh LIBRARY
+Streaming Archive Library (libarchive, -larchive)
 .Sh SYNOPSIS
 .Sh SYNOPSIS
 .In archive.h
 .In archive.h
 .Sh DESCRIPTION
 .Sh DESCRIPTION

+ 98 - 92
Utilities/cmlibarchive/libarchive/archive_write.c

@@ -232,6 +232,10 @@ __archive_write_filter(struct archive_write_filter *f,
 	int r;
 	int r;
 	if (length == 0)
 	if (length == 0)
 		return(ARCHIVE_OK);
 		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);
 	r = (f->write)(f, buff, length);
 	f->bytes_written += length;
 	f->bytes_written += length;
 	return (r);
 	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_write *a = (struct archive_write *)f->archive;
         struct archive_none *state = (struct archive_none *)f->data;
         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;
 			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;
 			char *p = state->buffer;
 			size_t to_write = state->buffer_size;
 			size_t to_write = state->buffer_size;
 			while (to_write > 0) {
 			while (to_write > 0) {
@@ -375,70 +379,72 @@ archive_write_client_write(struct archive_write_filter *f,
 				p += bytes_written;
 				p += bytes_written;
 				to_write -= 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
 static int
 archive_write_client_close(struct archive_write_filter *f)
 archive_write_client_close(struct archive_write_filter *f)
 {
 {
 	struct archive_write *a = (struct archive_write *)f->archive;
 	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)
 	if (a->client_closer)
 		(*a->client_closer)(&a->archive, a->client_data);
 		(*a->client_closer)(&a->archive, a->client_data);
 	free(state->buffer);
 	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 &&
 	if (a->skip_file_set &&
 	    archive_entry_dev_is_set(entry) &&
 	    archive_entry_dev_is_set(entry) &&
 	    archive_entry_ino_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_entry_ino64(entry) == a->skip_file_ino) {
 		archive_set_error(&a->archive, 0,
 		archive_set_error(&a->archive, 0,
 		    "Can't add archive to itself");
 		    "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);
+}

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