Imported Upstream version 3.23.2 upstream/3.23.2
authorJinWang An <jinwang.an@samsung.com>
Tue, 27 Dec 2022 08:20:14 +0000 (17:20 +0900)
committerJinWang An <jinwang.an@samsung.com>
Tue, 27 Dec 2022 08:20:14 +0000 (17:20 +0900)
84 files changed:
Help/command/add_library.rst
Help/cpack_gen/productbuild.rst
Help/guide/tutorial/Adding a Library.rst
Help/guide/tutorial/index.rst
Help/guide/tutorial/source.txt [new file with mode: 0644]
Help/manual/cmake-generator-expressions.7.rst
Help/release/3.23.rst
Modules/CMakeCheckCompilerFlagCommonPatterns.cmake
Modules/CMakePackageConfigHelpers.cmake
Modules/FindBoost.cmake
Modules/FindJNI.cmake
Modules/FindJava.cmake
Modules/FindPkgConfig.cmake
Modules/FindPython/Support.cmake
Modules/FindPythonInterp.cmake
Modules/FindPythonLibs.cmake
Modules/FortranCInterface/CMakeLists.txt
Modules/Internal/CPack/CPackNuGet.cmake
Modules/Internal/CheckLinkerFlag.cmake
Modules/Platform/Windows-Clang.cmake
Source/CMakeVersion.cmake
Source/CPack/IFW/cmCPackIFWInstaller.cxx
Source/CPack/cmCPackPKGGenerator.cxx
Source/CursesDialog/cmCursesMainForm.cxx
Source/CursesDialog/cmCursesMainForm.h
Source/cmExportBuildFileGenerator.cxx
Source/cmGeneratedFileStream.cxx
Source/cmGeneratorTarget.cxx
Source/cmInstallCommand.cxx
Source/cmRuntimeDependencyArchive.cxx
Source/cmVisualStudioGeneratorOptions.cxx
Tests/RunCMake/RunCMake.cmake
Tests/RunCMake/target_sources/FileSetGeneratedDependency.cmake [new file with mode: 0644]
Tests/RunCMake/target_sources/FileSetGeneratedDependency.h.in [new file with mode: 0644]
Tests/RunCMake/target_sources/FileSetImport.cmake
Tests/RunCMake/target_sources/FileSetInstallMissingSetsInterface-stderr.txt
Tests/RunCMake/target_sources/RunCMakeTest.cmake
Tests/RunCMake/target_sources/dependency.c [new file with mode: 0644]
Utilities/Scripts/update-libarchive.bash
Utilities/Sphinx/CMakeLists.txt
Utilities/Sphinx/tutorial_archive.cmake [new file with mode: 0644]
Utilities/cmThirdPartyChecks.cmake
Utilities/cmlibarchive/CMakeLists.txt
Utilities/cmlibarchive/build/cmake/config.h.in
Utilities/cmlibarchive/build/utils/gen_archive_string_composition_h.sh
Utilities/cmlibarchive/build/version
Utilities/cmlibarchive/libarchive/CMakeLists.txt
Utilities/cmlibarchive/libarchive/archive.h
Utilities/cmlibarchive/libarchive/archive_blake2s_ref.c
Utilities/cmlibarchive/libarchive/archive_blake2sp_ref.c
Utilities/cmlibarchive/libarchive/archive_disk_acl_freebsd.c
Utilities/cmlibarchive/libarchive/archive_disk_acl_linux.c
Utilities/cmlibarchive/libarchive/archive_disk_acl_sunos.c
Utilities/cmlibarchive/libarchive/archive_entry.h
Utilities/cmlibarchive/libarchive/archive_pathmatch.c
Utilities/cmlibarchive/libarchive/archive_private.h
Utilities/cmlibarchive/libarchive/archive_read_disk_posix.c
Utilities/cmlibarchive/libarchive/archive_read_disk_windows.c
Utilities/cmlibarchive/libarchive/archive_read_set_options.3
Utilities/cmlibarchive/libarchive/archive_read_support_filter_rpm.c
Utilities/cmlibarchive/libarchive/archive_read_support_filter_uu.c
Utilities/cmlibarchive/libarchive/archive_read_support_format_7zip.c
Utilities/cmlibarchive/libarchive/archive_read_support_format_cab.c
Utilities/cmlibarchive/libarchive/archive_read_support_format_cpio.c
Utilities/cmlibarchive/libarchive/archive_read_support_format_mtree.c
Utilities/cmlibarchive/libarchive/archive_read_support_format_rar.c
Utilities/cmlibarchive/libarchive/archive_read_support_format_rar5.c
Utilities/cmlibarchive/libarchive/archive_read_support_format_tar.c
Utilities/cmlibarchive/libarchive/archive_read_support_format_zip.c
Utilities/cmlibarchive/libarchive/archive_write.c
Utilities/cmlibarchive/libarchive/archive_write_disk_posix.c
Utilities/cmlibarchive/libarchive/archive_write_format.3
Utilities/cmlibarchive/libarchive/archive_write_set_format.c
Utilities/cmlibarchive/libarchive/archive_write_set_format_7zip.c
Utilities/cmlibarchive/libarchive/archive_write_set_format_by_name.c
Utilities/cmlibarchive/libarchive/archive_write_set_format_cpio.c
Utilities/cmlibarchive/libarchive/archive_write_set_format_cpio_binary.c [new file with mode: 0644]
Utilities/cmlibarchive/libarchive/archive_write_set_format_cpio_odc.c [new file with mode: 0644]
Utilities/cmlibarchive/libarchive/archive_write_set_options.3
Utilities/cmlibarchive/libarchive/config_freebsd.h
Utilities/cmlibarchive/libarchive/cpio.5
Utilities/cmlibarchive/libarchive/libarchive-formats.5
Utilities/cmlibarchive/libarchive/libarchive.3
Utilities/cmlibarchive/libarchive/xxhash.c

index 1235155..7dc4365 100644 (file)
@@ -151,6 +151,7 @@ itself and is not included as a target in the generated buildsystem.
   ``PUBLIC`` keywords.
 
   If an interface library has source files (i.e. the :prop_tgt:`SOURCES`
+  target property is set), or header sets (i.e. the :prop_tgt:`HEADER_SETS`
   target property is set), it will appear in the generated buildsystem
   as a build target much like a target defined by the
   :command:`add_custom_target` command.  It does not compile any sources,
index 26e0782..48a9b44 100644 (file)
@@ -203,3 +203,47 @@ installer.
 
  Does the same as :variable:`CPACK_PRODUCTBUILD_BACKGROUND_UTI` option,
  but for the dark theme.
+
+Distribution XML Template
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+CPack uses a template file to generate the ``distribution.dist`` file used
+internally by this package generator. Ordinarily, CMake provides the template
+file, but projects may supply their own by placing a file called
+``CPack.distribution.dist.in`` in one of the directories listed in the
+:variable:`CMAKE_MODULE_PATH` variable. CPack will then pick up the project's
+template file instead of using its own.
+
+The ``distribution.dist`` file is generated by performing substitutions
+similar to the :command:`configure_file` command. Any variable set when
+CPack runs will be available for substitution using the usual ``@...@``
+form. The following variables are also set internally and made available for
+substitution:
+
+``CPACK_RESOURCE_FILE_LICENSE_NOPATH``
+  Same as :variable:`CPACK_RESOURCE_FILE_LICENSE` except without the path.
+  The named file will be available in the same directory as the generated
+  ``distribution.dist`` file.
+
+``CPACK_RESOURCE_FILE_README_NOPATH``
+  Same as :variable:`CPACK_RESOURCE_FILE_README` except without the path.
+  The named file will be available in the same directory as the generated
+  ``distribution.dist`` file.
+
+``CPACK_RESOURCE_FILE_WELCOME_NOPATH``
+  Same as :variable:`CPACK_RESOURCE_FILE_WELCOME` except without the path.
+  The named file will be available in the same directory as the generated
+  ``distribution.dist`` file.
+
+``CPACK_APPLE_PKG_INSTALLER_CONTENT``
+  .. versionadded:: 3.23
+
+  This contains all the XML elements that specify installer-wide options
+  (including domain details), default backgrounds and the choices outline.
+
+``CPACK_PACKAGEMAKER_CHOICES``
+  .. deprecated:: 3.23
+
+  This contains only the XML elements that specify the default backgrounds
+  and the choices outline. It does not include the installer-wide options or
+  any domain details. Use ``CPACK_APPLE_PKG_INSTALLER_CONTENT`` instead.
index ed03448..71755be 100644 (file)
@@ -23,8 +23,9 @@ directory:
 To make use of the new library we will add an :command:`add_subdirectory`
 call in the top-level ``CMakeLists.txt`` file so that the library will get
 built. We add the new library to the executable, and add ``MathFunctions`` as
-an include directory so that the ``mysqrt.h`` header file can be found. The
-last few lines of the top-level ``CMakeLists.txt`` file should now look like:
+an include directory so that the ``MathFunctions.h`` header file can be found.
+The last few lines of the top-level ``CMakeLists.txt`` file should now look
+like:
 
 .. code-block:: cmake
         :caption: CMakeLists.txt
index 8b20a2d..09553cb 100644 (file)
@@ -11,8 +11,9 @@ work together in an example project can be very helpful.
 Steps
 =====
 
-The tutorial documentation and source code for examples can be found in
-the ``Help/guide/tutorial`` directory of the CMake source code tree.
+.. include:: source.txt
+
+|tutorial_source|
 Each step has its own subdirectory containing code that may be used as a
 starting point. The tutorial examples are progressive so that each step
 provides the complete solution for the previous step.
diff --git a/Help/guide/tutorial/source.txt b/Help/guide/tutorial/source.txt
new file mode 100644 (file)
index 0000000..bb45e86
--- /dev/null
@@ -0,0 +1,3 @@
+.. |tutorial_source| replace::
+  The tutorial documentation and source code examples can be found in
+  the ``Help/guide/tutorial`` directory of the CMake source code tree.
index df13dd0..a6d2a05 100644 (file)
@@ -197,6 +197,8 @@ Variable Queries
 
 .. genex:: $<HIP_COMPILER_ID:compiler_ids>
 
+  .. versionadded:: 3.21
+
   where ``compiler_ids`` is a comma-separated list.
   ``1`` if the CMake's compiler id of the HIP compiler matches any one
   of the entries in ``compiler_ids``, otherwise ``0``.
@@ -249,6 +251,8 @@ Variable Queries
 
 .. genex:: $<HIP_COMPILER_VERSION:version>
 
+  .. versionadded:: 3.21
+
   ``1`` if the version of the HIP compiler matches ``version``, otherwise ``0``.
   See also the :variable:`CMAKE_<LANG>_COMPILER_VERSION` variable.
 
@@ -714,6 +718,8 @@ Variable Queries
 
 .. genex:: $<HIP_COMPILER_ID>
 
+  .. versionadded:: 3.21
+
   The CMake's compiler id of the HIP compiler used.
   See also the :variable:`CMAKE_<LANG>_COMPILER_ID` variable.
 
@@ -760,6 +766,8 @@ Variable Queries
 
 .. genex:: $<HIP_COMPILER_VERSION>
 
+  .. versionadded:: 3.21
+
   The version of the HIP compiler used.
   See also the :variable:`CMAKE_<LANG>_COMPILER_VERSION` variable.
 
@@ -1057,10 +1065,10 @@ which is just the string ``tgt``.
   .. versionadded:: 3.21
 
   List of DLLs that the target depends on at runtime. This is determined by
-  the locations of all the ``SHARED`` and ``MODULE`` targets in the target's
-  transitive dependencies. Using this generator expression on targets other
-  than executables, ``SHARED`` libraries, and ``MODULE`` libraries is an error.
-  On non-DLL platforms, it evaluates to an empty string.
+  the locations of all the ``SHARED`` targets in the target's transitive
+  dependencies. Using this generator expression on targets other than
+  executables, ``SHARED`` libraries, and ``MODULE`` libraries is an error. On
+  non-DLL platforms, it evaluates to an empty string.
 
   This generator expression can be used to copy all of the DLLs that a target
   depends on into its output directory in a ``POST_BUILD`` custom command. For
@@ -1080,9 +1088,9 @@ which is just the string ``tgt``.
   .. note::
 
     :ref:`Imported Targets` are supported only if they know the location
-    of their ``.dll`` files.  An imported ``SHARED`` or ``MODULE`` library
-    must have :prop_tgt:`IMPORTED_LOCATION` set to its ``.dll`` file.  See
-    the :ref:`add_library imported libraries <add_library imported libraries>`
+    of their ``.dll`` files.  An imported ``SHARED`` library must have
+    :prop_tgt:`IMPORTED_LOCATION` set to its ``.dll`` file.  See the
+    :ref:`add_library imported libraries <add_library imported libraries>`
     section for details.  Many :ref:`Find Modules` produce imported targets
     with the ``UNKNOWN`` type and therefore will be ignored.
 
index 2febbec..47c4243 100644 (file)
@@ -185,6 +185,13 @@ CPack
   :variable:`CPACK_PRODUCTBUILD_IDENTIFIER`, used to customize the unique
   product identifier associated with the product.
 
+* The ``CPack.distribution.dist.in`` template used by the
+  :cpack_gen:`CPack productbuild Generator` and
+  :cpack_gen:`CPack PackageMaker Generator` was updated to use a new
+  ``CPACK_APPLE_PKG_INSTALLER_CONTENT`` variable for its main content.
+  This replaced the previously undocumented and now deprecated
+  ``CPACK_PACKAGEMAKER_CHOICES`` variable.
+
 * The :cpack_gen:`CPack IFW Generator` gained the new
   :variable:`CPACK_IFW_ARCHIVE_FORMAT` and
   :variable:`CPACK_IFW_ARCHIVE_COMPRESSION` variables for setting the
@@ -230,6 +237,15 @@ Deprecated and Removed Features
 
 * The :manual:`cpack(1)` undocumented ``OSXX11`` generator has been removed.
 
+* The previously undocumented ``CPACK_PACKAGEMAKER_CHOICES`` variable used in
+  the ``CPack.distribution.dist.in`` template has been replaced by a new
+  ``CPACK_APPLE_PKG_INSTALLER_CONTENT`` variable. This only affects projects
+  that were providing their own custom ``CPack.distribution.dist.in`` template
+  file, but still relied on ``CPACK_PACKAGEMAKER_CHOICES`` being set. Those
+  custom template files should be updated to use
+  ``CPACK_APPLE_PKG_INSTALLER_CONTENT`` instead, or to fully define all the
+  template file's contents without relying on substitution of either variable.
+
 Other Changes
 =============
 
@@ -282,3 +298,14 @@ Changes made since CMake 3.23.0 include the following.
 * The :prop_tgt:`HEADER_SETS` and :prop_tgt:`INTERFACE_HEADER_SETS` target
   properties added in CMake 3.23.0 are now read-only records of the header
   sets created by the :command:`target_sources` command.
+
+3.23.2
+------
+
+* The ``CPACK_PACKAGEMAKER_CHOICES`` variable used in the
+  ``CPack.distribution.dist.in`` template file was replaced by a new
+  ``CPACK_APPLE_PKG_INSTALLER_CONTENT`` variable in CMake 3.23.0.
+  This broke projects that provided their own template file but still
+  expected the ``CPACK_PACKAGEMAKER_CHOICES`` variable to be defined.
+  The old ``CPACK_PACKAGEMAKER_CHOICES`` variable is now also set to the
+  same content as it was before, but it is formally deprecated.
index 8f59acd..bda1d71 100644 (file)
@@ -13,7 +13,6 @@ macro (CHECK_COMPILER_FLAG_COMMON_PATTERNS _VAR)
     FAIL_REGEX "unknown .*option"                          # Clang
     FAIL_REGEX "optimization flag .* not supported"        # Clang
     FAIL_REGEX "unknown argument ignored"                  # Clang (cl)
-    FAIL_REGEX "warning: .* ignored"                       # Clang (linker)
     FAIL_REGEX "ignoring unknown option"                   # MSVC, Intel
     FAIL_REGEX "warning D9002"                             # MSVC, any lang
     FAIL_REGEX "option.*not supported"                     # Intel
index 5813956..6f5702a 100644 (file)
@@ -177,9 +177,9 @@ macro.
   packages with no binaries.
 
 .. versionadded:: 3.19
-  ``COMPATIBILITY_MODE`` ``AnyNewerVersion``, ``SameMajorVersion`` and
-  ``SameMinorVersion`` handle the version range if any is specified
-  (see :command:`find_package` command for the details).
+  The version file generated by ``AnyNewerVersion``, ``SameMajorVersion`` and
+  ``SameMinorVersion`` arguments of ``COMPATIBILITY`` handle the version range
+  if any is specified (see :command:`find_package` command for the details).
   ``ExactVersion`` mode is incompatible with version ranges and will display an
   author warning if one is specified.
 
index 91d4eee..0f407c8 100644 (file)
@@ -1380,7 +1380,7 @@ function(_Boost_COMPONENT_DEPENDENCIES component _ret)
       set(_Boost_TIMER_DEPENDENCIES chrono)
       set(_Boost_WAVE_DEPENDENCIES filesystem serialization thread chrono atomic)
       set(_Boost_WSERIALIZATION_DEPENDENCIES serialization)
-      if(Boost_VERSION_STRING VERSION_GREATER_EQUAL 1.79.0 AND NOT Boost_NO_WARN_NEW_VERSIONS)
+      if(Boost_VERSION_STRING VERSION_GREATER_EQUAL 1.80.0 AND NOT Boost_NO_WARN_NEW_VERSIONS)
         message(WARNING "New Boost version may have incorrect or missing dependencies and imported targets")
       endif()
     endif()
@@ -1653,6 +1653,7 @@ else()
   # _Boost_COMPONENT_HEADERS.  See the instructions at the top of
   # _Boost_COMPONENT_DEPENDENCIES.
   set(_Boost_KNOWN_VERSIONS ${Boost_ADDITIONAL_VERSIONS}
+    "1.79.0" "1.79"
     "1.78.0" "1.78" "1.77.0" "1.77" "1.76.0" "1.76" "1.75.0" "1.75" "1.74.0" "1.74"
     "1.73.0" "1.73" "1.72.0" "1.72" "1.71.0" "1.71" "1.70.0" "1.70" "1.69.0" "1.69"
     "1.68.0" "1.68" "1.67.0" "1.67" "1.66.0" "1.66" "1.65.1" "1.65.0" "1.65"
index e4f60b3..5182401 100644 (file)
@@ -145,46 +145,41 @@ endif()
 
 if (WIN32)
   set (_JNI_HINTS)
-  execute_process(COMMAND REG QUERY HKLM\\SOFTWARE\\JavaSoft\\JDK
-    RESULT_VARIABLE _JNI_RESULT
-    OUTPUT_VARIABLE _JNI_VERSIONS
-    ERROR_QUIET)
-  if (NOT  _JNI_RESULT)
-    string (REGEX MATCHALL "HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\JavaSoft\\\\JDK\\\\[0-9.]+" _JNI_VERSIONS "${_JNI_VERSIONS}")
-    if (_JNI_VERSIONS)
-      # sort versions. Most recent first
-      ## handle version 9 apart from other versions to get correct ordering
-      set (_JNI_V9 ${_JNI_VERSIONS})
-      list (FILTER _JNI_VERSIONS EXCLUDE REGEX "JDK\\\\9")
-      list (SORT _JNI_VERSIONS)
-      list (REVERSE _JNI_VERSIONS)
-      list (FILTER _JNI_V9 INCLUDE REGEX "JDK\\\\9")
-      list (SORT _JNI_V9)
-      list (REVERSE _JNI_V9)
-      list (APPEND _JNI_VERSIONS ${_JNI_V9})
-      foreach (_JNI_HINT IN LISTS _JNI_VERSIONS)
-        list(APPEND _JNI_HINTS "[${_JNI_HINT};JavaHome]")
-      endforeach()
+  macro (_JNI_GET_INSTALLED_VERSIONS _KIND)
+    execute_process(COMMAND REG QUERY "HKLM\\SOFTWARE\\JavaSoft\\${_KIND}"
+      RESULT_VARIABLE _JAVA_RESULT
+      OUTPUT_VARIABLE _JAVA_VERSIONS
+      ERROR_QUIET)
+    if (NOT  _JAVA_RESULT)
+      string (REGEX MATCHALL "HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\JavaSoft\\\\${_KIND}\\\\[0-9._]+" _JNI_VERSIONS "${_JAVA_VERSIONS}")
+      string (REGEX REPLACE "HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\JavaSoft\\\\${_KIND}\\\\([0-9._]+)" "\\1" _JNI_VERSIONS "${_JNI_VERSIONS}")
+      if (_JNI_VERSIONS)
+        # sort versions. Most recent first
+        list (SORT _JNI_VERSIONS COMPARE NATURAL ORDER DESCENDING)
+        foreach (_JNI_VERSION IN LISTS _JNI_VERSIONS)
+          string(REPLACE "_" "." _JNI_CMAKE_VERSION "${_JNI_VERSION}")
+          if (JNI_FIND_VERSION_EXACT
+              AND NOT _JNI_CMAKE_VERSION MATCHES "^${JNI_FIND_VERSION}")
+            continue()
+          endif()
+          if (DEFINED JNI_FIND_VERSION AND _JNI_CMAKE_VERSION VERSION_LESS JNI_FIND_VERSION)
+            break()
+          endif()
+          list(APPEND _JNI_HINTS "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\${_KIND}\\${_JNI_VERSION};JavaHome]")
+        endforeach()
+      endif()
     endif()
-  endif()
+  endmacro()
+
+    # for version 9 and upper
+  _JNI_GET_INSTALLED_VERSIONS("JDK")
+
+  # for versions older than 9
+  _JNI_GET_INSTALLED_VERSIONS("Java Development Kit")
 
   foreach (_JNI_HINT IN LISTS _JNI_HINTS)
     list(APPEND JAVA_AWT_LIBRARY_DIRECTORIES "${_JNI_HINT}/lib")
   endforeach()
-
-  get_filename_component(java_install_version
-    "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit;CurrentVersion]" NAME)
-
-  list(APPEND JAVA_AWT_LIBRARY_DIRECTORIES
-    "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.9;JavaHome]/lib"
-    "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.8;JavaHome]/lib"
-    "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.7;JavaHome]/lib"
-    "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.6;JavaHome]/lib"
-    "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.5;JavaHome]/lib"
-    "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.4;JavaHome]/lib"
-    "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.3;JavaHome]/lib"
-    "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\${java_install_version};JavaHome]/lib"
-    )
 endif()
 
 set(_JNI_JAVA_DIRECTORIES_BASE
@@ -268,16 +263,6 @@ if (WIN32)
   foreach (_JNI_HINT IN LISTS _JNI_HINTS)
     list(APPEND JAVA_AWT_INCLUDE_DIRECTORIES "${_JNI_HINT}/include")
   endforeach()
-  list(APPEND JAVA_AWT_INCLUDE_DIRECTORIES
-    "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.9;JavaHome]/include"
-    "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.8;JavaHome]/include"
-    "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.7;JavaHome]/include"
-    "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.6;JavaHome]/include"
-    "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.5;JavaHome]/include"
-    "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.4;JavaHome]/include"
-    "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.3;JavaHome]/include"
-    "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\${java_install_version};JavaHome]/include"
-    )
 endif()
 
 JAVA_APPEND_LIBRARY_DIRECTORIES(JAVA_AWT_INCLUDE_DIRECTORIES
index 4f0e0fe..7a95ef5 100644 (file)
@@ -90,50 +90,35 @@ if(_JAVA_HOME)
 endif()
 if (WIN32)
   macro (_JAVA_GET_INSTALLED_VERSIONS _KIND)
-    execute_process(COMMAND REG QUERY HKLM\\SOFTWARE\\JavaSoft\\${_KIND}
+    execute_process(COMMAND REG QUERY "HKLM\\SOFTWARE\\JavaSoft\\${_KIND}"
       RESULT_VARIABLE _JAVA_RESULT
       OUTPUT_VARIABLE _JAVA_VERSIONS
       ERROR_QUIET)
     if (NOT  _JAVA_RESULT)
-      string (REGEX MATCHALL "HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\JavaSoft\\\\${_KIND}\\\\[0-9.]+" _JAVA_VERSIONS "${_JAVA_VERSIONS}")
+      string (REGEX MATCHALL "HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\JavaSoft\\\\${_KIND}\\\\[0-9._]+" _JAVA_VERSIONS "${_JAVA_VERSIONS}")
+      string (REGEX REPLACE "HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\JavaSoft\\\\${_KIND}\\\\([0-9._]+)" "\\1" _JAVA_VERSIONS "${_JAVA_VERSIONS}")
       if (_JAVA_VERSIONS)
         # sort versions. Most recent first
-        ## handle version 9 apart from other versions to get correct ordering
-        set (_JAVA_V9 ${_JAVA_VERSIONS})
-        list (FILTER _JAVA_VERSIONS EXCLUDE REGEX "${_KIND}\\\\9")
-        list (SORT _JAVA_VERSIONS)
-        list (REVERSE _JAVA_VERSIONS)
-        list (FILTER _JAVA_V9 INCLUDE REGEX "${_KIND}\\\\9")
-        list (SORT _JAVA_V9)
-        list (REVERSE _JAVA_V9)
-        list (APPEND _JAVA_VERSIONS ${_JAVA_V9})
-        foreach (_JAVA_HINT IN LISTS _JAVA_VERSIONS)
-          list(APPEND _JAVA_HINTS "[${_JAVA_HINT};JavaHome]/bin")
+        list (SORT _JAVA_VERSIONS COMPARE NATURAL ORDER DESCENDING)
+        foreach (_JAVA_VERSION IN LISTS _JAVA_VERSIONS)
+          string(REPLACE "_" "." _JAVA_CMAKE_VERSION "${_JAVA_VERSION}")
+          if (Java_FIND_VERSION_EXACT
+              AND NOT _JAVA_CMAKE_VERSION MATCHES "^${Java_FIND_VERSION}")
+            continue()
+          endif()
+          list(APPEND _JAVA_HINTS "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\${_KIND}\\${_JAVA_VERSION};JavaHome]/bin")
         endforeach()
       endif()
     endif()
   endmacro()
 
-  # search for installed versions for version 9 and upper
+  # for version 9 and upper
   _JAVA_GET_INSTALLED_VERSIONS("JDK")
   _JAVA_GET_INSTALLED_VERSIONS("JRE")
 
-  list(APPEND _JAVA_HINTS
-  "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.9;JavaHome]/bin"
-  "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.8;JavaHome]/bin"
-  "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.7;JavaHome]/bin"
-  "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.6;JavaHome]/bin"
-  "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.5;JavaHome]/bin"
-  "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.4;JavaHome]/bin"
-  "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.3;JavaHome]/bin"
-  "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Runtime Environment\\1.9;JavaHome]/bin"
-  "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Runtime Environment\\1.8;JavaHome]/bin"
-  "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Runtime Environment\\1.7;JavaHome]/bin"
-  "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Runtime Environment\\1.6;JavaHome]/bin"
-  "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Runtime Environment\\1.5;JavaHome]/bin"
-  "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Runtime Environment\\1.4;JavaHome]/bin"
-  "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Runtime Environment\\1.3;JavaHome]/bin"
-  )
+  # for versions older than 9
+  _JAVA_GET_INSTALLED_VERSIONS("Java Development Kit")
+  _JAVA_GET_INSTALLED_VERSIONS("Java Runtime Environment")
 endif()
 
 # Hard-coded guesses should still go in PATHS. This ensures that the user
@@ -336,13 +321,13 @@ else()
     find_package_handle_standard_args(Java
       REQUIRED_VARS Java_JAVA_EXECUTABLE Java_JAR_EXECUTABLE Java_JAVAC_EXECUTABLE
                     Java_JAVAH_EXECUTABLE Java_JAVADOC_EXECUTABLE
-      VERSION_VAR Java_VERSION_STRING
+      VERSION_VAR Java_VERSION
       )
   else()
     find_package_handle_standard_args(Java
       REQUIRED_VARS Java_JAVA_EXECUTABLE Java_JAR_EXECUTABLE Java_JAVAC_EXECUTABLE
                     Java_JAVADOC_EXECUTABLE
-      VERSION_VAR Java_VERSION_STRING
+      VERSION_VAR Java_VERSION
       )
   endif()
 endif()
index 547bc52..ab8af3e 100644 (file)
@@ -429,7 +429,7 @@ macro(_pkg_set_path_internal)
   else()
     unset(_pkgconfig_allow_system_libs_old)
   endif()
-  set(ENV{PKG_CONFIG_ALLOW_SYSTEM_LIBS} 0)
+  set(ENV{PKG_CONFIG_ALLOW_SYSTEM_LIBS} 1)
 endmacro()
 
 macro(_pkg_restore_path_internal)
@@ -440,6 +440,8 @@ macro(_pkg_restore_path_internal)
   if(DEFINED _pkgconfig_allow_system_libs_old)
     set(ENV{PKG_CONFIG_ALLOW_SYSTEM_LIBS} "${_pkgconfig_allow_system_libs_old}")
     unset(_pkgconfig_allow_system_libs_old)
+  else()
+    unset(ENV{PKG_CONFIG_ALLOW_SYSTEM_LIBS})
   endif()
 
   unset(_extra_paths)
index afe9743..cbb6c1c 100644 (file)
@@ -22,7 +22,7 @@ if (NOT DEFINED _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR)
   message (FATAL_ERROR "FindPython: INTERNAL ERROR")
 endif()
 if (_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR EQUAL "3")
-  set(_${_PYTHON_PREFIX}_VERSIONS 3.11 3.10 3.9 3.8 3.7 3.6 3.5 3.4 3.3 3.2 3.1 3.0)
+  set(_${_PYTHON_PREFIX}_VERSIONS 3.12 3.11 3.10 3.9 3.8 3.7 3.6 3.5 3.4 3.3 3.2 3.1 3.0)
 elseif (_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR EQUAL "2")
   set(_${_PYTHON_PREFIX}_VERSIONS 2.7 2.6 2.5 2.4 2.3 2.2 2.1 2.0)
 else()
@@ -415,7 +415,6 @@ function (_PYTHON_GET_NAMES _PYTHON_PGN_NAMES)
         if (_PGN_WIN32)
           foreach (version IN LISTS _PGN_VERSION)
             string (REPLACE "." "" version_no_dots ${version})
-
             set (name "python${version_no_dots}")
             if (_PGN_DEBUG)
               string (APPEND name "_d")
@@ -423,6 +422,13 @@ function (_PYTHON_GET_NAMES _PYTHON_PGN_NAMES)
             list (APPEND names "${name}")
           endforeach()
         endif()
+
+        if (_PGN_POSIX)
+          foreach(version IN LISTS _PGN_VERSION)
+            list (APPEND names "pypy${version}-c")
+          endforeach()
+        endif()
+
         list (APPEND names ${_${_PYTHON_PREFIX}_PYPY_LIB_NAMES})
       endif()
     endif()
@@ -588,6 +594,11 @@ function (_PYTHON_GET_VERSION)
         set (${_PGV_PREFIX}VERSION_MINOR "${CMAKE_MATCH_2}" PARENT_SCOPE)
         set (${_PGV_PREFIX}VERSION "${CMAKE_MATCH_1}.${CMAKE_MATCH_2}" PARENT_SCOPE)
         set (${_PGV_PREFIX}ABI "${CMAKE_MATCH_3}" PARENT_SCOPE)
+      elseif (library_name MATCHES "pypy([23])\\.([0-9]+)-c")
+        set (${_PGV_PREFIX}VERSION_MAJOR "${CMAKE_MATCH_1}" PARENT_SCOPE)
+        set (${_PGV_PREFIX}VERSION_MINOR "${CMAKE_MATCH_2}" PARENT_SCOPE)
+        set (${_PGV_PREFIX}VERSION "${CMAKE_MATCH_1}.${CMAKE_MATCH_2}" PARENT_SCOPE)
+        set (${_PGV_PREFIX}ABI "" PARENT_SCOPE)
       elseif (library_name MATCHES "pypy(3)?-c")
         set (version "${CMAKE_MATCH_1}")
         # try to pick-up a more precise version from the path
@@ -663,7 +674,7 @@ endfunction()
 function (_PYTHON_GET_LAUNCHER _PYTHON_PGL_NAME)
   cmake_parse_arguments (PARSE_ARGV 1 _PGL "INTERPRETER;COMPILER" "" "")
 
-  unset ({_PYTHON_PGL_NAME} PARENT_SCOPE)
+  unset (${_PYTHON_PGL_NAME} PARENT_SCOPE)
 
   if ((_PGL_INTERPRETER AND NOT _${_PYTHON_PREFIX}_EXECUTABLE)
       OR (_PGL_COMPILER AND NOT _${_PYTHON_PREFIX}_COMPILER))
index 4fc40c8..7ad3587 100644 (file)
@@ -54,7 +54,7 @@ unset(_Python_NAMES)
 
 set(_PYTHON1_VERSIONS 1.6 1.5)
 set(_PYTHON2_VERSIONS 2.7 2.6 2.5 2.4 2.3 2.2 2.1 2.0)
-set(_PYTHON3_VERSIONS 3.11 3.10 3.9 3.8 3.7 3.6 3.5 3.4 3.3 3.2 3.1 3.0)
+set(_PYTHON3_VERSIONS 3.12 3.11 3.10 3.9 3.8 3.7 3.6 3.5 3.4 3.3 3.2 3.1 3.0)
 
 if(PythonInterp_FIND_VERSION)
     if(PythonInterp_FIND_VERSION_COUNT GREATER 1)
index c0caf34..43a84dd 100644 (file)
@@ -79,7 +79,7 @@ set(CMAKE_FIND_FRAMEWORK LAST)
 
 set(_PYTHON1_VERSIONS 1.6 1.5)
 set(_PYTHON2_VERSIONS 2.7 2.6 2.5 2.4 2.3 2.2 2.1 2.0)
-set(_PYTHON3_VERSIONS 3.11 3.10 3.9 3.8 3.7 3.6 3.5 3.4 3.3 3.2 3.1 3.0)
+set(_PYTHON3_VERSIONS 3.12 3.11 3.10 3.9 3.8 3.7 3.6 3.5 3.4 3.3 3.2 3.1 3.0)
 
 if(PythonLibs_FIND_VERSION)
     if(PythonLibs_FIND_VERSION_COUNT GREATER 1)
index ce0bc10..fb35ff0 100644 (file)
@@ -112,6 +112,9 @@ if(CMAKE_Fortran_COMPILER_ID STREQUAL "GNU" AND
   CMAKE_Fortran_COMPILER_VERSION VERSION_GREATER_EQUAL 12)
   target_compile_options(FortranCInterface PRIVATE "-fno-lto")
   target_compile_options(myfort PRIVATE "-flto=auto" "-ffat-lto-objects")
+endif()
+if(CMAKE_C_COMPILER_ID STREQUAL "GNU" AND
+  CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 12)
   target_compile_options(symbols PRIVATE "-flto=auto" "-ffat-lto-objects")
 endif()
 
index fb363f4..056d025 100644 (file)
@@ -332,7 +332,9 @@ endfunction()
 function(_cpack_nuget_make_files_tag)
     set(_files)
     foreach(_comp IN LISTS ARGN)
-        string(APPEND _files "        <file src=\"${_comp}/**\" target=\".\" />\n")
+        cmake_path(APPEND _comp "**")
+        cmake_path(NATIVE_PATH _comp _comp)
+        string(APPEND _files "        <file src=\"${_comp}\" target=\".\" />\n")
     endforeach()
     set(_CPACK_NUGET_FILES_TAG "<files>\n${_files}    </files>" PARENT_SCOPE)
 endfunction()
index 51d4225..7613105 100644 (file)
@@ -25,6 +25,15 @@ function(CMAKE_CHECK_LINKER_FLAG _lang _flag _var)
   set(CMAKE_REQUIRED_LINK_OPTIONS "${_flag}")
 
   check_compiler_flag_common_patterns(_common_patterns)
+
+  # Match linker warnings if the exact flag is ignored.
+  foreach(flag IN LISTS _flag)
+    string(REGEX REPLACE "([][+.*?()^$])" [[\\\1]] _flag_regex "${flag}")
+    list(APPEND _common_patterns
+      FAIL_REGEX "warning: .*${_flag_regex}.* ignored"
+      )
+  endforeach()
+
   cmake_check_source_compiles(${_lang}
     "${_lang_src}"
     ${_var}
index e7e975d..4d3de0e 100644 (file)
@@ -182,7 +182,7 @@ if("x${CMAKE_C_SIMULATE_ID}" STREQUAL "xMSVC"
     macro(__windows_compiler_clang_base lang)
       set(_COMPILE_${lang} "${_COMPILE_${lang}_MSVC}")
       __windows_compiler_msvc(${lang})
-      set(CMAKE_INCLUDE_SYSTEM_FLAG_${lang} "-imsvc ")
+      set(CMAKE_INCLUDE_SYSTEM_FLAG_${lang} "-imsvc")
     endmacro()
   else()
     cmake_policy(GET CMP0091 __WINDOWS_CLANG_CMP0091)
index 5570075..26dff05 100644 (file)
@@ -1,7 +1,7 @@
 # CMake version number components.
 set(CMake_VERSION_MAJOR 3)
 set(CMake_VERSION_MINOR 23)
-set(CMake_VERSION_PATCH 1)
+set(CMake_VERSION_PATCH 2)
 #set(CMake_VERSION_RC 0)
 set(CMake_VERSION_IS_DIRTY 0)
 
@@ -21,7 +21,7 @@ endif()
 
 if(NOT CMake_VERSION_NO_GIT)
   # If this source was exported by 'git archive', use its commit info.
-  set(git_info [==[efe08e2894 CMake 3.23.1]==])
+  set(git_info [==[a8bd06dfd4 CMake 3.23.2]==])
 
   # Otherwise, try to identify the current development source version.
   if(NOT git_info MATCHES "^([0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]?[0-9a-f]?)[0-9a-f]* "
index 92ff6df..2feca75 100644 (file)
@@ -424,7 +424,7 @@ void cmCPackIFWInstaller::GenerateInstallerFile()
   if (!this->Logo.empty()) {
     std::string srcName = cmSystemTools::GetFilenameName(this->Logo);
     std::string suffix = cmSystemTools::GetFilenameLastExtension(srcName);
-    std::string name = "cm_logo." + suffix;
+    std::string name = "cm_logo" + suffix;
     std::string path = this->Directory + "/config/" + name;
     cmsys::SystemTools::CopyFileIfDifferent(this->Logo, path);
     xout.Element("Logo", name);
@@ -461,7 +461,7 @@ void cmCPackIFWInstaller::GenerateInstallerFile()
       std::string srcName =
         cmSystemTools::GetFilenameName(this->InstallerApplicationIcon);
       std::string suffix = cmSystemTools::GetFilenameLastExtension(srcName);
-      std::string name = "cm_appicon." + suffix;
+      std::string name = "cm_appicon" + suffix;
       std::string path = this->Directory + "/config/" + name;
       cmsys::SystemTools::CopyFileIfDifferent(this->InstallerApplicationIcon,
                                               path);
@@ -476,7 +476,7 @@ void cmCPackIFWInstaller::GenerateInstallerFile()
       std::string srcName =
         cmSystemTools::GetFilenameName(this->InstallerWindowIcon);
       std::string suffix = cmSystemTools::GetFilenameLastExtension(srcName);
-      std::string name = "cm_winicon." + suffix;
+      std::string name = "cm_winicon" + suffix;
       std::string path = this->Directory + "/config/" + name;
       cmsys::SystemTools::CopyFileIfDifferent(this->InstallerWindowIcon, path);
       xout.Element("InstallerWindowIcon", name);
index 2a14ccf..7b9f6cf 100644 (file)
@@ -123,7 +123,9 @@ void cmCPackPKGGenerator::WriteDistributionFile(const char* metapackageFile,
   std::ostringstream xContents;
   cmXMLWriter xout(xContents, 1);
 
-  // Installer-wide options
+  // Installer-wide options and domains. These need to be separate from the
+  // choices and background elements added further below so that we can
+  // preserve backward compatibility.
   xout.StartElement("options");
   xout.Attribute("allow-external-scripts", "no");
   xout.Attribute("customize", "allow");
@@ -131,55 +133,69 @@ void cmCPackPKGGenerator::WriteDistributionFile(const char* metapackageFile,
     xout.Attribute("rootVolumeOnly", "false");
   }
   xout.EndElement();
+  this->CreateDomains(xout);
+
+  // In order to preserve backward compatibility, all elements added below
+  // here need to be made available in a variable named
+  // CPACK_PACKAGEMAKER_CHOICES. The above elements are new and only appear
+  // in the CPACK_APPLE_PKG_INSTALLER_CONTENT variable, which is a superset
+  // of what CPACK_PACKAGEMAKER_CHOICES used to provide. The renaming reflects
+  // the fact that CMake has deprecated the PackageMaker generator.
 
   // Create the choice outline, which provides a tree-based view of
   // the components in their groups.
-  xout.StartElement("choices-outline");
+  std::ostringstream choiceOut;
+  cmXMLWriter xChoiceOut(choiceOut, 1);
+  xChoiceOut.StartElement("choices-outline");
 
   // Emit the outline for the groups
   for (auto const& group : this->ComponentGroups) {
     if (group.second.ParentGroup == nullptr) {
-      CreateChoiceOutline(group.second, xout);
+      CreateChoiceOutline(group.second, xChoiceOut);
     }
   }
 
   // Emit the outline for the non-grouped components
   for (auto const& comp : this->Components) {
     if (!comp.second.Group) {
-      xout.StartElement("line");
-      xout.Attribute("choice", comp.first + "Choice");
-      xout.Content(""); // Avoid self-closing tag.
-      xout.EndElement();
+      xChoiceOut.StartElement("line");
+      xChoiceOut.Attribute("choice", comp.first + "Choice");
+      xChoiceOut.Content(""); // Avoid self-closing tag.
+      xChoiceOut.EndElement();
     }
   }
   if (!this->PostFlightComponent.Name.empty()) {
-    xout.StartElement("line");
-    xout.Attribute("choice", PostFlightComponent.Name + "Choice");
-    xout.Content(""); // Avoid self-closing tag.
-    xout.EndElement();
+    xChoiceOut.StartElement("line");
+    xChoiceOut.Attribute("choice", PostFlightComponent.Name + "Choice");
+    xChoiceOut.Content(""); // Avoid self-closing tag.
+    xChoiceOut.EndElement();
   }
-  xout.EndElement(); // choices-outline>
+  xChoiceOut.EndElement(); // choices-outline>
 
   // Create the actual choices
   for (auto const& group : this->ComponentGroups) {
-    CreateChoice(group.second, xout);
+    CreateChoice(group.second, xChoiceOut);
   }
   for (auto const& comp : this->Components) {
-    CreateChoice(comp.second, xout);
+    CreateChoice(comp.second, xChoiceOut);
   }
 
   if (!this->PostFlightComponent.Name.empty()) {
-    CreateChoice(PostFlightComponent, xout);
+    CreateChoice(PostFlightComponent, xChoiceOut);
   }
 
-  this->CreateDomains(xout);
-
-  // default background
-  this->CreateBackground(nullptr, metapackageFile, genName, xout);
+  // default background. These are not strictly part of the choices, but they
+  // must be included in CPACK_PACKAGEMAKER_CHOICES to preserve backward
+  // compatibility.
+  this->CreateBackground(nullptr, metapackageFile, genName, xChoiceOut);
   // Dark Aqua
-  this->CreateBackground("darkAqua", metapackageFile, genName, xout);
+  this->CreateBackground("darkAqua", metapackageFile, genName, xChoiceOut);
 
-  this->SetOption("CPACK_APPLE_PKG_INSTALLER_CONTENT", xContents.str());
+  // Provide the content for substitution into the template. Support both the
+  // old and new variables.
+  this->SetOption("CPACK_PACKAGEMAKER_CHOICES", choiceOut.str());
+  this->SetOption("CPACK_APPLE_PKG_INSTALLER_CONTENT",
+                  cmStrCat(xContents.str(), "    ", choiceOut.str()));
 
   // Create the distribution.dist file in the metapackage to turn it
   // into a distribution package.
index 11b3b35..8381e86 100644 (file)
@@ -35,11 +35,6 @@ cmCursesMainForm::cmCursesMainForm(std::vector<std::string> args,
   : Args(std::move(args))
   , InitialWidth(initWidth)
 {
-  this->HasNonStatusOutputs = false;
-  this->NumberOfPages = 0;
-  this->AdvancedMode = false;
-  this->NumberOfVisibleEntries = 0;
-  this->OkToGenerate = false;
   this->HelpMessage.emplace_back(
     "Welcome to ccmake, curses based user interface for CMake.");
   this->HelpMessage.emplace_back();
@@ -54,7 +49,6 @@ cmCursesMainForm::cmCursesMainForm(std::vector<std::string> args,
     cmStrCat(cmSystemTools::GetProgramPath(this->Args[0]), "/cmake");
   this->Args[0] = whereCMake;
   this->CMakeInstance->SetArgs(this->Args);
-  this->SearchMode = false;
 }
 
 cmCursesMainForm::~cmCursesMainForm()
@@ -99,13 +93,14 @@ void cmCursesMainForm::InitializeUI()
 
   int entrywidth = this->InitialWidth - 35;
 
-  if (count == 0) {
-    // If cache is empty, display a label saying so and a
-    // dummy entry widget (does not respond to input)
-    cmCursesCacheEntryComposite comp("EMPTY CACHE", 30, 30);
-    comp.Entry = cm::make_unique<cmCursesDummyWidget>(1, 1, 1, 1);
-    newEntries.emplace_back(std::move(comp));
-  } else {
+  // Add a label to display when cache is empty
+  // dummy entry widget (does not respond to input)
+  this->EmptyCacheEntry =
+    cm::make_unique<cmCursesCacheEntryComposite>("EMPTY CACHE", 30, 30);
+  this->EmptyCacheEntry->Entry =
+    cm::make_unique<cmCursesDummyWidget>(1, 1, 1, 1);
+
+  if (count > 0) {
     // Create the composites.
 
     // First add entries which are new
@@ -196,11 +191,11 @@ void cmCursesMainForm::RePost()
     this->Fields.push_back(entry.Entry->Field);
   }
   // if no cache entries there should still be one dummy field
-  if (this->Fields.empty()) {
-    const auto& front = this->Entries.front();
-    this->Fields.push_back(front.Label->Field);
-    this->Fields.push_back(front.IsNewLabel->Field);
-    this->Fields.push_back(front.Entry->Field);
+  this->IsEmpty = this->Fields.empty();
+  if (this->IsEmpty) {
+    this->Fields.push_back(this->EmptyCacheEntry->Label->Field);
+    this->Fields.push_back(this->EmptyCacheEntry->IsNewLabel->Field);
+    this->Fields.push_back(this->EmptyCacheEntry->Entry->Field);
     this->NumberOfVisibleEntries = 1;
   }
   // Has to be null terminated.
@@ -875,7 +870,7 @@ void cmCursesMainForm::HandleInput()
         }
       }
       // delete cache entry
-      else if (key == 'd' && this->NumberOfVisibleEntries) {
+      else if (key == 'd' && this->NumberOfVisibleEntries && !this->IsEmpty) {
         this->OkToGenerate = false;
         FIELD* cur = current_field(this->Form);
         size_t findex = field_index(cur);
index c6db66f..112b7e8 100644 (file)
@@ -138,7 +138,7 @@ protected:
   // Output produced by the last pass
   std::vector<std::string> Outputs;
   // Did the last pass produced outputs of interest (errors, warnings, ...)
-  bool HasNonStatusOutputs;
+  bool HasNonStatusOutputs = false;
   // Last progress bar
   std::string LastProgress;
 
@@ -155,17 +155,19 @@ protected:
   // Fields displayed. Includes labels, new entry markers, entries
   std::vector<FIELD*> Fields;
   // Number of entries shown (depends on mode -normal or advanced-)
-  size_t NumberOfVisibleEntries;
-  bool AdvancedMode;
+  size_t NumberOfVisibleEntries = 0;
+  bool AdvancedMode = false;
   // Did the iteration converge (no new entries) ?
-  bool OkToGenerate;
+  bool OkToGenerate = false;
   // Number of pages displayed
-  int NumberOfPages;
+  int NumberOfPages = 0;
+  bool IsEmpty = false;
+  std::unique_ptr<cmCursesCacheEntryComposite> EmptyCacheEntry;
 
   int InitialWidth;
   std::unique_ptr<cmake> CMakeInstance;
 
   std::string SearchString;
   std::string OldSearchString;
-  bool SearchMode;
+  bool SearchMode = false;
 };
index a47f1e5..2773b3b 100644 (file)
@@ -2,6 +2,7 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include "cmExportBuildFileGenerator.h"
 
+#include <algorithm>
 #include <map>
 #include <memory>
 #include <set>
@@ -15,7 +16,6 @@
 #include "cmGeneratorExpression.h"
 #include "cmGeneratorTarget.h"
 #include "cmGlobalGenerator.h"
-#include "cmListFileCache.h"
 #include "cmLocalGenerator.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
@@ -362,16 +362,93 @@ std::string cmExportBuildFileGenerator::InstallNameDir(
   return install_name_dir;
 }
 
+namespace {
+bool EntryIsContextSensitive(
+  const std::unique_ptr<cmCompiledGeneratorExpression>& cge)
+{
+  return cge->GetHadContextSensitiveCondition();
+}
+}
+
 std::string cmExportBuildFileGenerator::GetFileSetDirectories(
-  cmGeneratorTarget* /*gte*/, cmFileSet* fileSet, cmTargetExport* /*te*/)
+  cmGeneratorTarget* gte, cmFileSet* fileSet, cmTargetExport* /*te*/)
 {
-  return cmOutputConverter::EscapeForCMake(
-    cmJoin(fileSet->GetDirectoryEntries(), ";"));
+  std::vector<std::string> resultVector;
+
+  auto configs =
+    gte->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
+  auto directoryEntries = fileSet->CompileDirectoryEntries();
+
+  for (auto const& config : configs) {
+    auto directories = fileSet->EvaluateDirectoryEntries(
+      directoryEntries, gte->LocalGenerator, config, gte);
+
+    bool const contextSensitive =
+      std::any_of(directoryEntries.begin(), directoryEntries.end(),
+                  EntryIsContextSensitive);
+
+    for (auto const& directory : directories) {
+      auto dest = cmOutputConverter::EscapeForCMake(
+        directory, cmOutputConverter::WrapQuotes::NoWrap);
+
+      if (contextSensitive && configs.size() != 1) {
+        resultVector.push_back(
+          cmStrCat("\"$<$<CONFIG:", config, ">:", dest, ">\""));
+      } else {
+        resultVector.push_back(cmStrCat('"', dest, '"'));
+        break;
+      }
+    }
+  }
+
+  return cmJoin(resultVector, " ");
 }
 
-std::string cmExportBuildFileGenerator::GetFileSetFiles(
-  cmGeneratorTarget* /*gte*/, cmFileSet* fileSet, cmTargetExport* /*te*/)
+std::string cmExportBuildFileGenerator::GetFileSetFiles(cmGeneratorTarget* gte,
+                                                        cmFileSet* fileSet,
+                                                        cmTargetExport* /*te*/)
 {
-  return cmOutputConverter::EscapeForCMake(
-    cmJoin(fileSet->GetFileEntries(), ";"));
+  std::vector<std::string> resultVector;
+
+  auto configs =
+    gte->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
+
+  auto fileEntries = fileSet->CompileFileEntries();
+  auto directoryEntries = fileSet->CompileDirectoryEntries();
+
+  for (auto const& config : configs) {
+    auto directories = fileSet->EvaluateDirectoryEntries(
+      directoryEntries, gte->LocalGenerator, config, gte);
+
+    std::map<std::string, std::vector<std::string>> files;
+    for (auto const& entry : fileEntries) {
+      fileSet->EvaluateFileEntry(directories, files, entry,
+                                 gte->LocalGenerator, config, gte);
+    }
+
+    bool const contextSensitive =
+      std::any_of(directoryEntries.begin(), directoryEntries.end(),
+                  EntryIsContextSensitive) ||
+      std::any_of(fileEntries.begin(), fileEntries.end(),
+                  EntryIsContextSensitive);
+
+    for (auto const& it : files) {
+      for (auto const& filename : it.second) {
+        auto escapedFile = cmOutputConverter::EscapeForCMake(
+          filename, cmOutputConverter::WrapQuotes::NoWrap);
+        if (contextSensitive && configs.size() != 1) {
+          resultVector.push_back(
+            cmStrCat("\"$<$<CONFIG:", config, ">:", escapedFile, ">\""));
+        } else {
+          resultVector.push_back(cmStrCat('"', escapedFile, '"'));
+        }
+      }
+    }
+
+    if (!(contextSensitive && configs.size() != 1)) {
+      break;
+    }
+  }
+
+  return cmJoin(resultVector, " ");
 }
index c86001a..a52e66a 100644 (file)
@@ -180,7 +180,9 @@ bool cmGeneratedFileStreamBase::Close()
   // Else, the destination was not replaced.
   //
   // Always delete the temporary file. We never want it to stay around.
-  cmSystemTools::RemoveFile(this->TempName);
+  if (!this->TempName.empty()) {
+    cmSystemTools::RemoveFile(this->TempName);
+  }
 
   return replaced;
 }
index a8bc91c..fec4679 100644 (file)
@@ -1208,8 +1208,10 @@ bool cmGeneratorTarget::IsInBuildSystem() const
     case cmStateEnums::GLOBAL_TARGET:
       return true;
     case cmStateEnums::INTERFACE_LIBRARY:
-      // An INTERFACE library is in the build system if it has SOURCES.
-      if (!this->SourceEntries.empty()) {
+      // An INTERFACE library is in the build system if it has SOURCES or
+      // HEADER_SETS.
+      if (!this->SourceEntries.empty() ||
+          !this->Target->GetHeaderSetsEntries().empty()) {
         return true;
       }
       break;
index 8ce7ed1..bb08215 100644 (file)
@@ -741,9 +741,9 @@ bool HandleTargetsMode(std::vector<std::string> const& args,
                   [=](const cmInstallCommandFileSetArguments& fileSetArg)
                     -> bool { return fileSetArg.GetFileSet() == name; });
               })) {
-          status.SetError(cmStrCat(
-            "TARGETS target ", target.GetName(),
-            " is exported but not all of its file sets are installed"));
+          status.SetError(cmStrCat("TARGETS target ", target.GetName(),
+                                   " is exported but not all of its interface "
+                                   "file sets are installed"));
           return false;
         }
 
index 26f255d..4dfdfae 100644 (file)
@@ -236,6 +236,7 @@ bool cmRuntimeDependencyArchive::GetGetRuntimeDependenciesCommand(
   cmGlobalGenerator* gg = this->GetMakefile()->GetGlobalGenerator();
 
   // Add newer Visual Studio paths
+  AddVisualStudioPath(paths, "Visual Studio 17 ", 17, gg);
   AddVisualStudioPath(paths, "Visual Studio 16 ", 16, gg);
   AddVisualStudioPath(paths, "Visual Studio 15 ", 15, gg);
 
index 9045a4d..0b27dfb 100644 (file)
@@ -171,14 +171,15 @@ void cmVisualStudioGeneratorOptions::FixCudaCodeGeneration()
     code.clear();
   }
 
-  if (arch.empty() && gencode.empty()) {
-    return;
-  }
-
   // Create a CodeGeneration field with [arch],[code] syntax in each entry.
   // CUDA will convert it to `-gencode=arch=[arch],code="[code],[arch]"`.
   FlagValue& result = this->FlagMap["CodeGeneration"];
 
+  // If there are no flags, leave the CodeGeneration field empty.
+  if (arch.empty() && gencode.empty()) {
+    return;
+  }
+
   // First entries for the -arch=<arch> [-code=<code>,...] pair.
   if (!arch.empty()) {
     std::string arch_name = arch[0];
index 26b4bae..3ddb890 100644 (file)
@@ -164,6 +164,7 @@ function(run_cmake test)
 
     "|[^\n]*install_name_tool: warning: changes being made to the file will invalidate the code signature in:"
     "|[^\n]*xcodebuild[^\n]*DVTPlugInManager"
+    "|[^\n]*xcodebuild[^\n]*Requested but did not find extension point with identifier"
     "|[^\n]*xcodebuild[^\n]*warning: file type[^\n]*is based on missing file type"
     "|[^\n]*objc[^\n]*: Class [^\n]* One of the two will be used. Which one is undefined."
     "|[^\n]*is a member of multiple groups"
diff --git a/Tests/RunCMake/target_sources/FileSetGeneratedDependency.cmake b/Tests/RunCMake/target_sources/FileSetGeneratedDependency.cmake
new file mode 100644 (file)
index 0000000..9e91929
--- /dev/null
@@ -0,0 +1,12 @@
+enable_language(C)
+
+add_library(lib INTERFACE)
+add_custom_command(
+  OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/dependency.h
+  COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/FileSetGeneratedDependency.h.in ${CMAKE_CURRENT_BINARY_DIR}/dependency.h
+  VERBATIM
+  )
+target_sources(lib PUBLIC FILE_SET HEADERS BASE_DIRS ${CMAKE_CURRENT_BINARY_DIR} FILES ${CMAKE_CURRENT_BINARY_DIR}/dependency.h)
+
+add_executable(exe dependency.c)
+target_link_libraries(exe PRIVATE lib)
diff --git a/Tests/RunCMake/target_sources/FileSetGeneratedDependency.h.in b/Tests/RunCMake/target_sources/FileSetGeneratedDependency.h.in
new file mode 100644 (file)
index 0000000..40a8c17
--- /dev/null
@@ -0,0 +1 @@
+/* empty */
index 7e790c7..8ef8e7d 100644 (file)
@@ -19,20 +19,54 @@ include("${export_build_dir}/install/lib/cmake/export.cmake")
 assert_prop_eq(export::lib1 HEADER_SETS "")
 assert_prop_eq(export::lib1 INTERFACE_HEADER_SETS "HEADERS;b;c;d;dir3;e;f;g")
 assert_prop_eq(export::lib1 HEADER_SET "${CMAKE_CURRENT_SOURCE_DIR}/error.c")
-assert_prop_eq(export::lib1 HEADER_DIRS "${CMAKE_CURRENT_SOURCE_DIR}")
+if (_multi_config)
+  assert_prop_eq(export::lib1 HEADER_DIRS "${CMAKE_CURRENT_SOURCE_DIR};${CMAKE_CURRENT_SOURCE_DIR}")
+else ()
+  assert_prop_eq(export::lib1 HEADER_DIRS "${CMAKE_CURRENT_SOURCE_DIR}")
+endif ()
 assert_prop_eq(export::lib1 HEADER_SET_b "${CMAKE_CURRENT_SOURCE_DIR}/h2.h")
-assert_prop_eq(export::lib1 HEADER_DIRS_b "${CMAKE_CURRENT_SOURCE_DIR}")
-assert_prop_eq(export::lib1 HEADER_SET_c "$<1:dir/dir.h>")
-assert_prop_eq(export::lib1 HEADER_DIRS_c "$<1:${CMAKE_CURRENT_SOURCE_DIR}/dir>")
-assert_prop_eq(export::lib1 HEADER_SET_d "${CMAKE_CURRENT_SOURCE_DIR}/$<IF:$<CONFIG:Debug>,debug,release>/empty.h")
-assert_prop_eq(export::lib1 HEADER_DIRS_d "${CMAKE_CURRENT_SOURCE_DIR}")
-assert_prop_eq(export::lib1 HEADER_SET_e "${CMAKE_CURRENT_SOURCE_DIR}/$<IF:$<CONFIG:Debug>,debug,release>/empty2.h")
-assert_prop_eq(export::lib1 HEADER_DIRS_e "${CMAKE_CURRENT_SOURCE_DIR}/$<IF:$<CONFIG:Debug>,debug,release>")
+if (_multi_config)
+  assert_prop_eq(export::lib1 HEADER_DIRS_b "${CMAKE_CURRENT_SOURCE_DIR};${CMAKE_CURRENT_SOURCE_DIR}")
+else ()
+  assert_prop_eq(export::lib1 HEADER_DIRS_b "${CMAKE_CURRENT_SOURCE_DIR}")
+endif ()
+assert_prop_eq(export::lib1 HEADER_SET_c "${CMAKE_CURRENT_SOURCE_DIR}/dir/dir.h")
+if (_multi_config)
+  assert_prop_eq(export::lib1 HEADER_DIRS_c "${CMAKE_CURRENT_SOURCE_DIR}/dir;${CMAKE_CURRENT_SOURCE_DIR}/dir")
+else ()
+  assert_prop_eq(export::lib1 HEADER_DIRS_c "${CMAKE_CURRENT_SOURCE_DIR}/dir")
+endif ()
+if (_multi_config)
+  assert_prop_eq(export::lib1 HEADER_SET_d "$<$<CONFIG:Debug>:${CMAKE_CURRENT_SOURCE_DIR}/debug/empty.h>;$<$<CONFIG:Release>:${CMAKE_CURRENT_SOURCE_DIR}/release/empty.h>")
+  assert_prop_eq(export::lib1 HEADER_DIRS_d "${CMAKE_CURRENT_SOURCE_DIR};${CMAKE_CURRENT_SOURCE_DIR}")
+else ()
+  assert_prop_eq(export::lib1 HEADER_SET_d "${CMAKE_CURRENT_SOURCE_DIR}/debug/empty.h")
+  assert_prop_eq(export::lib1 HEADER_DIRS_d "${CMAKE_CURRENT_SOURCE_DIR}")
+endif ()
+if (_multi_config)
+  assert_prop_eq(export::lib1 HEADER_SET_e "$<$<CONFIG:Debug>:${CMAKE_CURRENT_SOURCE_DIR}/debug/empty2.h>;$<$<CONFIG:Release>:${CMAKE_CURRENT_SOURCE_DIR}/release/empty2.h>")
+  assert_prop_eq(export::lib1 HEADER_DIRS_e "$<$<CONFIG:Debug>:${CMAKE_CURRENT_SOURCE_DIR}/debug>;$<$<CONFIG:Release>:${CMAKE_CURRENT_SOURCE_DIR}/release>")
+else ()
+  assert_prop_eq(export::lib1 HEADER_SET_e "${CMAKE_CURRENT_SOURCE_DIR}/debug/empty2.h")
+  assert_prop_eq(export::lib1 HEADER_DIRS_e "${CMAKE_CURRENT_SOURCE_DIR}/debug")
+endif ()
 assert_prop_eq(export::lib1 HEADER_SET_f "${CMAKE_CURRENT_SOURCE_DIR}/empty3.h")
-assert_prop_eq(export::lib1 HEADER_DIRS_f "${CMAKE_CURRENT_SOURCE_DIR}")
+if (_multi_config)
+  assert_prop_eq(export::lib1 HEADER_DIRS_f "${CMAKE_CURRENT_SOURCE_DIR};${CMAKE_CURRENT_SOURCE_DIR}")
+else ()
+  assert_prop_eq(export::lib1 HEADER_DIRS_f "${CMAKE_CURRENT_SOURCE_DIR}")
+endif ()
 assert_prop_eq(export::lib1 HEADER_SET_g "${CMAKE_CURRENT_SOURCE_DIR}/dir1/file1.h;${CMAKE_CURRENT_SOURCE_DIR}/dir2/file2.h")
-assert_prop_eq(export::lib1 HEADER_DIRS_g "${CMAKE_CURRENT_SOURCE_DIR}/dir1;${CMAKE_CURRENT_SOURCE_DIR}/dir2")
-assert_prop_eq(export::lib1 INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_SOURCE_DIR};${CMAKE_CURRENT_SOURCE_DIR};$<1:${CMAKE_CURRENT_SOURCE_DIR}/dir>;${CMAKE_CURRENT_SOURCE_DIR};${CMAKE_CURRENT_SOURCE_DIR}/$<IF:$<CONFIG:Debug>,debug,release>;${CMAKE_CURRENT_SOURCE_DIR};${CMAKE_CURRENT_SOURCE_DIR}/dir1;${CMAKE_CURRENT_SOURCE_DIR}/dir2;${CMAKE_CURRENT_SOURCE_DIR}/dir3;$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>;$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>;$<BUILD_INTERFACE:$<1:${CMAKE_CURRENT_SOURCE_DIR}/dir>>;$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>;$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/$<IF:$<CONFIG:Debug>,debug,release>>;$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>;$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/dir1>;$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/dir2>;$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/dir3>")
+if (_multi_config)
+  assert_prop_eq(export::lib1 HEADER_DIRS_g "${CMAKE_CURRENT_SOURCE_DIR}/dir1;${CMAKE_CURRENT_SOURCE_DIR}/dir1")
+else ()
+  assert_prop_eq(export::lib1 HEADER_DIRS_g "${CMAKE_CURRENT_SOURCE_DIR}/dir1")
+endif ()
+if (_multi_config)
+  assert_prop_eq(export::lib1 INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_SOURCE_DIR};${CMAKE_CURRENT_SOURCE_DIR};$<1:${CMAKE_CURRENT_SOURCE_DIR}/dir>;${CMAKE_CURRENT_SOURCE_DIR};${CMAKE_CURRENT_SOURCE_DIR}/$<IF:$<CONFIG:Debug>,debug,release>;${CMAKE_CURRENT_SOURCE_DIR};${CMAKE_CURRENT_SOURCE_DIR}/dir1;${CMAKE_CURRENT_SOURCE_DIR}/dir2;${CMAKE_CURRENT_SOURCE_DIR}/dir3;$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>;$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>;$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>;$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>;$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/dir>;$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/dir>;$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>;$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>;$<BUILD_INTERFACE:$<$<CONFIG:Debug>:${CMAKE_CURRENT_SOURCE_DIR}/debug>>;$<BUILD_INTERFACE:$<$<CONFIG:Release>:${CMAKE_CURRENT_SOURCE_DIR}/release>>;$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>;$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>;$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/dir1>;$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/dir1>;$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/dir3>;$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/dir3>")
+else ()
+  assert_prop_eq(export::lib1 INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_SOURCE_DIR};${CMAKE_CURRENT_SOURCE_DIR};$<1:${CMAKE_CURRENT_SOURCE_DIR}/dir>;${CMAKE_CURRENT_SOURCE_DIR};${CMAKE_CURRENT_SOURCE_DIR}/$<IF:$<CONFIG:Debug>,debug,release>;${CMAKE_CURRENT_SOURCE_DIR};${CMAKE_CURRENT_SOURCE_DIR}/dir1;${CMAKE_CURRENT_SOURCE_DIR}/dir2;${CMAKE_CURRENT_SOURCE_DIR}/dir3;$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>;$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>;$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/dir>;$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>;$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/debug>;$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>;$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/dir1>;$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/dir3>")
+endif ()
 
 assert_prop_eq(install::lib1 HEADER_SETS "")
 assert_prop_eq(install::lib1 INTERFACE_HEADER_SETS "HEADERS;b;c;d;dir3;e;f;g")
index 694f227..8b06ebd 100644 (file)
@@ -1,5 +1,5 @@
 ^CMake Error at FileSetInstallMissingSetsInterface\.cmake:[0-9]+ \(install\):
-  install TARGETS target lib1 is exported but not all of its file sets are
-  installed
+  install TARGETS target lib1 is exported but not all of its interface file
+  sets are installed
 Call Stack \(most recent call first\):
   CMakeLists\.txt:[0-9]+ \(include\)$
index 8429c96..e78ee9d 100644 (file)
@@ -43,6 +43,15 @@ if(APPLE)
   run_cmake(FileSetFramework)
 endif()
 
+set(RunCMake_TEST_NO_CLEAN 1)
+set(RunCMake_TEST_BINARY_DIR "${RunCMake_BINARY_DIR}/FileSetGeneratedDependency-build")
+file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
+file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
+run_cmake(FileSetGeneratedDependency)
+run_cmake_command(FileSetGeneratedDependency-build ${CMAKE_COMMAND} --build . --config Debug)
+unset(RunCMake_TEST_BINARY_DIR)
+unset(RunCMake_TEST_NO_CLEAN)
+
 set(RunCMake_TEST_OPTIONS -DCMAKE_POLICY_DEFAULT_CMP0115=NEW)
 run_cmake(FileSetFileNoExist)
 unset(RunCMake_TEST_OPTIONS)
diff --git a/Tests/RunCMake/target_sources/dependency.c b/Tests/RunCMake/target_sources/dependency.c
new file mode 100644 (file)
index 0000000..2f2dd25
--- /dev/null
@@ -0,0 +1,6 @@
+#include <dependency.h>
+
+int main(void)
+{
+  return 0;
+}
index 3a24e2b..8f5b13a 100755 (executable)
@@ -8,7 +8,7 @@ readonly name="LibArchive"
 readonly ownership="LibArchive Upstream <libarchive-discuss@googlegroups.com>"
 readonly subtree="Utilities/cmlibarchive"
 readonly repo="https://github.com/libarchive/libarchive.git"
-readonly tag="v3.5.1"
+readonly tag="v3.5.3"
 readonly shortlog=false
 readonly paths="
   CMakeLists.txt
index d2bfb61..51c035e 100644 (file)
@@ -68,7 +68,7 @@ if(SPHINX_HTML)
 
   # we provide the path to the produced html output in the console
   # for tools that support URI protocol schemes
-  set(html_extra_commands
+  set(html_post_commands
     COMMAND ${CMAKE_COMMAND} -E echo "sphinx-build html: HTML documentation generated in file://${CMAKE_CURRENT_BINARY_DIR}/html/index.html"
   )
 
@@ -94,7 +94,7 @@ if(SPHINX_INFO)
 
   # Sphinx texinfo builder supports .info, .txt, .html and .pdf output.
   # SPHINX_INFO controls the .info output.
-  set(texinfo_extra_commands
+  set(texinfo_post_commands
     COMMAND ${MAKEINFO_EXECUTABLE} --no-split -o
       ${CMAKE_CURRENT_BINARY_DIR}/texinfo/cmake.info
       ${CMAKE_CURRENT_BINARY_DIR}/texinfo/cmake.texi
@@ -112,7 +112,7 @@ if(SPHINX_QTHELP)
   endif()
   list(APPEND doc_formats qthelp)
 
-  set(qthelp_extra_commands
+  set(qthelp_post_commands
     # Workaround for assistant prior to
     # https://codereview.qt-project.org/#change,82250 in Qt 4.
     COMMAND ${CMAKE_COMMAND} "-DCSS_DIR=${CMAKE_CURRENT_BINARY_DIR}/qthelp/_static"
@@ -148,7 +148,11 @@ if(CMake_SPHINX_CMAKE_ORG)
     list(APPEND doc_html_opts -A outdated=1)
   endif()
 
-  list(APPEND qthelp_extra_commands
+  list(APPEND html_pre_commands
+    COMMAND ${CMAKE_COMMAND} -Dversion=${CMake_VERSION} -P ${CMAKE_CURRENT_SOURCE_DIR}/tutorial_archive.cmake
+    )
+
+  list(APPEND qthelp_post_commands
     COMMAND ${CMAKE_COMMAND} -E copy
       "${CMAKE_CURRENT_BINARY_DIR}/qthelp/CMake.qch"
       "${CMAKE_CURRENT_BINARY_DIR}/html/CMake.qch"
@@ -170,6 +174,7 @@ foreach(format ${doc_formats})
     # arguments in peculiar order
     add_custom_command(
       OUTPUT ${doc_format_output}
+      ${${format}_pre_commands}
       COMMAND ${SPHINX_EXECUTABLE}
               -M ${format}
               ${CMake_SOURCE_DIR}/Help
@@ -179,7 +184,7 @@ foreach(format ${doc_formats})
               ${sphinx_flags}
               ${doc_${format}_opts}
               > ${doc_format_log} # log stdout, pass stderr
-      ${${format}_extra_commands}
+      ${${format}_post_commands}
       DEPENDS ${doc_format_last}
       COMMENT "sphinx-build ${format}: see Utilities/Sphinx/${doc_format_log}"
       VERBATIM
@@ -188,6 +193,7 @@ foreach(format ${doc_formats})
     # other formats use standard builder (-b) mode
     add_custom_command(
       OUTPUT ${doc_format_output}
+      ${${format}_pre_commands}
       COMMAND ${SPHINX_EXECUTABLE}
               -c ${CMAKE_CURRENT_BINARY_DIR}
               -d ${CMAKE_CURRENT_BINARY_DIR}/${doctrees}
@@ -197,7 +203,7 @@ foreach(format ${doc_formats})
               ${CMake_SOURCE_DIR}/Help
               ${CMAKE_CURRENT_BINARY_DIR}/${format}
               > ${doc_format_log} # log stdout, pass stderr
-      ${${format}_extra_commands}
+      ${${format}_post_commands}
       DEPENDS ${doc_format_last}
       COMMENT "sphinx-build ${format}: see Utilities/Sphinx/${doc_format_log}"
       VERBATIM
diff --git a/Utilities/Sphinx/tutorial_archive.cmake b/Utilities/Sphinx/tutorial_archive.cmake
new file mode 100644 (file)
index 0000000..212a622
--- /dev/null
@@ -0,0 +1,42 @@
+if(NOT version)
+  message(FATAL_ERROR "Pass -Dversion=")
+endif()
+
+# Name of the archive and its top-level directory.
+set(archive_name "cmake-${version}-tutorial-source")
+
+# Base directory for CMake Documentation.
+set(help_dir "${CMAKE_CURRENT_LIST_DIR}/../../Help")
+cmake_path(ABSOLUTE_PATH help_dir NORMALIZE)
+
+# Collect the non-documentation part of the tutorial directory.
+file(COPY "${help_dir}/guide/tutorial/"
+  DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/${archive_name}"
+  NO_SOURCE_PERMISSIONS
+  PATTERN *.rst EXCLUDE
+  PATTERN source.txt EXCLUDE
+  )
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/${archive_name}/README.txt" [[
+This directory contains source code examples for the CMake Tutorial.
+Each step has its own subdirectory containing code that may be used as a
+starting point. The tutorial examples are progressive so that each step
+provides the complete solution for the previous step.
+]])
+
+# Create an archive containing the tutorial source examples.
+file(MAKE_DIRECTORY "${help_dir}/_generated")
+file(ARCHIVE_CREATE
+  OUTPUT "${help_dir}/_generated/${archive_name}.zip"
+  PATHS "${CMAKE_CURRENT_BINARY_DIR}/${archive_name}"
+  FORMAT zip
+  )
+
+# Write a reStructuredText snippet included from the tutorial index.
+file(WRITE "${help_dir}/guide/tutorial/source.txt" "
+.. |tutorial_source| replace::
+  The tutorial source code examples are available in
+  :download:`this archive </_generated/${archive_name}.zip>`.
+")
+
+# Remove temporary directory.
+file(REMOVE_RECURSE "${CMAKE_CURRENT_BINARY_DIR}/${archive_name}")
index 7e38df9..c7b3c8a 100644 (file)
@@ -118,6 +118,7 @@ if(WIN32)
   set(HAVE_LIBWS2_32 1)
   set(HAVE_LIMITS_H 1)
   set(HAVE_LINK 0)
+  set(HAVE_LINKAT 0)
   set(HAVE_LINUX_FIEMAP_H 0)
   set(HAVE_LINUX_FS_H 0)
   set(HAVE_LINUX_MAGIC_H 0)
@@ -184,6 +185,7 @@ if(WIN32)
   set(HAVE_STROPTS_H 0)
   set(HAVE__STRTOI64 1)
   set(HAVE_STRTOLL 1)
+  set(HAVE_STRUCT_STATFS 0)
   set(HAVE_STRUCT_STATFS_F_NAMEMAX 0)
   set(HAVE_STRUCT_STAT_ST_BIRTHTIME 0)
   set(HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC 0)
index 2a788ff..5e9e137 100644 (file)
@@ -81,7 +81,7 @@ math(EXPR INTERFACE_VERSION  "13 + ${_minor}")
 # ?? Should there be more here ??
 SET(SOVERSION "${INTERFACE_VERSION}")
 
-# Enalbe CMAKE_PUSH_CHECK_STATE() and CMAKE_POP_CHECK_STATE() macros
+# Enable CMAKE_PUSH_CHECK_STATE() and CMAKE_POP_CHECK_STATE() macros
 # saving and restoring the state of the variables.
 INCLUDE(${CMake_SOURCE_DIR}/Modules/CMakePushCheckState.cmake)
 
@@ -405,7 +405,7 @@ IF(WIN32 AND NOT CMAKE_CL_64 AND NOT CYGWIN)
   SET(__GNUWIN32PATH "C:/Program Files/GnuWin32")
 ENDIF(WIN32 AND NOT CMAKE_CL_64 AND NOT CYGWIN)
 IF(DEFINED __GNUWIN32PATH AND EXISTS "${__GNUWIN32PATH}")
-  # You have to add a path availabel DLL file into PATH environment variable.
+  # You have to add a path available DLL file into PATH environment variable.
   # Maybe DLL path is "C:/Program Files/GnuWin32/bin".
   # The zlib and the bzip2 Setup program have installed programs and DLLs into
   # "C:/Program Files/GnuWin32" by default.
@@ -1044,7 +1044,7 @@ MACRO(CHECK_ICONV LIB TRY_ICONV_CONST)
         CMAKE_C_COMPILER_ID MATCHES "^Clang$")
       #
       # During checking iconv proto type, we should use -Werror to avoid the
-      # success of iconv detection with a warnig which success is a miss
+      # success of iconv detection with a warning 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")
@@ -1380,6 +1380,7 @@ CHECK_FUNCTION_EXISTS_GLIBC(lchflags HAVE_LCHFLAGS)
 CHECK_FUNCTION_EXISTS_GLIBC(lchmod HAVE_LCHMOD)
 CHECK_FUNCTION_EXISTS_GLIBC(lchown HAVE_LCHOWN)
 CHECK_FUNCTION_EXISTS_GLIBC(link HAVE_LINK)
+CHECK_FUNCTION_EXISTS_GLIBC(linkat HAVE_LINKAT)
 CHECK_FUNCTION_EXISTS_GLIBC(localtime_r HAVE_LOCALTIME_R)
 CHECK_FUNCTION_EXISTS_GLIBC(lstat HAVE_LSTAT)
 CHECK_FUNCTION_EXISTS_GLIBC(lutimes HAVE_LUTIMES)
@@ -1449,6 +1450,10 @@ CHECK_C_SOURCE_COMPILES(
   "#include <sys/types.h>\n#include <sys/mount.h>\nint main(void) { struct xvfsconf v; return sizeof(v);}"
   HAVE_STRUCT_XVFSCONF)
 
+CHECK_C_SOURCE_COMPILES(
+  "#include <sys/types.h>\n#include <sys/mount.h>\nint main(void) { struct statfs s; return sizeof(s);}"
+  HAVE_STRUCT_STATFS)
+
 # Make sure we have the POSIX version of readdir_r, not the
 # older 2-argument version.
 CHECK_C_SOURCE_COMPILES(
@@ -1512,9 +1517,14 @@ CHECK_STRUCT_HAS_MEMBER("struct tm" tm_gmtoff
 CHECK_STRUCT_HAS_MEMBER("struct tm" __tm_gmtoff
     "time.h" HAVE_STRUCT_TM___TM_GMTOFF)
 
+IF(HAVE_STRUCT_STATFS)
 # Check for f_namemax in struct statfs
 CHECK_STRUCT_HAS_MEMBER("struct statfs" f_namemax
     "sys/param.h;sys/mount.h" HAVE_STRUCT_STATFS_F_NAMEMAX)
+# Check for f_iosize in struct statfs
+CHECK_STRUCT_HAS_MEMBER("struct statfs" f_iosize
+    "sys/param.h;sys/mount.h" HAVE_STRUCT_STATFS_F_IOSIZE)
+ENDIF(HAVE_STRUCT_STATFS)
 
 # Check for birthtime in struct stat
 CHECK_STRUCT_HAS_MEMBER("struct stat" st_birthtime
index 9bd2667..3b7b6ef 100644 (file)
 /* Define to 1 if you have the `link' function. */
 #cmakedefine HAVE_LINK 1
 
+/* Define to 1 if you have the `linkat' function. */
+#cmakedefine HAVE_LINKAT 1
+
 /* Define to 1 if you have the <linux/types.h> header file. */
 #cmakedefine HAVE_LINUX_TYPES_H 1
 
index 925de5c..558e9c0 100755 (executable)
@@ -246,7 +246,7 @@ function hextoi(hex)
 # Exclusion code points specified by  
 # http://unicode.org/Public/6.0.0/ucd/CompositionExclusions.txt
 ##
-# 1. Script Specifices
+# 1. Script Specifics
 ##
 \$1 ~/^095[89ABCDEF]\$/ {
     next
index 891a140..feb8697 100644 (file)
@@ -144,7 +144,9 @@ SET(libarchive_SOURCES
   archive_write_set_format_ar.c
   archive_write_set_format_by_name.c
   archive_write_set_format_cpio.c
+  archive_write_set_format_cpio_binary.c
   archive_write_set_format_cpio_newc.c
+  archive_write_set_format_cpio_odc.c
   archive_write_set_format_filter_by_ext.c
   archive_write_set_format_gnutar.c
   archive_write_set_format_iso9660.c
index a1f0b87..911747e 100644 (file)
@@ -36,7 +36,7 @@
  * assert that ARCHIVE_VERSION_NUMBER >= 2012108.
  */
 /* Note: Compiler will complain if this does not match archive_entry.h! */
-#define        ARCHIVE_VERSION_NUMBER 3005001
+#define        ARCHIVE_VERSION_NUMBER 3005003
 
 #include <sys/stat.h>
 #include <stddef.h>  /* for wchar_t */
@@ -152,7 +152,7 @@ __LA_DECL int               archive_version_number(void);
 /*
  * Textual name/version of the library, useful for version displays.
  */
-#define        ARCHIVE_VERSION_ONLY_STRING "3.5.1"
+#define        ARCHIVE_VERSION_ONLY_STRING "3.5.3"
 #define        ARCHIVE_VERSION_STRING "libarchive " ARCHIVE_VERSION_ONLY_STRING
 __LA_DECL const char * archive_version_string(void);
 
@@ -316,6 +316,7 @@ typedef const char *archive_passphrase_callback(struct archive *,
 #define        ARCHIVE_FORMAT_CPIO_SVR4_NOCRC          (ARCHIVE_FORMAT_CPIO | 4)
 #define        ARCHIVE_FORMAT_CPIO_SVR4_CRC            (ARCHIVE_FORMAT_CPIO | 5)
 #define        ARCHIVE_FORMAT_CPIO_AFIO_LARGE          (ARCHIVE_FORMAT_CPIO | 6)
+#define        ARCHIVE_FORMAT_CPIO_PWB                 (ARCHIVE_FORMAT_CPIO | 7)
 #define        ARCHIVE_FORMAT_SHAR                     0x20000
 #define        ARCHIVE_FORMAT_SHAR_BASE                (ARCHIVE_FORMAT_SHAR | 1)
 #define        ARCHIVE_FORMAT_SHAR_DUMP                (ARCHIVE_FORMAT_SHAR | 2)
@@ -797,7 +798,10 @@ __LA_DECL int archive_write_set_format_7zip(struct archive *);
 __LA_DECL int archive_write_set_format_ar_bsd(struct archive *);
 __LA_DECL int archive_write_set_format_ar_svr4(struct archive *);
 __LA_DECL int archive_write_set_format_cpio(struct archive *);
+__LA_DECL int archive_write_set_format_cpio_bin(struct archive *);
 __LA_DECL int archive_write_set_format_cpio_newc(struct archive *);
+__LA_DECL int archive_write_set_format_cpio_odc(struct archive *);
+__LA_DECL int archive_write_set_format_cpio_pwb(struct archive *);
 __LA_DECL int archive_write_set_format_gnutar(struct archive *);
 __LA_DECL int archive_write_set_format_iso9660(struct archive *);
 __LA_DECL int archive_write_set_format_mtree(struct archive *);
index d92ffd0..93d3281 100644 (file)
@@ -13,6 +13,8 @@
    https://blake2.net.
 */
 
+#include "archive_platform.h"
+
 #include <stdint.h>
 #include <string.h>
 #include <stdio.h>
index aef1010..b913a4d 100644 (file)
@@ -13,6 +13,8 @@
    https://blake2.net.
 */
 
+#include "archive_platform.h"
+
 #include <stdlib.h>
 #include <string.h>
 #include <stdio.h>
index aba41e5..ed4e7a7 100644 (file)
@@ -319,7 +319,7 @@ translate_acl(struct archive_read_disk *a,
 
 static int
 set_acl(struct archive *a, int fd, const char *name,
-    struct archive_acl *abstract_acl,
+    struct archive_acl *abstract_acl, __LA_MODE_T mode,
     int ae_requested_type, const char *tname)
 {
        int              acl_type = 0;
@@ -364,6 +364,13 @@ set_acl(struct archive *a, int fd, const char *name,
                return (ARCHIVE_FAILED);
        }
 
+       if (acl_type == ACL_TYPE_DEFAULT && !S_ISDIR(mode)) {
+               errno = EINVAL;
+               archive_set_error(a, errno,
+                   "Cannot set default ACL on non-directory");
+               return (ARCHIVE_WARN);
+       }
+
        acl = acl_init(entries);
        if (acl == (acl_t)NULL) {
                archive_set_error(a, errno,
@@ -542,7 +549,10 @@ set_acl(struct archive *a, int fd, const char *name,
        else if (acl_set_link_np(name, acl_type, acl) != 0)
 #else
        /* FreeBSD older than 8.0 */
-       else if (acl_set_file(name, acl_type, acl) != 0)
+       else if (S_ISLNK(mode)) {
+           /* acl_set_file() follows symbolic links, skip */
+           ret = ARCHIVE_OK;
+       } else if (acl_set_file(name, acl_type, acl) != 0)
 #endif
        {
                if (errno == EOPNOTSUPP) {
@@ -677,14 +687,14 @@ archive_write_disk_set_acls(struct archive *a, int fd, const char *name,
            & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) {
                if ((archive_acl_types(abstract_acl)
                    & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) {
-                       ret = set_acl(a, fd, name, abstract_acl,
+                       ret = set_acl(a, fd, name, abstract_acl, mode,
                            ARCHIVE_ENTRY_ACL_TYPE_ACCESS, "access");
                        if (ret != ARCHIVE_OK)
                                return (ret);
                }
                if ((archive_acl_types(abstract_acl)
                    & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0)
-                       ret = set_acl(a, fd, name, abstract_acl,
+                       ret = set_acl(a, fd, name, abstract_acl, mode,
                            ARCHIVE_ENTRY_ACL_TYPE_DEFAULT, "default");
 
                /* Simultaneous POSIX.1e and NFSv4 is not supported */
@@ -693,7 +703,7 @@ archive_write_disk_set_acls(struct archive *a, int fd, const char *name,
 #if ARCHIVE_ACL_FREEBSD_NFS4
        else if ((archive_acl_types(abstract_acl) &
            ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) {
-               ret = set_acl(a, fd, name, abstract_acl,
+               ret = set_acl(a, fd, name, abstract_acl, mode,
                    ARCHIVE_ENTRY_ACL_TYPE_NFS4, "nfs4");
        }
 #endif
index 3928f3d..31d2705 100644 (file)
@@ -343,6 +343,11 @@ set_richacl(struct archive *a, int fd, const char *name,
                return (ARCHIVE_FAILED);
        }
 
+       if (S_ISLNK(mode)) {
+               /* Linux does not support RichACLs on symbolic links */
+               return (ARCHIVE_OK);
+       }
+
        richacl = richacl_alloc(entries);
        if (richacl == NULL) {
                archive_set_error(a, errno,
@@ -455,7 +460,7 @@ exit_free:
 #if ARCHIVE_ACL_LIBACL
 static int
 set_acl(struct archive *a, int fd, const char *name,
-    struct archive_acl *abstract_acl,
+    struct archive_acl *abstract_acl, __LA_MODE_T mode,
     int ae_requested_type, const char *tname)
 {
        int              acl_type = 0;
@@ -488,6 +493,18 @@ set_acl(struct archive *a, int fd, const char *name,
                return (ARCHIVE_FAILED);
        }
 
+       if (S_ISLNK(mode)) {
+               /* Linux does not support ACLs on symbolic links */
+               return (ARCHIVE_OK);
+       }
+
+       if (acl_type == ACL_TYPE_DEFAULT && !S_ISDIR(mode)) {
+               errno = EINVAL;
+               archive_set_error(a, errno,
+                   "Cannot set default ACL on non-directory");
+               return (ARCHIVE_WARN);
+       }
+
        acl = acl_init(entries);
        if (acl == (acl_t)NULL) {
                archive_set_error(a, errno,
@@ -727,14 +744,14 @@ archive_write_disk_set_acls(struct archive *a, int fd, const char *name,
            & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) {
                if ((archive_acl_types(abstract_acl)
                    & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) {
-                       ret = set_acl(a, fd, name, abstract_acl,
+                       ret = set_acl(a, fd, name, abstract_acl, mode,
                            ARCHIVE_ENTRY_ACL_TYPE_ACCESS, "access");
                        if (ret != ARCHIVE_OK)
                                return (ret);
                }
                if ((archive_acl_types(abstract_acl)
                    & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0)
-                       ret = set_acl(a, fd, name, abstract_acl,
+                       ret = set_acl(a, fd, name, abstract_acl, mode,
                            ARCHIVE_ENTRY_ACL_TYPE_DEFAULT, "default");
        }
 #endif /* ARCHIVE_ACL_LIBACL */
index b0f5dfa..0ef3ad5 100644 (file)
@@ -443,7 +443,7 @@ translate_acl(struct archive_read_disk *a,
 
 static int
 set_acl(struct archive *a, int fd, const char *name,
-    struct archive_acl *abstract_acl,
+    struct archive_acl *abstract_acl, __LA_MODE_T mode,
     int ae_requested_type, const char *tname)
 {
        aclent_t         *aclent;
@@ -467,7 +467,6 @@ set_acl(struct archive *a, int fd, const char *name,
        if (entries == 0)
                return (ARCHIVE_OK);
 
-
        switch (ae_requested_type) {
        case ARCHIVE_ENTRY_ACL_TYPE_POSIX1E:
                cmd = SETACL;
@@ -492,6 +491,12 @@ set_acl(struct archive *a, int fd, const char *name,
                return (ARCHIVE_FAILED);
        }
 
+        if (S_ISLNK(mode)) {
+                /* Skip ACLs on symbolic links */
+               ret = ARCHIVE_OK;
+               goto exit_free;
+        }
+
        e = 0;
 
        while (archive_acl_next(a, abstract_acl, ae_requested_type, &ae_type,
@@ -801,7 +806,7 @@ archive_write_disk_set_acls(struct archive *a, int fd, const char *name,
        if ((archive_acl_types(abstract_acl)
            & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) {
                /* Solaris writes POSIX.1e access and default ACLs together */
-               ret = set_acl(a, fd, name, abstract_acl,
+               ret = set_acl(a, fd, name, abstract_acl, mode,
                    ARCHIVE_ENTRY_ACL_TYPE_POSIX1E, "posix1e");
 
                /* Simultaneous POSIX.1e and NFSv4 is not supported */
@@ -810,7 +815,7 @@ archive_write_disk_set_acls(struct archive *a, int fd, const char *name,
 #if ARCHIVE_ACL_SUNOS_NFS4
        else if ((archive_acl_types(abstract_acl) &
            ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) {
-               ret = set_acl(a, fd, name, abstract_acl,
+               ret = set_acl(a, fd, name, abstract_acl, mode,
                    ARCHIVE_ENTRY_ACL_TYPE_NFS4, "nfs4");
        }
 #endif
index 21e89d2..c638b75 100644 (file)
@@ -30,7 +30,7 @@
 #define        ARCHIVE_ENTRY_H_INCLUDED
 
 /* Note: Compiler will complain if this does not match archive.h! */
-#define        ARCHIVE_VERSION_NUMBER 3005001
+#define        ARCHIVE_VERSION_NUMBER 3005003
 
 /*
  * Note: archive_entry.h is for use outside of libarchive; the
index 619e2b6..0867a26 100644 (file)
@@ -384,6 +384,8 @@ __archive_pathmatch(const char *p, const char *s, int flags)
        /* Empty pattern only matches the empty string. */
        if (p == NULL || *p == '\0')
                return (s == NULL || *s == '\0');
+       else if (s == NULL)
+               return (0);
 
        /* Leading '^' anchors the start of the pattern. */
        if (*p == '^') {
@@ -424,6 +426,8 @@ __archive_pathmatch_w(const wchar_t *p, const wchar_t *s, int flags)
        /* Empty pattern only matches the empty string. */
        if (p == NULL || *p == L'\0')
                return (s == NULL || *s == L'\0');
+       else if (s == NULL)
+               return (0);
 
        /* Leading '^' anchors the start of the pattern. */
        if (*p == L'^') {
index 937a87b..55a8da1 100644 (file)
 #define        __LA_DEAD
 #endif
 
+#if defined(__GNUC__) && (__GNUC__ > 2 || \
+                         (__GNUC__ == 2 && __GNUC_MINOR__ >= 7))
+#define        __LA_UNUSED     __attribute__((__unused__))
+#else
+#define        __LA_UNUSED
+#endif
+
 #define        ARCHIVE_WRITE_MAGIC     (0xb0c5c0deU)
 #define        ARCHIVE_READ_MAGIC      (0xdeb0c5U)
 #define        ARCHIVE_WRITE_DISK_MAGIC (0xc001b0c5U)
index 2898206..3ee6269 100644 (file)
@@ -1522,8 +1522,40 @@ get_xfer_size(struct tree *t, int fd, const char *path)
 }
 #endif
 
-#if defined(HAVE_STATFS) && defined(HAVE_FSTATFS) && defined(MNT_LOCAL) \
-       && !defined(ST_LOCAL)
+#if defined(HAVE_STATVFS)
+static inline __LA_UNUSED void
+set_statvfs_transfer_size(struct filesystem *fs, const struct statvfs *sfs)
+{
+       fs->xfer_align = sfs->f_frsize > 0 ? (long)sfs->f_frsize : -1;
+       fs->max_xfer_size = -1;
+#if defined(HAVE_STRUCT_STATVFS_F_IOSIZE)
+       fs->min_xfer_size = sfs->f_iosize > 0 ? (long)sfs->f_iosize : -1;
+       fs->incr_xfer_size = sfs->f_iosize > 0 ? (long)sfs->f_iosize : -1;
+#else
+       fs->min_xfer_size = sfs->f_bsize > 0 ? (long)sfs->f_bsize : -1;
+       fs->incr_xfer_size = sfs->f_bsize > 0 ? (long)sfs->f_bsize : -1;
+#endif
+}
+#endif
+
+#if defined(HAVE_STRUCT_STATFS)
+static inline __LA_UNUSED void
+set_statfs_transfer_size(struct filesystem *fs, const struct statfs *sfs)
+{
+       fs->xfer_align = sfs->f_bsize > 0 ? (long)sfs->f_bsize : -1;
+       fs->max_xfer_size = -1;
+#if defined(HAVE_STRUCT_STATFS_F_IOSIZE)
+       fs->min_xfer_size = sfs->f_iosize > 0 ? (long)sfs->f_iosize : -1;
+       fs->incr_xfer_size = sfs->f_iosize > 0 ? (long)sfs->f_iosize : -1;
+#else
+       fs->min_xfer_size = sfs->f_bsize > 0 ? (long)sfs->f_bsize : -1;
+       fs->incr_xfer_size = sfs->f_bsize > 0 ? (long)sfs->f_bsize : -1;
+#endif
+}
+#endif
+
+#if defined(HAVE_STRUCT_STATFS) && defined(HAVE_STATFS) && \
+    defined(HAVE_FSTATFS) && defined(MNT_LOCAL) && !defined(ST_LOCAL)
 
 /*
  * Gather current filesystem properties on FreeBSD, OpenBSD and Mac OS X.
@@ -1593,10 +1625,7 @@ setup_current_filesystem(struct archive_read_disk *a)
                return (ARCHIVE_FAILED);
        } else if (xr == 1) {
                /* pathconf(_PC_REX_*) operations are not supported. */
-               t->current_filesystem->xfer_align = sfs.f_bsize;
-               t->current_filesystem->max_xfer_size = -1;
-               t->current_filesystem->min_xfer_size = sfs.f_iosize;
-               t->current_filesystem->incr_xfer_size = sfs.f_iosize;
+               set_statfs_transfer_size(t->current_filesystem, &sfs);
        }
        if (sfs.f_flags & MNT_LOCAL)
                t->current_filesystem->remote = 0;
@@ -1688,15 +1717,7 @@ setup_current_filesystem(struct archive_read_disk *a)
        } else if (xr == 1) {
                /* Usually come here unless NetBSD supports _PC_REC_XFER_ALIGN
                 * for pathconf() function. */
-               t->current_filesystem->xfer_align = svfs.f_frsize;
-               t->current_filesystem->max_xfer_size = -1;
-#if defined(HAVE_STRUCT_STATVFS_F_IOSIZE)
-               t->current_filesystem->min_xfer_size = svfs.f_iosize;
-               t->current_filesystem->incr_xfer_size = svfs.f_iosize;
-#else
-               t->current_filesystem->min_xfer_size = svfs.f_bsize;
-               t->current_filesystem->incr_xfer_size = svfs.f_bsize;
-#endif
+               set_statvfs_transfer_size(t->current_filesystem, &svfs);
        }
        if (svfs.f_flag & ST_LOCAL)
                t->current_filesystem->remote = 0;
@@ -1803,15 +1824,9 @@ setup_current_filesystem(struct archive_read_disk *a)
        } else if (xr == 1) {
                /* pathconf(_PC_REX_*) operations are not supported. */
 #if defined(HAVE_STATVFS)
-               t->current_filesystem->xfer_align = svfs.f_frsize;
-               t->current_filesystem->max_xfer_size = -1;
-               t->current_filesystem->min_xfer_size = svfs.f_bsize;
-               t->current_filesystem->incr_xfer_size = svfs.f_bsize;
+               set_statvfs_transfer_size(t->current_filesystem, &svfs);
 #else
-               t->current_filesystem->xfer_align = sfs.f_frsize;
-               t->current_filesystem->max_xfer_size = -1;
-               t->current_filesystem->min_xfer_size = sfs.f_bsize;
-               t->current_filesystem->incr_xfer_size = sfs.f_bsize;
+               set_statfs_transfer_size(t->current_filesystem, &sfs);
 #endif
        }
        switch (sfs.f_type) {
@@ -1918,10 +1933,7 @@ setup_current_filesystem(struct archive_read_disk *a)
                return (ARCHIVE_FAILED);
        } else if (xr == 1) {
                /* pathconf(_PC_REX_*) operations are not supported. */
-               t->current_filesystem->xfer_align = svfs.f_frsize;
-               t->current_filesystem->max_xfer_size = -1;
-               t->current_filesystem->min_xfer_size = svfs.f_bsize;
-               t->current_filesystem->incr_xfer_size = svfs.f_bsize;
+               set_statvfs_transfer_size(t->current_filesystem, &svfs);
        }
 
 #if defined(ST_NOATIME)
index fdd376f..877bc44 100644 (file)
@@ -1844,7 +1844,7 @@ tree_next(struct tree *t)
                                        continue;
                                return (r);
                        } else {
-                               HANDLE h = FindFirstFileW(d, &t->_findData);
+                               HANDLE h = FindFirstFileW(t->stack->full_path.s, &t->_findData);
                                if (h == INVALID_HANDLE_VALUE) {
                                        la_dosmaperr(GetLastError());
                                        t->tree_errno = errno;
index 78d9999..b2db4cb 100644 (file)
@@ -188,9 +188,18 @@ used when translating file names.
 .El
 .It Format cpio
 .Bl -tag -compact -width indent
+.It Cm compat-2x
+Libarchive 2.x incorrectly encoded Unicode filenames on
+some platforms.
+This option mimics the libarchive 2.x filename handling
+so that such archives can be read correctly.
 .It Cm hdrcharset
 The value is used as a character set name that will be
 used when translating file names.
+.It Cm pwb
+When reading a binary CPIO archive, assume that it is
+in the original PWB cpio format, and handle file mode
+bits accordingly.  The default is to assume v7 format.
 .El
 .It Format iso9660
 .Bl -tag -compact -width indent
index e7e58e5..ddd6839 100644 (file)
@@ -216,7 +216,7 @@ rpm_filter_read(struct archive_read_filter *self, const void **buff)
                                                archive_set_error(
                                                    &self->archive->archive,
                                                    ARCHIVE_ERRNO_FILE_FORMAT,
-                                                   "Unrecoginized rpm header");
+                                                   "Unrecognized rpm header");
                                                return (ARCHIVE_FATAL);
                                        }
                                        rpm->state = ST_ARCHIVE;
index 67ddffb..689c18c 100644 (file)
@@ -248,7 +248,7 @@ bid_get_line(struct archive_read_filter *filter,
                *ravail = *avail;
                *b += diff;
                *avail -= diff;
-               tested = len;/* Skip some bytes we already determinated. */
+               tested = len;/* Skip some bytes we already determined. */
                len = get_line(*b + tested, *avail - tested, nl);
                if (len >= 0)
                        len += tested;
index 456b2f8..7d7e702 100644 (file)
@@ -808,8 +808,12 @@ archive_read_format_7zip_read_data(struct archive_read *a,
        if (zip->end_of_entry)
                return (ARCHIVE_EOF);
 
-       bytes = read_stream(a, buff,
-               (size_t)zip->entry_bytes_remaining, 0);
+       const uint64_t max_read_size = 16 * 1024 * 1024;  // Don't try to read more than 16 MB at a time
+       size_t bytes_to_read = max_read_size;
+       if ((uint64_t)bytes_to_read > zip->entry_bytes_remaining) {
+               bytes_to_read = zip->entry_bytes_remaining;
+       }
+       bytes = read_stream(a, buff, bytes_to_read, 0);
        if (bytes < 0)
                return ((int)bytes);
        if (bytes == 0) {
@@ -1493,7 +1497,7 @@ decompress(struct archive_read *a, struct _7zip *zip,
                                zip->ppmd7_stat = -1;
                                archive_set_error(&a->archive,
                                    ARCHIVE_ERRNO_MISC,
-                                   "Failed to initialize PPMd range decorder");
+                                   "Failed to initialize PPMd range decoder");
                                return (ARCHIVE_FAILED);
                        }
                        if (zip->ppstream.overconsumed) {
@@ -3031,10 +3035,10 @@ extract_pack_stream(struct archive_read *a, size_t minimum)
                            "Truncated 7-Zip file body");
                        return (ARCHIVE_FATAL);
                }
-               if (bytes_avail > (ssize_t)zip->pack_stream_inbytes_remaining)
+               if ((uint64_t)bytes_avail > zip->pack_stream_inbytes_remaining)
                        bytes_avail = (ssize_t)zip->pack_stream_inbytes_remaining;
                zip->pack_stream_inbytes_remaining -= bytes_avail;
-               if (bytes_avail > (ssize_t)zip->folder_outbytes_remaining)
+               if ((uint64_t)bytes_avail > zip->folder_outbytes_remaining)
                        bytes_avail = (ssize_t)zip->folder_outbytes_remaining;
                zip->folder_outbytes_remaining -= bytes_avail;
                zip->uncompressed_buffer_bytes_remaining = bytes_avail;
index 57547d4..8742378 100644 (file)
@@ -2110,7 +2110,6 @@ lzx_decode_init(struct lzx_stream *strm, int w_bits)
                ds->pos_tbl = malloc(sizeof(ds->pos_tbl[0]) * w_slot);
                if (ds->pos_tbl == NULL)
                        return (ARCHIVE_FATAL);
-               lzx_huffman_free(&(ds->mt));
        }
 
        for (footer = 0; footer < 18; footer++)
index 1c96e6a..6b8ae33 100644 (file)
@@ -185,6 +185,8 @@ struct cpio {
        struct archive_string_conv *opt_sconv;
        struct archive_string_conv *sconv_default;
        int                       init_default_conversion;
+
+       int                       option_pwb;
 };
 
 static int64_t atol16(const char *, unsigned);
@@ -343,6 +345,10 @@ archive_read_format_cpio_options(struct archive_read *a,
                                ret = ARCHIVE_FATAL;
                }
                return (ret);
+       } else if (strcmp(key, "pwb")  == 0) {
+               if (val != NULL && val[0] != 0)
+                       cpio->option_pwb = 1;
+               return (ARCHIVE_OK);
        }
 
        /* Note: The "warn" return is just to inform the options
@@ -891,6 +897,12 @@ header_bin_le(struct archive_read *a, struct cpio *cpio,
        archive_entry_set_dev(entry, header[bin_dev_offset] + header[bin_dev_offset + 1] * 256);
        archive_entry_set_ino(entry, header[bin_ino_offset] + header[bin_ino_offset + 1] * 256);
        archive_entry_set_mode(entry, header[bin_mode_offset] + header[bin_mode_offset + 1] * 256);
+       if (cpio->option_pwb) {
+               /* turn off random bits left over from V6 inode */
+               archive_entry_set_mode(entry, archive_entry_mode(entry) & 067777);
+               if ((archive_entry_mode(entry) & AE_IFMT) == 0)
+                       archive_entry_set_mode(entry, archive_entry_mode(entry) | AE_IFREG);
+       }
        archive_entry_set_uid(entry, header[bin_uid_offset] + header[bin_uid_offset + 1] * 256);
        archive_entry_set_gid(entry, header[bin_gid_offset] + header[bin_gid_offset + 1] * 256);
        archive_entry_set_nlink(entry, header[bin_nlink_offset] + header[bin_nlink_offset + 1] * 256);
@@ -930,6 +942,12 @@ header_bin_be(struct archive_read *a, struct cpio *cpio,
        archive_entry_set_dev(entry, header[bin_dev_offset] * 256 + header[bin_dev_offset + 1]);
        archive_entry_set_ino(entry, header[bin_ino_offset] * 256 + header[bin_ino_offset + 1]);
        archive_entry_set_mode(entry, header[bin_mode_offset] * 256 + header[bin_mode_offset + 1]);
+       if (cpio->option_pwb) {
+               /* turn off random bits left over from V6 inode */
+               archive_entry_set_mode(entry, archive_entry_mode(entry) & 067777);
+               if ((archive_entry_mode(entry) & AE_IFMT) == 0)
+                       archive_entry_set_mode(entry, archive_entry_mode(entry) | AE_IFREG);
+       }
        archive_entry_set_uid(entry, header[bin_uid_offset] * 256 + header[bin_uid_offset + 1]);
        archive_entry_set_gid(entry, header[bin_gid_offset] * 256 + header[bin_gid_offset + 1]);
        archive_entry_set_nlink(entry, header[bin_nlink_offset] * 256 + header[bin_nlink_offset + 1]);
index 93ba295..c87a154 100644 (file)
@@ -408,7 +408,7 @@ next_line(struct archive_read *a,
                *ravail = *avail;
                *b += diff;
                *avail -= diff;
-               tested = len;/* Skip some bytes we already determinated. */
+               tested = len;/* Skip some bytes we already determined. */
                len = get_line_size(*b + len, *avail - len, nl);
                if (len >= 0)
                        len += tested;
@@ -1074,7 +1074,7 @@ read_mtree(struct archive_read *a, struct mtree *mtree)
                        continue;
                /* Non-printable characters are not allowed */
                for (s = p;s < p + len - 1; s++) {
-                       if (!isprint(*s)) {
+                       if (!isprint((unsigned char)*s)) {
                                r = ARCHIVE_FATAL;
                                break;
                        }
@@ -2035,13 +2035,13 @@ mtree_atol(char **p, int base)
 
        if (**p == '-') {
                limit = INT64_MIN / base;
-               last_digit_limit = INT64_MIN % base;
+               last_digit_limit = -(INT64_MIN % base);
                ++(*p);
 
                l = 0;
                digit = parsedigit(**p);
                while (digit >= 0 && digit < base) {
-                       if (l < limit || (l == limit && digit > last_digit_limit))
+                       if (l < limit || (l == limit && digit >= last_digit_limit))
                                return INT64_MIN;
                        l = (l * base) - digit;
                        digit = parsedigit(*++(*p));
index 6dca350..a9fa1dc 100644 (file)
@@ -958,17 +958,17 @@ archive_read_format_rar_read_header(struct archive_read *a,
       crc32_val = 0;
       while (skip > 0) {
              size_t to_read = skip;
-             ssize_t did_read;
-             if (to_read > 32 * 1024) {
+             if (to_read > 32 * 1024)
                      to_read = 32 * 1024;
-             }
-             if ((h = __archive_read_ahead(a, to_read, &did_read)) == NULL) {
+             if ((h = __archive_read_ahead(a, to_read, NULL)) == NULL) {
+                     archive_set_error(&a->archive,  ARCHIVE_ERRNO_FILE_FORMAT,
+                         "Bad RAR file");
                      return (ARCHIVE_FATAL);
              }
              p = h;
-             crc32_val = crc32(crc32_val, (const unsigned char *)p, (unsigned)did_read);
-             __archive_read_consume(a, did_read);
-             skip -= did_read;
+             crc32_val = crc32(crc32_val, (const unsigned char *)p, to_read);
+             __archive_read_consume(a, to_read);
+             skip -= to_read;
       }
       if ((crc32_val & 0xffff) != crc32_expected) {
              archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
index 3131955..855317a 100644 (file)
@@ -1012,7 +1012,16 @@ static int read_var_sized(struct archive_read* a, size_t* pvalue,
        return ret;
 }
 
-static int read_bits_32(struct rar5* rar, const uint8_t* p, uint32_t* value) {
+static int read_bits_32(struct archive_read* a, struct rar5* rar,
+       const uint8_t* p, uint32_t* value)
+{
+       if(rar->bits.in_addr >= rar->cstate.cur_block_size) {
+               archive_set_error(&a->archive,
+                       ARCHIVE_ERRNO_PROGRAMMER,
+                       "Premature end of stream during extraction of data (#1)");
+               return ARCHIVE_FATAL;
+       }
+
        uint32_t bits = ((uint32_t) p[rar->bits.in_addr]) << 24;
        bits |= p[rar->bits.in_addr + 1] << 16;
        bits |= p[rar->bits.in_addr + 2] << 8;
@@ -1023,7 +1032,16 @@ static int read_bits_32(struct rar5* rar, const uint8_t* p, uint32_t* value) {
        return ARCHIVE_OK;
 }
 
-static int read_bits_16(struct rar5* rar, const uint8_t* p, uint16_t* value) {
+static int read_bits_16(struct archive_read* a, struct rar5* rar,
+       const uint8_t* p, uint16_t* value)
+{
+       if(rar->bits.in_addr >= rar->cstate.cur_block_size) {
+               archive_set_error(&a->archive,
+                       ARCHIVE_ERRNO_PROGRAMMER,
+                       "Premature end of stream during extraction of data (#2)");
+               return ARCHIVE_FATAL;
+       }
+
        int bits = (int) ((uint32_t) p[rar->bits.in_addr]) << 16;
        bits |= (int) p[rar->bits.in_addr + 1] << 8;
        bits |= (int) p[rar->bits.in_addr + 2];
@@ -1039,8 +1057,8 @@ static void skip_bits(struct rar5* rar, int bits) {
 }
 
 /* n = up to 16 */
-static int read_consume_bits(struct rar5* rar, const uint8_t* p, int n,
-    int* value)
+static int read_consume_bits(struct archive_read* a, struct rar5* rar,
+       const uint8_t* p, int n, int* value)
 {
        uint16_t v;
        int ret, num;
@@ -1051,7 +1069,7 @@ static int read_consume_bits(struct rar5* rar, const uint8_t* p, int n,
                return ARCHIVE_FATAL;
        }
 
-       ret = read_bits_16(rar, p, &v);
+       ret = read_bits_16(a, rar, p, &v);
        if(ret != ARCHIVE_OK)
                return ret;
 
@@ -1712,14 +1730,29 @@ static int process_head_file(struct archive_read* a, struct rar5* rar,
                }
        }
 
-       /* If we're currently switching volumes, ignore the new definition of
-        * window_size. */
-       if(rar->cstate.switch_multivolume == 0) {
-               /* Values up to 64M should fit into ssize_t on every
-                * architecture. */
-               rar->cstate.window_size = (ssize_t) window_size;
+       if(rar->cstate.window_size < (ssize_t) window_size &&
+           rar->cstate.window_buf)
+       {
+               /* If window_buf has been allocated before, reallocate it, so
+                * that its size will match new window_size. */
+
+               uint8_t* new_window_buf =
+                       realloc(rar->cstate.window_buf, window_size);
+
+               if(!new_window_buf) {
+                       archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
+                               "Not enough memory when trying to realloc the window "
+                               "buffer.");
+                       return ARCHIVE_FATAL;
+               }
+
+               rar->cstate.window_buf = new_window_buf;
        }
 
+       /* Values up to 64M should fit into ssize_t on every
+        * architecture. */
+       rar->cstate.window_size = (ssize_t) window_size;
+
        if(rar->file.solid > 0 && rar->file.solid_window_size == 0) {
                /* Solid files have to have the same window_size across
                   whole archive. Remember the window_size parameter
@@ -2425,13 +2458,13 @@ static int create_decode_tables(uint8_t* bit_length,
 static int decode_number(struct archive_read* a, struct decode_table* table,
     const uint8_t* p, uint16_t* num)
 {
-       int i, bits, dist;
+       int i, bits, dist, ret;
        uint16_t bitfield;
        uint32_t pos;
        struct rar5* rar = get_context(a);
 
-       if(ARCHIVE_OK != read_bits_16(rar, p, &bitfield)) {
-               return ARCHIVE_EOF;
+       if(ARCHIVE_OK != (ret = read_bits_16(a, rar, p, &bitfield))) {
+               return ret;
        }
 
        bitfield &= 0xfffe;
@@ -2537,14 +2570,6 @@ static int parse_tables(struct archive_read* a, struct rar5* rar,
        for(i = 0; i < HUFF_TABLE_SIZE;) {
                uint16_t num;
 
-               if((rar->bits.in_addr + 6) >= rar->cstate.cur_block_size) {
-                       /* Truncated data, can't continue. */
-                       archive_set_error(&a->archive,
-                           ARCHIVE_ERRNO_FILE_FORMAT,
-                           "Truncated data in huffman tables (#2)");
-                       return ARCHIVE_FATAL;
-               }
-
                ret = decode_number(a, &rar->cstate.bd, p, &num);
                if(ret != ARCHIVE_OK) {
                        archive_set_error(&a->archive,
@@ -2561,8 +2586,8 @@ static int parse_tables(struct archive_read* a, struct rar5* rar,
                        /* 16..17: repeat previous code */
                        uint16_t n;
 
-                       if(ARCHIVE_OK != read_bits_16(rar, p, &n))
-                               return ARCHIVE_EOF;
+                       if(ARCHIVE_OK != (ret = read_bits_16(a, rar, p, &n)))
+                               return ret;
 
                        if(num == 16) {
                                n >>= 13;
@@ -2590,8 +2615,8 @@ static int parse_tables(struct archive_read* a, struct rar5* rar,
                        /* other codes: fill with zeroes `n` times */
                        uint16_t n;
 
-                       if(ARCHIVE_OK != read_bits_16(rar, p, &n))
-                               return ARCHIVE_EOF;
+                       if(ARCHIVE_OK != (ret = read_bits_16(a, rar, p, &n)))
+                               return ret;
 
                        if(num == 18) {
                                n >>= 13;
@@ -2707,22 +2732,22 @@ static int parse_block_header(struct archive_read* a, const uint8_t* p,
 }
 
 /* Convenience function used during filter processing. */
-static int parse_filter_data(struct rar5* rar, const uint8_t* p,
-    uint32_t* filter_data)
+static int parse_filter_data(struct archive_read* a, struct rar5* rar,
+       const uint8_t* p, uint32_t* filter_data)
 {
-       int i, bytes;
+       int i, bytes, ret;
        uint32_t data = 0;
 
-       if(ARCHIVE_OK != read_consume_bits(rar, p, 2, &bytes))
-               return ARCHIVE_EOF;
+       if(ARCHIVE_OK != (ret = read_consume_bits(a, rar, p, 2, &bytes)))
+               return ret;
 
        bytes++;
 
        for(i = 0; i < bytes; i++) {
                uint16_t byte;
 
-               if(ARCHIVE_OK != read_bits_16(rar, p, &byte)) {
-                       return ARCHIVE_EOF;
+               if(ARCHIVE_OK != (ret = read_bits_16(a, rar, p, &byte))) {
+                       return ret;
                }
 
                /* Cast to uint32_t will ensure the shift operation will not
@@ -2765,16 +2790,17 @@ static int parse_filter(struct archive_read* ar, const uint8_t* p) {
        uint16_t filter_type;
        struct filter_info* filt = NULL;
        struct rar5* rar = get_context(ar);
+       int ret;
 
        /* Read the parameters from the input stream. */
-       if(ARCHIVE_OK != parse_filter_data(rar, p, &block_start))
-               return ARCHIVE_EOF;
+       if(ARCHIVE_OK != (ret = parse_filter_data(ar, rar, p, &block_start)))
+               return ret;
 
-       if(ARCHIVE_OK != parse_filter_data(rar, p, &block_length))
-               return ARCHIVE_EOF;
+       if(ARCHIVE_OK != (ret = parse_filter_data(ar, rar, p, &block_length)))
+               return ret;
 
-       if(ARCHIVE_OK != read_bits_16(rar, p, &filter_type))
-               return ARCHIVE_EOF;
+       if(ARCHIVE_OK != (ret = read_bits_16(ar, rar, p, &filter_type)))
+               return ret;
 
        filter_type >>= 13;
        skip_bits(rar, 3);
@@ -2814,8 +2840,8 @@ static int parse_filter(struct archive_read* ar, const uint8_t* p) {
        if(filter_type == FILTER_DELTA) {
                int channels;
 
-               if(ARCHIVE_OK != read_consume_bits(rar, p, 5, &channels))
-                       return ARCHIVE_EOF;
+               if(ARCHIVE_OK != (ret = read_consume_bits(ar, rar, p, 5, &channels)))
+                       return ret;
 
                filt->channels = channels + 1;
        }
@@ -2823,10 +2849,11 @@ static int parse_filter(struct archive_read* ar, const uint8_t* p) {
        return ARCHIVE_OK;
 }
 
-static int decode_code_length(struct rar5* rar, const uint8_t* p,
-    uint16_t code)
+static int decode_code_length(struct archive_read* a, struct rar5* rar,
+       const uint8_t* p, uint16_t code)
 {
        int lbits, length = 2;
+
        if(code < 8) {
                lbits = 0;
                length += code;
@@ -2838,7 +2865,7 @@ static int decode_code_length(struct rar5* rar, const uint8_t* p,
        if(lbits > 0) {
                int add;
 
-               if(ARCHIVE_OK != read_consume_bits(rar, p, lbits, &add))
+               if(ARCHIVE_OK != read_consume_bits(a, rar, p, lbits, &add))
                        return -1;
 
                length += add;
@@ -2933,7 +2960,7 @@ static int do_uncompress_block(struct archive_read* a, const uint8_t* p) {
                        continue;
                } else if(num >= 262) {
                        uint16_t dist_slot;
-                       int len = decode_code_length(rar, p, num - 262),
+                       int len = decode_code_length(a, rar, p, num - 262),
                                dbits,
                                dist = 1;
 
@@ -2975,12 +3002,12 @@ static int do_uncompress_block(struct archive_read* a, const uint8_t* p) {
                                        uint16_t low_dist;
 
                                        if(dbits > 4) {
-                                               if(ARCHIVE_OK != read_bits_32(
-                                                   rar, p, &add)) {
+                                               if(ARCHIVE_OK != (ret = read_bits_32(
+                                                   a, rar, p, &add))) {
                                                        /* Return EOF if we
                                                         * can't read more
                                                         * data. */
-                                                       return ARCHIVE_EOF;
+                                                       return ret;
                                                }
 
                                                skip_bits(rar, dbits - 4);
@@ -3015,11 +3042,11 @@ static int do_uncompress_block(struct archive_read* a, const uint8_t* p) {
                                        /* dbits is one of [0,1,2,3] */
                                        int add;
 
-                                       if(ARCHIVE_OK != read_consume_bits(rar,
-                                            p, dbits, &add)) {
+                                       if(ARCHIVE_OK != (ret = read_consume_bits(a, rar,
+                                            p, dbits, &add))) {
                                                /* Return EOF if we can't read
                                                 * more data. */
-                                               return ARCHIVE_EOF;
+                                               return ret;
                                        }
 
                                        dist += add;
@@ -3076,7 +3103,11 @@ static int do_uncompress_block(struct archive_read* a, const uint8_t* p) {
                                return ARCHIVE_FATAL;
                        }
 
-                       len = decode_code_length(rar, p, len_slot);
+                       len = decode_code_length(a, rar, p, len_slot);
+                       if (len == -1) {
+                               return ARCHIVE_FATAL;
+                       }
+
                        rar->cstate.last_len = len;
 
                        if(ARCHIVE_OK != copy_string(a, len, dist))
@@ -3600,6 +3631,16 @@ static int do_uncompress_file(struct archive_read* a) {
                rar->cstate.initialized = 1;
        }
 
+       /* Don't allow extraction if window_size is invalid. */
+       if(rar->cstate.window_size == 0) {
+               archive_set_error(&a->archive,
+                       ARCHIVE_ERRNO_FILE_FORMAT,
+                       "Invalid window size declaration in this file");
+
+               /* This should never happen in valid files. */
+               return ARCHIVE_FATAL;
+       }
+
        if(rar->cstate.all_filters_applied == 1) {
                /* We use while(1) here, but standard case allows for just 1
                 * iteration. The loop will iterate if process_block() didn't
@@ -4076,6 +4117,7 @@ int archive_read_support_format_rar5(struct archive *_a) {
        if(ARCHIVE_OK != rar5_init(rar)) {
                archive_set_error(&ar->archive, ENOMEM,
                    "Can't allocate rar5 filter buffer");
+               free(rar);
                return ARCHIVE_FATAL;
        }
 
index 96d8101..7e8feba 100644 (file)
@@ -1906,7 +1906,7 @@ pax_attribute(struct archive_read *a, struct tar *tar,
                }
                if (strcmp(key, "GNU.sparse.numbytes") == 0) {
                        tar->sparse_numbytes = tar_atol10(value, strlen(value));
-                       if (tar->sparse_numbytes != -1) {
+                       if (tar->sparse_offset != -1) {
                                if (gnu_add_sparse_entry(a, tar,
                                    tar->sparse_offset, tar->sparse_numbytes)
                                    != ARCHIVE_OK)
@@ -2643,14 +2643,14 @@ tar_atol_base_n(const char *p, size_t char_cnt, int base)
 
                maxval = INT64_MIN;
                limit = -(INT64_MIN / base);
-               last_digit_limit = INT64_MIN % base;
+               last_digit_limit = -(INT64_MIN % base);
        }
 
        l = 0;
        if (char_cnt != 0) {
                digit = *p - '0';
                while (digit >= 0 && digit < base  && char_cnt != 0) {
-                       if (l>limit || (l == limit && digit > last_digit_limit)) {
+                       if (l>limit || (l == limit && digit >= last_digit_limit)) {
                                return maxval; /* Truncate on overflow. */
                        }
                        l = (l * base) + digit;
index 6314c68..4702316 100644 (file)
@@ -142,6 +142,7 @@ struct zip {
        /* Structural information about the archive. */
        struct archive_string   format_name;
        int64_t                 central_directory_offset;
+       int64_t                 central_directory_offset_adjusted;
        size_t                  central_directory_entries_total;
        size_t                  central_directory_entries_on_this_disk;
        int                     has_encrypted_entries;
@@ -246,6 +247,17 @@ struct zip {
 /* Many systems define min or MIN, but not all. */
 #define        zipmin(a,b) ((a) < (b) ? (a) : (b))
 
+#ifdef HAVE_ZLIB_H
+static int
+zip_read_data_deflate(struct archive_read *a, const void **buff,
+       size_t *size, int64_t *offset);
+#endif
+#if HAVE_LZMA_H && HAVE_LIBLZMA
+static int
+zip_read_data_zipx_lzma_alone(struct archive_read *a, const void **buff,
+       size_t *size, int64_t *offset);
+#endif
+
 /* This function is used by Ppmd8_DecodeSymbol during decompression of Ppmd8
  * streams inside ZIP files. It has 2 purposes: one is to fetch the next
  * compressed byte from the stream, second one is to increase the counter how
@@ -899,81 +911,6 @@ process_extra(struct archive_read *a, struct archive_entry *entry,
        return ARCHIVE_OK;
 }
 
-#if HAVE_LZMA_H && HAVE_LIBLZMA
-/*
- * Auxiliary function to uncompress data chunk from zipx archive
- * (zip with lzma compression).
- */
-static int
-zipx_lzma_uncompress_buffer(const char *compressed_buffer,
-       size_t compressed_buffer_size,
-       char *uncompressed_buffer,
-       size_t uncompressed_buffer_size)
-{
-       int status = ARCHIVE_FATAL;
-       // length of 'lzma properties data' in lzma compressed
-       // data segment (stream) inside zip archive
-       const size_t lzma_params_length = 5;
-       // offset of 'lzma properties data' from the beginning of lzma stream
-       const size_t lzma_params_offset = 4;
-       // end position of 'lzma properties data' in lzma stream
-       const size_t lzma_params_end = lzma_params_offset + lzma_params_length;
-       if (compressed_buffer == NULL ||
-                       compressed_buffer_size < lzma_params_end ||
-                       uncompressed_buffer == NULL)
-               return status;
-
-       // prepare header for lzma_alone_decoder to replace zipx header
-       // (see comments in 'zipx_lzma_alone_init' for justification)
-#pragma pack(push)
-#pragma pack(1)
-       struct _alone_header
-       {
-               uint8_t bytes[5]; // lzma_params_length
-               uint64_t uncompressed_size;
-       } alone_header;
-#pragma pack(pop)
-       // copy 'lzma properties data' blob
-       memcpy(&alone_header.bytes[0], compressed_buffer + lzma_params_offset,
-               lzma_params_length);
-       alone_header.uncompressed_size = UINT64_MAX;
-
-       // prepare new compressed buffer, see 'zipx_lzma_alone_init' for details
-       const size_t lzma_alone_buffer_size =
-               compressed_buffer_size - lzma_params_end + sizeof(alone_header);
-       unsigned char *lzma_alone_compressed_buffer =
-               (unsigned char*) malloc(lzma_alone_buffer_size);
-       if (lzma_alone_compressed_buffer == NULL)
-               return status;
-       // copy lzma_alone header into new buffer
-       memcpy(lzma_alone_compressed_buffer, (void*) &alone_header,
-               sizeof(alone_header));
-       // copy compressed data into new buffer
-       memcpy(lzma_alone_compressed_buffer + sizeof(alone_header),
-               compressed_buffer + lzma_params_end,
-               compressed_buffer_size - lzma_params_end);
-
-       // create and fill in lzma_alone_decoder stream
-       lzma_stream stream = LZMA_STREAM_INIT;
-       lzma_ret ret = lzma_alone_decoder(&stream, UINT64_MAX);
-       if (ret == LZMA_OK)
-       {
-               stream.next_in = lzma_alone_compressed_buffer;
-               stream.avail_in = lzma_alone_buffer_size;
-               stream.total_in = 0;
-               stream.next_out = (unsigned char*)uncompressed_buffer;
-               stream.avail_out = uncompressed_buffer_size;
-               stream.total_out = 0;
-               ret = lzma_code(&stream, LZMA_RUN);
-               if (ret == LZMA_OK || ret == LZMA_STREAM_END)
-                       status = ARCHIVE_OK;
-       }
-       lzma_end(&stream);
-       free(lzma_alone_compressed_buffer);
-       return status;
-}
-#endif
-
 /*
  * Assumes file pointer is at beginning of local file header.
  */
@@ -1242,36 +1179,30 @@ zip_read_local_file_header(struct archive_read *a, struct archive_entry *entry,
                linkname_length = (size_t)zip_entry->compressed_size;
 
                archive_entry_set_size(entry, 0);
-               p = __archive_read_ahead(a, linkname_length, NULL);
-               if (p == NULL) {
-                       archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
-                           "Truncated Zip file");
-                       return ARCHIVE_FATAL;
-               }
+
                // take into account link compression if any
                size_t linkname_full_length = linkname_length;
                if (zip->entry->compression != 0)
                {
                        // symlink target string appeared to be compressed
                        int status = ARCHIVE_FATAL;
-                       char *uncompressed_buffer =
-                               (char*) malloc(zip_entry->uncompressed_size);
-                       if (uncompressed_buffer == NULL)
-                       {
-                               archive_set_error(&a->archive, ENOMEM,
-                                       "No memory for lzma decompression");
-                               return status;
-                       }
+                       const void *uncompressed_buffer;
 
                        switch (zip->entry->compression)
                        {
+#if HAVE_ZLIB_H
+                               case 8: /* Deflate compression. */
+                                       zip->entry_bytes_remaining = zip_entry->compressed_size;
+                                       status = zip_read_data_deflate(a, &uncompressed_buffer,
+                                               &linkname_full_length, NULL);
+                                       break;
+#endif
 #if HAVE_LZMA_H && HAVE_LIBLZMA
                                case 14: /* ZIPx LZMA compression. */
                                        /*(see zip file format specification, section 4.4.5)*/
-                                       status = zipx_lzma_uncompress_buffer(p,
-                                               linkname_length,
-                                               uncompressed_buffer,
-                                               (size_t)zip_entry->uncompressed_size);
+                                       zip->entry_bytes_remaining = zip_entry->compressed_size;
+                                       status = zip_read_data_zipx_lzma_alone(a, &uncompressed_buffer,
+                                               &linkname_full_length, NULL);
                                        break;
 #endif
                                default: /* Unsupported compression. */
@@ -1280,8 +1211,6 @@ zip_read_local_file_header(struct archive_read *a, struct archive_entry *entry,
                        if (status == ARCHIVE_OK)
                        {
                                p = uncompressed_buffer;
-                               linkname_full_length =
-                                       (size_t)zip_entry->uncompressed_size;
                        }
                        else
                        {
@@ -1294,6 +1223,16 @@ zip_read_local_file_header(struct archive_read *a, struct archive_entry *entry,
                                return ARCHIVE_FAILED;
                        }
                }
+               else
+               {
+                       p = __archive_read_ahead(a, linkname_length, NULL);
+               }
+
+               if (p == NULL) {
+                       archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+                           "Truncated Zip file");
+                       return ARCHIVE_FATAL;
+               }
 
                sconv = zip->sconv;
                if (sconv == NULL && (zip->entry->zip_flags & ZIP_UTF8_NAME))
@@ -1663,7 +1602,8 @@ zipx_lzma_alone_init(struct archive_read *a, struct zip *zip)
        /* To unpack ZIPX's "LZMA" (id 14) stream we can use standard liblzma
         * that is a part of XZ Utils. The stream format stored inside ZIPX
         * file is a modified "lzma alone" file format, that was used by the
-        * `lzma` utility which was later deprecated in favour of `xz` utility.          * Since those formats are nearly the same, we can use a standard
+        * `lzma` utility which was later deprecated in favour of `xz` utility.
+        * Since those formats are nearly the same, we can use a standard
         * "lzma alone" decoder from XZ Utils. */
 
        memset(&zip->zipx_lzma_stream, 0, sizeof(zip->zipx_lzma_stream));
@@ -3415,24 +3355,31 @@ archive_read_support_format_zip_capabilities_seekable(struct archive_read * a)
 static int
 read_eocd(struct zip *zip, const char *p, int64_t current_offset)
 {
+       uint16_t disk_num;
+       uint32_t cd_size, cd_offset;
+       
+       disk_num = archive_le16dec(p + 4);
+       cd_size = archive_le32dec(p + 12);
+       cd_offset = archive_le32dec(p + 16);
+
        /* Sanity-check the EOCD we've found. */
 
        /* This must be the first volume. */
-       if (archive_le16dec(p + 4) != 0)
+       if (disk_num != 0)
                return 0;
        /* Central directory must be on this volume. */
-       if (archive_le16dec(p + 4) != archive_le16dec(p + 6))
+       if (disk_num != archive_le16dec(p + 6))
                return 0;
        /* All central directory entries must be on this volume. */
        if (archive_le16dec(p + 10) != archive_le16dec(p + 8))
                return 0;
        /* Central directory can't extend beyond start of EOCD record. */
-       if (archive_le32dec(p + 16) + archive_le32dec(p + 12)
-           > current_offset)
+       if (cd_offset + cd_size > current_offset)
                return 0;
 
        /* Save the central directory location for later use. */
-       zip->central_directory_offset = archive_le32dec(p + 16);
+       zip->central_directory_offset = cd_offset;
+       zip->central_directory_offset_adjusted = current_offset - cd_size;
 
        /* This is just a tiny bit higher than the maximum
           returned by the streaming Zip bidder.  This ensures
@@ -3484,6 +3431,8 @@ read_zip64_eocd(struct archive_read *a, struct zip *zip, const char *p)
 
        /* Save the central directory offset for later use. */
        zip->central_directory_offset = archive_le64dec(p + 48);
+       /* TODO: Needs scanning backwards to find the eocd64 instead of assuming */
+       zip->central_directory_offset_adjusted = zip->central_directory_offset;
 
        return 32;
 }
@@ -3655,7 +3604,8 @@ slurp_central_directory(struct archive_read *a, struct archive_entry* entry,
         * know the correction we need to apply to account for leading
         * padding.
         */
-       if (__archive_read_seek(a, zip->central_directory_offset, SEEK_SET) < 0)
+       if (__archive_read_seek(a, zip->central_directory_offset_adjusted, SEEK_SET)
+               < 0)
                return ARCHIVE_FATAL;
 
        found = 0;
index 8d70f51..38c14cb 100644 (file)
@@ -482,6 +482,8 @@ archive_write_client_close(struct archive_write_filter *f)
        ssize_t block_length;
        ssize_t target_block_length;
        ssize_t bytes_written;
+       size_t to_write;
+       char *p;
        int ret = ARCHIVE_OK;
 
        /* If there's pending data, pad and write the last block */
@@ -504,9 +506,24 @@ archive_write_client_close(struct archive_write_filter *f)
                            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;
+               p = state->buffer;
+               to_write = block_length;
+               while (to_write > 0) {
+                       bytes_written = (a->client_writer)(&a->archive,
+                           a->client_data, p, to_write);
+                       if (bytes_written <= 0) {
+                               ret = ARCHIVE_FATAL;
+                               break;
+                       }
+                       if ((size_t)bytes_written > to_write) {
+                               archive_set_error(&(a->archive),
+                                                 -1, "write overrun");
+                               ret = ARCHIVE_FATAL;
+                               break;
+                       }
+                       p += bytes_written;
+                       to_write -= bytes_written;
+               }
        }
        if (a->client_closer)
                (*a->client_closer)(&a->archive, a->client_data);
index 2551ebe..e29c3d0 100644 (file)
@@ -173,6 +173,7 @@ struct fixup_entry {
        struct fixup_entry      *next;
        struct archive_acl       acl;
        mode_t                   mode;
+       __LA_MODE_T              filetype;
        int64_t                  atime;
        int64_t                  birthtime;
        int64_t                  mtime;
@@ -357,10 +358,11 @@ struct archive_write_disk {
 
 static int     la_opendirat(int, const char *);
 static int     la_mktemp(struct archive_write_disk *);
+static int     la_verify_filetype(mode_t, __LA_MODE_T);
 static void    fsobj_error(int *, struct archive_string *, int, const char *,
                    const char *);
 static int     check_symlinks_fsobj(char *, int *, struct archive_string *,
-                   int);
+                   int, int);
 static int     check_symlinks(struct archive_write_disk *);
 static int     create_filesystem_object(struct archive_write_disk *);
 static struct fixup_entry *current_fixup(struct archive_write_disk *,
@@ -465,6 +467,39 @@ la_opendirat(int fd, const char *path) {
 }
 
 static int
+la_verify_filetype(mode_t mode, __LA_MODE_T filetype) {
+       int ret = 0;
+
+       switch (filetype) {
+       case AE_IFREG:
+               ret = (S_ISREG(mode));
+               break;
+       case AE_IFDIR:
+               ret = (S_ISDIR(mode));
+               break;
+       case AE_IFLNK:
+               ret = (S_ISLNK(mode));
+               break;
+       case AE_IFSOCK:
+               ret = (S_ISSOCK(mode));
+               break;
+       case AE_IFCHR:
+               ret = (S_ISCHR(mode));
+               break;
+       case AE_IFBLK:
+               ret = (S_ISBLK(mode));
+               break;
+       case AE_IFIFO:
+               ret = (S_ISFIFO(mode));
+               break;
+       default:
+               break;
+       }
+
+       return (ret);
+}
+
+static int
 lazy_stat(struct archive_write_disk *a)
 {
        if (a->pst != NULL) {
@@ -822,6 +857,7 @@ _archive_write_disk_header(struct archive *_a, struct archive_entry *entry)
                fe = current_fixup(a, archive_entry_pathname(entry));
                if (fe == NULL)
                        return (ARCHIVE_FATAL);
+               fe->filetype = archive_entry_filetype(entry);
                fe->fixup |= TODO_MODE_BASE;
                fe->mode = a->mode;
        }
@@ -832,6 +868,7 @@ _archive_write_disk_header(struct archive *_a, struct archive_entry *entry)
                fe = current_fixup(a, archive_entry_pathname(entry));
                if (fe == NULL)
                        return (ARCHIVE_FATAL);
+               fe->filetype = archive_entry_filetype(entry);
                fe->mode = a->mode;
                fe->fixup |= TODO_TIMES;
                if (archive_entry_atime_is_set(entry)) {
@@ -865,6 +902,7 @@ _archive_write_disk_header(struct archive *_a, struct archive_entry *entry)
                fe = current_fixup(a, archive_entry_pathname(entry));
                if (fe == NULL)
                        return (ARCHIVE_FATAL);
+               fe->filetype = archive_entry_filetype(entry);
                fe->fixup |= TODO_ACLS;
                archive_acl_copy(&fe->acl, archive_entry_acl(entry));
        }
@@ -877,6 +915,7 @@ _archive_write_disk_header(struct archive *_a, struct archive_entry *entry)
                        fe = current_fixup(a, archive_entry_pathname(entry));
                        if (fe == NULL)
                                return (ARCHIVE_FATAL);
+                       fe->filetype = archive_entry_filetype(entry);
                        fe->mac_metadata = malloc(metadata_size);
                        if (fe->mac_metadata != NULL) {
                                memcpy(fe->mac_metadata, metadata,
@@ -891,6 +930,7 @@ _archive_write_disk_header(struct archive *_a, struct archive_entry *entry)
                fe = current_fixup(a, archive_entry_pathname(entry));
                if (fe == NULL)
                        return (ARCHIVE_FATAL);
+               fe->filetype = archive_entry_filetype(entry);
                fe->fixup |= TODO_FFLAGS;
                /* TODO: Complete this.. defer fflags from below. */
        }
@@ -2263,7 +2303,7 @@ create_filesystem_object(struct archive_write_disk *a)
                        return (EPERM);
                }
                r = check_symlinks_fsobj(linkname_copy, &error_number,
-                   &error_string, a->flags);
+                   &error_string, a->flags, 1);
                if (r != ARCHIVE_OK) {
                        archive_set_error(&a->archive, error_number, "%s",
                            error_string.s);
@@ -2284,7 +2324,12 @@ create_filesystem_object(struct archive_write_disk *a)
                 */
                if (a->flags & ARCHIVE_EXTRACT_SAFE_WRITES)
                        unlink(a->name);
+#ifdef HAVE_LINKAT
+               r = linkat(AT_FDCWD, linkname, AT_FDCWD, a->name,
+                   0) ? errno : 0;
+#else
                r = link(linkname, a->name) ? errno : 0;
+#endif
                /*
                 * New cpio and pax formats allow hardlink entries
                 * to carry data, so we may have to open the file
@@ -2456,7 +2501,9 @@ _archive_write_disk_close(struct archive *_a)
 {
        struct archive_write_disk *a = (struct archive_write_disk *)_a;
        struct fixup_entry *next, *p;
-       int fd, ret;
+       struct stat st;
+       char *c;
+       int fd, ret, openflags;
 
        archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,
            ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA,
@@ -2469,10 +2516,70 @@ _archive_write_disk_close(struct archive *_a)
        while (p != NULL) {
                fd = -1;
                a->pst = NULL; /* Mark stat cache as out-of-date. */
-               if (p->fixup &
-                   (TODO_TIMES | TODO_MODE_BASE | TODO_ACLS | TODO_FFLAGS)) {
-                       fd = open(p->name,
-                           O_WRONLY | O_BINARY | O_NOFOLLOW | O_CLOEXEC);
+
+               /* We must strip trailing slashes from the path to avoid
+                  dereferencing symbolic links to directories */
+               c = p->name;
+               while (*c != '\0')
+                       c++;
+               while (c != p->name && *(c - 1) == '/') {
+                       c--;
+                       *c = '\0';
+               }
+
+               if (p->fixup == 0)
+                       goto skip_fixup_entry;
+               else {
+                       /*
+                        * We need to verify if the type of the file
+                        * we are going to open matches the file type
+                        * of the fixup entry.
+                        */
+                       openflags = O_BINARY | O_NOFOLLOW | O_RDONLY
+                           | O_CLOEXEC;
+#if defined(O_DIRECTORY)
+                       if (p->filetype == AE_IFDIR)
+                               openflags |= O_DIRECTORY;
+#endif
+                       fd = open(p->name, openflags);
+
+#if defined(O_DIRECTORY)
+                       /*
+                        * If we support O_DIRECTORY and open was
+                        * successful we can skip the file type check
+                        * for directories. For other file types
+                        * we need to verify via fstat() or lstat()
+                        */
+                       if (fd == -1 || p->filetype != AE_IFDIR) {
+#if HAVE_FSTAT
+                               if (fd > 0 && (
+                                   fstat(fd, &st) != 0 ||
+                                   la_verify_filetype(st.st_mode,
+                                   p->filetype) == 0)) {
+                                       goto skip_fixup_entry;
+                               } else
+#endif
+                               if (lstat(p->name, &st) != 0 ||
+                                   la_verify_filetype(st.st_mode,
+                                   p->filetype) == 0) {
+                                       goto skip_fixup_entry;
+                               }
+                       }
+#else
+#if HAVE_FSTAT
+                       if (fd > 0 && (
+                           fstat(fd, &st) != 0 ||
+                           la_verify_filetype(st.st_mode,
+                           p->filetype) == 0)) {
+                               goto skip_fixup_entry;
+                       } else
+#endif
+                       if (lstat(p->name, &st) != 0 ||
+                           la_verify_filetype(st.st_mode,
+                           p->filetype) == 0) {
+                               goto skip_fixup_entry;
+                       }
+#endif
                }
                if (p->fixup & TODO_TIMES) {
                        set_times(a, fd, p->mode, p->name,
@@ -2484,10 +2591,14 @@ _archive_write_disk_close(struct archive *_a)
                if (p->fixup & TODO_MODE_BASE) {
 #ifdef HAVE_FCHMOD
                        if (fd >= 0)
-                               fchmod(fd, p->mode);
+                               fchmod(fd, p->mode & 07777);
                        else
 #endif
-                       chmod(p->name, p->mode);
+#ifdef HAVE_LCHMOD
+                       lchmod(p->name, p->mode & 07777);
+#else
+                       chmod(p->name, p->mode & 07777);
+#endif
                }
                if (p->fixup & TODO_ACLS)
                        archive_write_disk_set_acls(&a->archive, fd,
@@ -2498,6 +2609,7 @@ _archive_write_disk_close(struct archive *_a)
                if (p->fixup & TODO_MAC_METADATA)
                        set_mac_metadata(a, p->name, p->mac_metadata,
                                         p->mac_metadata_size);
+skip_fixup_entry:
                next = p->next;
                archive_acl_clear(&p->acl);
                free(p->mac_metadata);
@@ -2638,6 +2750,7 @@ new_fixup(struct archive_write_disk *a, const char *pathname)
        fe->next = a->fixup_list;
        a->fixup_list = fe;
        fe->fixup = 0;
+       fe->filetype = 0;
        fe->name = strdup(pathname);
        return (fe);
 }
@@ -2675,7 +2788,7 @@ fsobj_error(int *a_eno, struct archive_string *a_estr,
  */
 static int
 check_symlinks_fsobj(char *path, int *a_eno, struct archive_string *a_estr,
-    int flags)
+    int flags, int checking_linkname)
 {
 #if !defined(HAVE_LSTAT) && \
     !(defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_UNLINKAT))
@@ -2684,6 +2797,7 @@ check_symlinks_fsobj(char *path, int *a_eno, struct archive_string *a_estr,
        (void)error_number; /* UNUSED */
        (void)error_string; /* UNUSED */
        (void)flags; /* UNUSED */
+       (void)checking_linkname; /* UNUSED */
        return (ARCHIVE_OK);
 #else
        int res = ARCHIVE_OK;
@@ -2805,6 +2919,28 @@ check_symlinks_fsobj(char *path, int *a_eno, struct archive_string *a_estr,
                                head = tail + 1;
                        }
                } else if (S_ISLNK(st.st_mode)) {
+                       if (last && checking_linkname) {
+#ifdef HAVE_LINKAT
+                               /*
+                                * Hardlinks to symlinks are safe to write
+                                * if linkat() is supported as it does not
+                                * follow symlinks.
+                                */
+                               res = ARCHIVE_OK;
+#else
+                               /*
+                                * We return ARCHIVE_FAILED here as we are
+                                * not able to safely write hardlinks
+                                * to symlinks.
+                                */
+                               tail[0] = c;
+                               fsobj_error(a_eno, a_estr, errno,
+                                   "Cannot write hardlink to symlink ",
+                                   path);
+                               res = ARCHIVE_FAILED;
+#endif
+                               break;
+                       } else
                        if (last) {
                                /*
                                 * Last element is symlink; remove it
@@ -2971,7 +3107,7 @@ check_symlinks(struct archive_write_disk *a)
        int rc;
        archive_string_init(&error_string);
        rc = check_symlinks_fsobj(a->name, &error_number, &error_string,
-           a->flags);
+           a->flags, 0);
        if (rc != ARCHIVE_OK) {
                archive_set_error(&a->archive, error_number, "%s",
                    error_string.s);
@@ -3737,6 +3873,7 @@ set_fflags(struct archive_write_disk *a)
                        le = current_fixup(a, a->name);
                        if (le == NULL)
                                return (ARCHIVE_FATAL);
+                       le->filetype = archive_entry_filetype(a->entry);
                        le->fixup |= TODO_FFLAGS;
                        le->fflags_set = set;
                        /* Store the mode if it's not already there. */
@@ -3899,7 +4036,8 @@ set_fflags_platform(struct archive_write_disk *a, int fd, const char *name,
 
        /* If we weren't given an fd, open it ourselves. */
        if (myfd < 0) {
-               myfd = open(name, O_RDONLY | O_NONBLOCK | O_BINARY | O_CLOEXEC);
+               myfd = open(name, O_RDONLY | O_NONBLOCK | O_BINARY |
+                   O_CLOEXEC | O_NOFOLLOW);
                __archive_ensure_cloexec_flag(myfd);
        }
        if (myfd < 0)
index 47a7403..653089f 100644 (file)
 .Nm archive_write_set_format_ar_svr4 ,
 .Nm archive_write_set_format_by_name ,
 .Nm archive_write_set_format_cpio ,
+.Nm archive_write_set_format_cpio_bin ,
 .Nm archive_write_set_format_cpio_newc ,
+.Nm archive_write_set_format_cpio_odc ,
+.Nm archive_write_set_format_cpio_pwb ,
 .Nm archive_write_set_format_filter_by_ext ,
 .Nm archive_write_set_format_filter_by_ext_def ,
 .Nm archive_write_set_format_gnutar ,
@@ -73,8 +76,14 @@ Streaming Archive Library (libarchive, -larchive)
 .Ft int
 .Fn archive_write_set_format_cpio "struct archive *"
 .Ft int
+.Fn archive_write_set_format_cpio_bin "struct archive *"
+.Ft int
 .Fn archive_write_set_format_cpio_newc "struct archive *"
 .Ft int
+.Fn archive_write_set_format_cpio_odc "struct archive *"
+.Ft int
+.Fn archive_write_set_format_cpio_pwb "struct archive *"
+.Ft int
 .Fn archive_write_set_format_filter_by_ext "struct archive *" "const char *filename"
 .Ft int
 .Fn archive_write_set_format_filter_by_ext_def "struct archive *" "const char *filename" "const char *def_ext"
@@ -119,17 +128,20 @@ to create a new archive with the same format as an existing archive.
 .It Fn archive_write_set_format_by_name
 Sets the corresponding format based on the common name.
 .It Xo
-.Fn archive_write_set_format_filter_by_ext ,
+.Fn archive_write_set_format_filter_by_ext
 .Fn archive_write_set_format_filter_by_ext_def
 .Xc
 Sets both filters and format based on the output filename.
 Supported extensions: .7z, .zip, .jar, .cpio, .iso, .a, .ar, .tar, .tgz, .tar.gz, .tar.bz2, .tar.xz
 .It Xo
 .Fn archive_write_set_format_7zip
-.Fn archive_write_set_format_ar_bsd ,
-.Fn archive_write_set_format_ar_svr4 ,
+.Fn archive_write_set_format_ar_bsd
+.Fn archive_write_set_format_ar_svr4
 .Fn archive_write_set_format_cpio
+.Fn archive_write_set_format_cpio_bin
 .Fn archive_write_set_format_cpio_newc
+.Fn archive_write_set_format_cpio_odc
+.Fn archive_write_set_format_cpio_pwb
 .Fn archive_write_set_format_gnutar
 .Fn archive_write_set_format_iso9660
 .Fn archive_write_set_format_mtree
index 7dbe7b9..1f65fa4 100644 (file)
@@ -44,7 +44,9 @@ struct { int code; int (*setter)(struct archive *); } codes[] =
 {
        { ARCHIVE_FORMAT_7ZIP,          archive_write_set_format_7zip },
        { ARCHIVE_FORMAT_CPIO,          archive_write_set_format_cpio },
-       { ARCHIVE_FORMAT_CPIO_POSIX,    archive_write_set_format_cpio },
+       { ARCHIVE_FORMAT_CPIO_BIN_LE,   archive_write_set_format_cpio_bin },
+       { ARCHIVE_FORMAT_CPIO_PWB,      archive_write_set_format_cpio_pwb },
+       { ARCHIVE_FORMAT_CPIO_POSIX,    archive_write_set_format_cpio_odc },
        { ARCHIVE_FORMAT_CPIO_SVR4_NOCRC,       archive_write_set_format_cpio_newc },
        { ARCHIVE_FORMAT_ISO9660,       archive_write_set_format_iso9660 },
        { ARCHIVE_FORMAT_MTREE,         archive_write_set_format_mtree },
index 7f2e6ac..87b3586 100644 (file)
@@ -755,6 +755,10 @@ _7z_close(struct archive_write *a)
                 */
 #if HAVE_LZMA_H
                header_compression = _7Z_LZMA1;
+               if(zip->opt_compression == _7Z_LZMA2 ||
+                  zip->opt_compression == _7Z_COPY)
+                       header_compression = zip->opt_compression;
+
                /* If the stored file is only one, do not encode the header.
                 * This is the same way 7z command does. */
                if (zip->total_number_entry == 1)
@@ -762,7 +766,8 @@ _7z_close(struct archive_write *a)
 #else
                header_compression = _7Z_COPY;
 #endif
-               r = _7z_compression_init_encoder(a, header_compression, 6);
+               r = _7z_compression_init_encoder(a, header_compression,
+                                                zip->opt_compression_level);
                if (r < 0)
                        return (r);
                zip->crc32flg = PRECODE_CRC32;
index 86e8621..bfb4b35 100644 (file)
@@ -49,6 +49,7 @@ struct { const char *name; int (*setter)(struct archive *); } names[] =
        { "arbsd",      archive_write_set_format_ar_bsd },
        { "argnu",      archive_write_set_format_ar_svr4 },
        { "arsvr4",     archive_write_set_format_ar_svr4 },
+       { "bin",        archive_write_set_format_cpio_bin },
        { "bsdtar",     archive_write_set_format_pax_restricted },
        { "cd9660",     archive_write_set_format_iso9660 },
        { "cpio",       archive_write_set_format_cpio },
@@ -58,11 +59,12 @@ struct { const char *name; int (*setter)(struct archive *); } names[] =
        { "mtree",      archive_write_set_format_mtree },
        { "mtree-classic",      archive_write_set_format_mtree_classic },
        { "newc",       archive_write_set_format_cpio_newc },
-       { "odc",        archive_write_set_format_cpio },
+       { "odc",        archive_write_set_format_cpio_odc },
        { "oldtar",     archive_write_set_format_v7tar },
        { "pax",        archive_write_set_format_pax },
        { "paxr",       archive_write_set_format_pax_restricted },
        { "posix",      archive_write_set_format_pax },
+       { "pwb",        archive_write_set_format_cpio_pwb },
        { "raw",        archive_write_set_format_raw },
        { "rpax",       archive_write_set_format_pax_restricted },
        { "shar",       archive_write_set_format_shar },
index e066733..29a7cad 100644 (file)
-/*-
- * Copyright (c) 2003-2007 Tim Kientzle
- * Copyright (c) 2011-2012 Michihiro NAKAJIMA
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "archive_platform.h"
-__FBSDID("$FreeBSD: head/lib/libarchive/archive_write_set_format_cpio.c 201170 2009-12-29 06:34:23Z kientzle $");
-
-#ifdef HAVE_ERRNO_H
-#include <errno.h>
-#endif
-#include <stdio.h>
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-#ifdef HAVE_STRING_H
-#include <string.h>
-#endif
-
 #include "archive.h"
-#include "archive_entry.h"
-#include "archive_entry_locale.h"
-#include "archive_private.h"
-#include "archive_write_private.h"
-#include "archive_write_set_format_private.h"
-
-static ssize_t archive_write_cpio_data(struct archive_write *,
-                   const void *buff, size_t s);
-static int     archive_write_cpio_close(struct archive_write *);
-static int     archive_write_cpio_free(struct archive_write *);
-static int     archive_write_cpio_finish_entry(struct archive_write *);
-static int     archive_write_cpio_header(struct archive_write *,
-                   struct archive_entry *);
-static int     archive_write_cpio_options(struct archive_write *,
-                   const char *, const char *);
-static int     format_octal(int64_t, void *, int);
-static int64_t format_octal_recursive(int64_t, char *, int);
-static int     write_header(struct archive_write *, struct archive_entry *);
-
-struct cpio {
-       uint64_t          entry_bytes_remaining;
-
-       int64_t           ino_next;
-
-       struct           { int64_t old; int new;} *ino_list;
-       size_t            ino_list_size;
-       size_t            ino_list_next;
-
-       struct archive_string_conv *opt_sconv;
-       struct archive_string_conv *sconv_default;
-       int               init_default_conversion;
-};
-
-#define        c_magic_offset 0
-#define        c_magic_size 6
-#define        c_dev_offset 6
-#define        c_dev_size 6
-#define        c_ino_offset 12
-#define        c_ino_size 6
-#define        c_mode_offset 18
-#define        c_mode_size 6
-#define        c_uid_offset 24
-#define        c_uid_size 6
-#define        c_gid_offset 30
-#define        c_gid_size 6
-#define        c_nlink_offset 36
-#define        c_nlink_size 6
-#define        c_rdev_offset 42
-#define        c_rdev_size 6
-#define        c_mtime_offset 48
-#define        c_mtime_size 11
-#define        c_namesize_offset 59
-#define        c_namesize_size 6
-#define        c_filesize_offset 65
-#define        c_filesize_size 11
 
 /*
- * Set output format to 'cpio' format.
+ * Set output format to the default 'cpio' format.
  */
 int
 archive_write_set_format_cpio(struct archive *_a)
 {
-       struct archive_write *a = (struct archive_write *)_a;
-       struct cpio *cpio;
-
-       archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,
-           ARCHIVE_STATE_NEW, "archive_write_set_format_cpio");
-
-       /* If someone else was already registered, unregister them. */
-       if (a->format_free != NULL)
-               (a->format_free)(a);
-
-       cpio = (struct cpio *)calloc(1, sizeof(*cpio));
-       if (cpio == NULL) {
-               archive_set_error(&a->archive, ENOMEM, "Can't allocate cpio data");
-               return (ARCHIVE_FATAL);
-       }
-       a->format_data = cpio;
-       a->format_name = "cpio";
-       a->format_options = archive_write_cpio_options;
-       a->format_write_header = archive_write_cpio_header;
-       a->format_write_data = archive_write_cpio_data;
-       a->format_finish_entry = archive_write_cpio_finish_entry;
-       a->format_close = archive_write_cpio_close;
-       a->format_free = archive_write_cpio_free;
-       a->archive.archive_format = ARCHIVE_FORMAT_CPIO_POSIX;
-       a->archive.archive_format_name = "POSIX cpio";
-       return (ARCHIVE_OK);
-}
-
-static int
-archive_write_cpio_options(struct archive_write *a, const char *key,
-    const char *val)
-{
-       struct cpio *cpio = (struct cpio *)a->format_data;
-       int ret = ARCHIVE_FAILED;
-
-       if (strcmp(key, "hdrcharset")  == 0) {
-               if (val == NULL || val[0] == 0)
-                       archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
-                           "%s: hdrcharset option needs a character-set name",
-                           a->format_name);
-               else {
-                       cpio->opt_sconv = archive_string_conversion_to_charset(
-                           &a->archive, val, 0);
-                       if (cpio->opt_sconv != NULL)
-                               ret = ARCHIVE_OK;
-                       else
-                               ret = ARCHIVE_FATAL;
-               }
-               return (ret);
-       }
-
-       /* Note: The "warn" return is just to inform the options
-        * supervisor that we didn't handle it.  It will generate
-        * a suitable error if no one used this option. */
-       return (ARCHIVE_WARN);
-}
-
-/*
- * Ino values are as long as 64 bits on some systems; cpio format
- * only allows 18 bits and relies on the ino values to identify hardlinked
- * files.  So, we can't merely "hash" the ino numbers since collisions
- * would corrupt the archive.  Instead, we generate synthetic ino values
- * to store in the archive and maintain a map of original ino values to
- * synthetic ones so we can preserve hardlink information.
- *
- * TODO: Make this more efficient.  It's not as bad as it looks (most
- * files don't have any hardlinks and we don't do any work here for those),
- * but it wouldn't be hard to do better.
- *
- * TODO: Work with dev/ino pairs here instead of just ino values.
- */
-static int
-synthesize_ino_value(struct cpio *cpio, struct archive_entry *entry)
-{
-       int64_t ino = archive_entry_ino64(entry);
-       int ino_new;
-       size_t i;
-
-       /*
-        * If no index number was given, don't assign one.  In
-        * particular, this handles the end-of-archive marker
-        * correctly by giving it a zero index value.  (This is also
-        * why we start our synthetic index numbers with one below.)
-        */
-       if (ino == 0)
-               return (0);
-
-       /* Don't store a mapping if we don't need to. */
-       if (archive_entry_nlink(entry) < 2) {
-               return (int)(++cpio->ino_next);
-       }
-
-       /* Look up old ino; if we have it, this is a hardlink
-        * and we reuse the same value. */
-       for (i = 0; i < cpio->ino_list_next; ++i) {
-               if (cpio->ino_list[i].old == ino)
-                       return (cpio->ino_list[i].new);
-       }
-
-       /* Assign a new index number. */
-       ino_new = (int)(++cpio->ino_next);
-
-       /* Ensure space for the new mapping. */
-       if (cpio->ino_list_size <= cpio->ino_list_next) {
-               size_t newsize = cpio->ino_list_size < 512
-                   ? 512 : cpio->ino_list_size * 2;
-               void *newlist = realloc(cpio->ino_list,
-                   sizeof(cpio->ino_list[0]) * newsize);
-               if (newlist == NULL)
-                       return (-1);
-
-               cpio->ino_list_size = newsize;
-               cpio->ino_list = newlist;
-       }
-
-       /* Record and return the new value. */
-       cpio->ino_list[cpio->ino_list_next].old = ino;
-       cpio->ino_list[cpio->ino_list_next].new = ino_new;
-       ++cpio->ino_list_next;
-       return (ino_new);
-}
-
-
-static struct archive_string_conv *
-get_sconv(struct archive_write *a)
-{
-       struct cpio *cpio;
-       struct archive_string_conv *sconv;
-
-       cpio = (struct cpio *)a->format_data;
-       sconv = cpio->opt_sconv;
-       if (sconv == NULL) {
-               if (!cpio->init_default_conversion) {
-                       cpio->sconv_default =
-                           archive_string_default_conversion_for_write(
-                             &(a->archive));
-                       cpio->init_default_conversion = 1;
-               }
-               sconv = cpio->sconv_default;
-       }
-       return (sconv);
-}
-
-static int
-archive_write_cpio_header(struct archive_write *a, struct archive_entry *entry)
-{
-       const char *path;
-       size_t len;
-
-       if (archive_entry_filetype(entry) == 0 && archive_entry_hardlink(entry) == NULL) {
-               archive_set_error(&a->archive, -1, "Filetype required");
-               return (ARCHIVE_FAILED);
-       }
-
-       if (archive_entry_pathname_l(entry, &path, &len, get_sconv(a)) != 0
-           && errno == ENOMEM) {
-               archive_set_error(&a->archive, ENOMEM,
-                   "Can't allocate memory for Pathname");
-               return (ARCHIVE_FATAL);
-       }
-       if (len == 0 || path == NULL || path[0] == '\0') {
-               archive_set_error(&a->archive, -1, "Pathname required");
-               return (ARCHIVE_FAILED);
-       }
-
-       if (!archive_entry_size_is_set(entry) || archive_entry_size(entry) < 0) {
-               archive_set_error(&a->archive, -1, "Size required");
-               return (ARCHIVE_FAILED);
-       }
-       return write_header(a, entry);
-}
-
-static int
-write_header(struct archive_write *a, struct archive_entry *entry)
-{
-       struct cpio *cpio;
-       const char *p, *path;
-       int pathlength, ret, ret_final;
-       int64_t ino;
-       char h[76];
-       struct archive_string_conv *sconv;
-       struct archive_entry *entry_main;
-       size_t len;
-
-       cpio = (struct cpio *)a->format_data;
-       ret_final = ARCHIVE_OK;
-       sconv = get_sconv(a);
-
-#if defined(_WIN32) && !defined(__CYGWIN__)
-       /* Make sure the path separators in pathname, hardlink and symlink
-        * are all slash '/', not the Windows path separator '\'. */
-       entry_main = __la_win_entry_in_posix_pathseparator(entry);
-       if (entry_main == NULL) {
-               archive_set_error(&a->archive, ENOMEM,
-                   "Can't allocate ustar data");
-               return(ARCHIVE_FATAL);
-       }
-       if (entry != entry_main)
-               entry = entry_main;
-       else
-               entry_main = NULL;
-#else
-       entry_main = NULL;
-#endif
-
-       ret = archive_entry_pathname_l(entry, &path, &len, sconv);
-       if (ret != 0) {
-               if (errno == ENOMEM) {
-                       archive_set_error(&a->archive, ENOMEM,
-                           "Can't allocate memory for Pathname");
-                       ret_final = ARCHIVE_FATAL;
-                       goto exit_write_header;
-               }
-               archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
-                   "Can't translate pathname '%s' to %s",
-                   archive_entry_pathname(entry),
-                   archive_string_conversion_charset_name(sconv));
-               ret_final = ARCHIVE_WARN;
-       }
-       /* Include trailing null. */
-       pathlength = (int)len + 1;
-
-       memset(h, 0, sizeof(h));
-       format_octal(070707, h + c_magic_offset, c_magic_size);
-       format_octal(archive_entry_dev(entry), h + c_dev_offset, c_dev_size);
-
-       ino = synthesize_ino_value(cpio, entry);
-       if (ino < 0) {
-               archive_set_error(&a->archive, ENOMEM,
-                   "No memory for ino translation table");
-               ret_final = ARCHIVE_FATAL;
-               goto exit_write_header;
-       } else if (ino > 0777777) {
-               archive_set_error(&a->archive, ERANGE,
-                   "Too many files for this cpio format");
-               ret_final = ARCHIVE_FATAL;
-               goto exit_write_header;
-       }
-       format_octal(ino & 0777777, h + c_ino_offset, c_ino_size);
-
-       /* TODO: Set ret_final to ARCHIVE_WARN if any of these overflow. */
-       format_octal(archive_entry_mode(entry), h + c_mode_offset, c_mode_size);
-       format_octal(archive_entry_uid(entry), h + c_uid_offset, c_uid_size);
-       format_octal(archive_entry_gid(entry), h + c_gid_offset, c_gid_size);
-       format_octal(archive_entry_nlink(entry), h + c_nlink_offset, c_nlink_size);
-       if (archive_entry_filetype(entry) == AE_IFBLK
-           || archive_entry_filetype(entry) == AE_IFCHR)
-           format_octal(archive_entry_rdev(entry), h + c_rdev_offset, c_rdev_size);
-       else
-           format_octal(0, h + c_rdev_offset, c_rdev_size);
-       format_octal(archive_entry_mtime(entry), h + c_mtime_offset, c_mtime_size);
-       format_octal(pathlength, h + c_namesize_offset, c_namesize_size);
-
-       /* Non-regular files don't store bodies. */
-       if (archive_entry_filetype(entry) != AE_IFREG)
-               archive_entry_set_size(entry, 0);
-
-       /* Symlinks get the link written as the body of the entry. */
-       ret = archive_entry_symlink_l(entry, &p, &len, sconv);
-       if (ret != 0) {
-               if (errno == ENOMEM) {
-                       archive_set_error(&a->archive, ENOMEM,
-                           "Can't allocate memory for Linkname");
-                       ret_final = ARCHIVE_FATAL;
-                       goto exit_write_header;
-               }
-               archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
-                   "Can't translate linkname '%s' to %s",
-                   archive_entry_symlink(entry),
-                   archive_string_conversion_charset_name(sconv));
-               ret_final = ARCHIVE_WARN;
-       }
-       if (len > 0 && p != NULL  &&  *p != '\0')
-               ret = format_octal(strlen(p), h + c_filesize_offset,
-                   c_filesize_size);
-       else
-               ret = format_octal(archive_entry_size(entry),
-                   h + c_filesize_offset, c_filesize_size);
-       if (ret) {
-               archive_set_error(&a->archive, ERANGE,
-                   "File is too large for cpio format.");
-               ret_final = ARCHIVE_FAILED;
-               goto exit_write_header;
-       }
-
-       ret = __archive_write_output(a, h, sizeof(h));
-       if (ret != ARCHIVE_OK) {
-               ret_final = ARCHIVE_FATAL;
-               goto exit_write_header;
-       }
-
-       ret = __archive_write_output(a, path, pathlength);
-       if (ret != ARCHIVE_OK) {
-               ret_final = ARCHIVE_FATAL;
-               goto exit_write_header;
-       }
-
-       cpio->entry_bytes_remaining = archive_entry_size(entry);
-
-       /* Write the symlink now. */
-       if (p != NULL  &&  *p != '\0') {
-               ret = __archive_write_output(a, p, strlen(p));
-               if (ret != ARCHIVE_OK) {
-                       ret_final = ARCHIVE_FATAL;
-                       goto exit_write_header;
-               }
-       }
-exit_write_header:
-       archive_entry_free(entry_main);
-       return (ret_final);
-}
-
-static ssize_t
-archive_write_cpio_data(struct archive_write *a, const void *buff, size_t s)
-{
-       struct cpio *cpio;
-       int ret;
-
-       cpio = (struct cpio *)a->format_data;
-       if (s > cpio->entry_bytes_remaining)
-               s = (size_t)cpio->entry_bytes_remaining;
-
-       ret = __archive_write_output(a, buff, s);
-       cpio->entry_bytes_remaining -= s;
-       if (ret >= 0)
-               return (s);
-       else
-               return (ret);
-}
-
-/*
- * Format a number into the specified field.
- */
-static int
-format_octal(int64_t v, void *p, int digits)
-{
-       int64_t max;
-       int     ret;
-
-       max = (((int64_t)1) << (digits * 3)) - 1;
-       if (v >= 0  &&  v <= max) {
-           format_octal_recursive(v, (char *)p, digits);
-           ret = 0;
-       } else {
-           format_octal_recursive(max, (char *)p, digits);
-           ret = -1;
-       }
-       return (ret);
-}
-
-static int64_t
-format_octal_recursive(int64_t v, char *p, int s)
-{
-       if (s == 0)
-               return (v);
-       v = format_octal_recursive(v, p+1, s-1);
-       *p = '0' + ((char)v & 7);
-       return (v >> 3);
-}
-
-static int
-archive_write_cpio_close(struct archive_write *a)
-{
-       int er;
-       struct archive_entry *trailer;
-
-       trailer = archive_entry_new2(NULL);
-       /* nlink = 1 here for GNU cpio compat. */
-       archive_entry_set_nlink(trailer, 1);
-       archive_entry_set_size(trailer, 0);
-       archive_entry_set_pathname(trailer, "TRAILER!!!");
-       er = write_header(a, trailer);
-       archive_entry_free(trailer);
-       return (er);
-}
-
-static int
-archive_write_cpio_free(struct archive_write *a)
-{
-       struct cpio *cpio;
-
-       cpio = (struct cpio *)a->format_data;
-       free(cpio->ino_list);
-       free(cpio);
-       a->format_data = NULL;
-       return (ARCHIVE_OK);
-}
-
-static int
-archive_write_cpio_finish_entry(struct archive_write *a)
-{
-       struct cpio *cpio;
-
-       cpio = (struct cpio *)a->format_data;
-       return (__archive_write_nulls(a,
-               (size_t)cpio->entry_bytes_remaining));
+       return archive_write_set_format_cpio_odc(_a);
 }
diff --git a/Utilities/cmlibarchive/libarchive/archive_write_set_format_cpio_binary.c b/Utilities/cmlibarchive/libarchive/archive_write_set_format_cpio_binary.c
new file mode 100644 (file)
index 0000000..c1e2f65
--- /dev/null
@@ -0,0 +1,610 @@
+/*-
+ * Copyright (c) 2003-2007 Tim Kientzle
+ * Copyright (c) 2011-2012 Michihiro NAKAJIMA
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "archive_platform.h"
+__FBSDID("$FreeBSD: head/lib/libarchive/archive_write_set_format_cpio.c 201170 2009-12-29 06:34:23Z kientzle $");
+
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#include <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#include "archive.h"
+#include "archive_entry.h"
+#include "archive_entry_locale.h"
+#include "archive_private.h"
+#include "archive_write_private.h"
+#include "archive_write_set_format_private.h"
+
+static ssize_t archive_write_binary_data(struct archive_write *,
+                   const void *buff, size_t s);
+static int     archive_write_binary_close(struct archive_write *);
+static int     archive_write_binary_free(struct archive_write *);
+static int     archive_write_binary_finish_entry(struct archive_write *);
+static int     archive_write_binary_header(struct archive_write *,
+                   struct archive_entry *);
+static int     archive_write_binary_options(struct archive_write *,
+                   const char *, const char *);
+static int     write_header(struct archive_write *, struct archive_entry *);
+
+struct cpio {
+       uint64_t          entry_bytes_remaining;
+
+       int64_t           ino_next;
+
+       struct           { int64_t old; int new;} *ino_list;
+       size_t            ino_list_size;
+       size_t            ino_list_next;
+
+       struct archive_string_conv *opt_sconv;
+       struct archive_string_conv *sconv_default;
+       int               init_default_conversion;
+};
+
+/* This struct needs to be packed to get the header right */
+
+#if defined(__GNUC__)
+#define PACKED(x) x __attribute__((packed))
+#elif defined(_MSC_VER)
+#define PACKED(x) __pragma(pack(push, 1)) x __pragma(pack(pop))
+#else
+#define PACKED(x) x
+#endif
+
+#define HSIZE 26
+
+PACKED(struct cpio_binary_header {
+       uint16_t        h_magic;
+       uint16_t        h_dev;
+       uint16_t        h_ino;
+       uint16_t        h_mode;
+       uint16_t        h_uid;
+       uint16_t        h_gid;
+       uint16_t        h_nlink;
+       uint16_t        h_majmin;
+       uint32_t        h_mtime;
+       uint16_t        h_namesize;
+       uint32_t        h_filesize;
+});
+
+/* Back in the day, the 7th Edition cpio.c had this, to
+ * adapt to, as the comment said, "VAX, Interdata, ...":
+ *
+ * union { long l; short s[2]; char c[4]; } U;
+ * #define MKSHORT(v,lv) {U.l=1L;if(U.c[0]) U.l=lv,v[0]=U.s[1],v[1]=U.s[0]; else U.l=lv,v[0]=U.s[0],v[1]=U.s[1];}
+ * long mklong(v)
+ * short v[];
+ * {
+ *         U.l = 1;
+ *         if(U.c[0])
+ *                 U.s[0] = v[1], U.s[1] = v[0];
+ *         else
+ *                 U.s[0] = v[0], U.s[1] = v[1];
+ *         return U.l;
+ * }
+ *
+ * Of course, that assumes that all machines have little-endian shorts,
+ * and just adapts the others to the special endianness of the PDP-11.
+ *
+ * Now, we could do this:
+ *
+ * union { uint32_t l; uint16_t s[2]; uint8_t c[4]; } U;
+ * #define PUTI16(v,sv) {U.s[0]=1;if(U.c[0]) v=sv; else U.s[0]=sv,U.c[2]=U.c[1],U.c[3]=U.c[0],v=U.s[1];}
+ * #define PUTI32(v,lv) {char_t Ut;U.l=1;if(U.c[0]) U.l=lv,v[0]=U.s[1],v[1]=U.s[0]; else U.l=lv,Ut=U.c[0],U.c[0]=U.c[1],U.c[1]=Ut,Ut=U.c[2],U.c[2]=U.c[3],U.c[3]=Ut,v[0]=U.s[0],v[1]=U.s[1];}
+ *
+ * ...but it feels a little better to do it like this:
+ */
+
+static uint16_t swap16(uint16_t in) {
+       union {
+               uint16_t s[2];
+               uint8_t c[4];
+       } U;
+       U.s[0] = 1;
+       if (U.c[0])
+               return in;
+       else {
+               U.s[0] = in;
+               U.c[2] = U.c[1];
+               U.c[3] = U.c[0];
+               return U.s[1];
+       }
+       /* NOTREACHED */
+}
+
+static uint32_t swap32(uint32_t in) {
+       union {
+               uint32_t l;
+               uint16_t s[2];
+               uint8_t c[4];
+       } U;
+       U.l = 1;
+       if (U.c[0]) {           /* Little-endian */
+               uint16_t t;
+               U.l = in;
+               t = U.s[0];
+               U.s[0] = U.s[1];
+               U.s[1] = t;
+       } else if (U.c[3]) {    /* Big-endian */
+               U.l = in;
+               U.s[0] = swap16(U.s[0]);
+               U.s[1] = swap16(U.s[1]);
+       } else {                /* PDP-endian */
+               U.l = in;
+       }
+       return U.l;
+}
+
+/*
+ * Set output format to the selected binary variant
+ */
+static int
+archive_write_set_format_cpio_binary(struct archive *_a, int format)
+{
+       struct archive_write *a = (struct archive_write *)_a;
+       struct cpio *cpio;
+
+       if (sizeof(struct cpio_binary_header) != HSIZE) {
+               archive_set_error(&a->archive, EINVAL,
+                                 "Binary cpio format not supported on this platform");
+               return (ARCHIVE_FATAL);
+       }
+
+       archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,
+           ARCHIVE_STATE_NEW, "archive_write_set_format_cpio_binary");
+
+       /* If someone else was already registered, unregister them. */
+       if (a->format_free != NULL)
+               (a->format_free)(a);
+
+       cpio = (struct cpio *)calloc(1, sizeof(*cpio));
+       if (cpio == NULL) {
+               archive_set_error(&a->archive, ENOMEM, "Can't allocate cpio data");
+               return (ARCHIVE_FATAL);
+       }
+       a->format_data = cpio;
+       a->format_name = "cpio";
+       a->format_options = archive_write_binary_options;
+       a->format_write_header = archive_write_binary_header;
+       a->format_write_data = archive_write_binary_data;
+       a->format_finish_entry = archive_write_binary_finish_entry;
+       a->format_close = archive_write_binary_close;
+       a->format_free = archive_write_binary_free;
+       a->archive.archive_format = format;
+       switch (format) {
+       case ARCHIVE_FORMAT_CPIO_PWB:
+               a->archive.archive_format_name = "PWB cpio";
+               break;
+       case ARCHIVE_FORMAT_CPIO_BIN_LE:
+               a->archive.archive_format_name = "7th Edition cpio";
+               break;
+       default:
+               archive_set_error(&a->archive, EINVAL, "binary format must be 'pwb' or 'bin'");
+               return (ARCHIVE_FATAL);
+       }
+       return (ARCHIVE_OK);
+}
+
+/*
+ * Set output format to PWB (6th Edition) binary format
+ */
+int
+archive_write_set_format_cpio_pwb(struct archive *_a)
+{
+       return archive_write_set_format_cpio_binary(_a, ARCHIVE_FORMAT_CPIO_PWB);
+}
+
+/*
+ * Set output format to 7th Edition binary format
+ */
+int
+archive_write_set_format_cpio_bin(struct archive *_a)
+{
+       return archive_write_set_format_cpio_binary(_a, ARCHIVE_FORMAT_CPIO_BIN_LE);
+}
+
+static int
+archive_write_binary_options(struct archive_write *a, const char *key,
+    const char *val)
+{
+       struct cpio *cpio = (struct cpio *)a->format_data;
+       int ret = ARCHIVE_FAILED;
+
+       if (strcmp(key, "hdrcharset")  == 0) {
+               if (val == NULL || val[0] == 0)
+                       archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+                           "%s: hdrcharset option needs a character-set name",
+                           a->format_name);
+               else {
+                       cpio->opt_sconv = archive_string_conversion_to_charset(
+                           &a->archive, val, 0);
+                       if (cpio->opt_sconv != NULL)
+                               ret = ARCHIVE_OK;
+                       else
+                               ret = ARCHIVE_FATAL;
+               }
+               return (ret);
+       }
+
+       /* Note: The "warn" return is just to inform the options
+        * supervisor that we didn't handle it.  It will generate
+        * a suitable error if no one used this option. */
+       return (ARCHIVE_WARN);
+}
+
+/*
+ * Ino values are as long as 64 bits on some systems; cpio format
+ * only allows 16 bits and relies on the ino values to identify hardlinked
+ * files.  So, we can't merely "hash" the ino numbers since collisions
+ * would corrupt the archive.  Instead, we generate synthetic ino values
+ * to store in the archive and maintain a map of original ino values to
+ * synthetic ones so we can preserve hardlink information.
+ *
+ * TODO: Make this more efficient.  It's not as bad as it looks (most
+ * files don't have any hardlinks and we don't do any work here for those),
+ * but it wouldn't be hard to do better.
+ *
+ * TODO: Work with dev/ino pairs here instead of just ino values.
+ */
+static int
+synthesize_ino_value(struct cpio *cpio, struct archive_entry *entry)
+{
+       int64_t ino = archive_entry_ino64(entry);
+       int ino_new;
+       size_t i;
+
+       /*
+        * If no index number was given, don't assign one.  In
+        * particular, this handles the end-of-archive marker
+        * correctly by giving it a zero index value.  (This is also
+        * why we start our synthetic index numbers with one below.)
+        */
+       if (ino == 0)
+               return (0);
+
+       /* Don't store a mapping if we don't need to. */
+       if (archive_entry_nlink(entry) < 2) {
+               return (int)(++cpio->ino_next);
+       }
+
+       /* Look up old ino; if we have it, this is a hardlink
+        * and we reuse the same value. */
+       for (i = 0; i < cpio->ino_list_next; ++i) {
+               if (cpio->ino_list[i].old == ino)
+                       return (cpio->ino_list[i].new);
+       }
+
+       /* Assign a new index number. */
+       ino_new = (int)(++cpio->ino_next);
+
+       /* Ensure space for the new mapping. */
+       if (cpio->ino_list_size <= cpio->ino_list_next) {
+               size_t newsize = cpio->ino_list_size < 512
+                   ? 512 : cpio->ino_list_size * 2;
+               void *newlist = realloc(cpio->ino_list,
+                   sizeof(cpio->ino_list[0]) * newsize);
+               if (newlist == NULL)
+                       return (-1);
+
+               cpio->ino_list_size = newsize;
+               cpio->ino_list = newlist;
+       }
+
+       /* Record and return the new value. */
+       cpio->ino_list[cpio->ino_list_next].old = ino;
+       cpio->ino_list[cpio->ino_list_next].new = ino_new;
+       ++cpio->ino_list_next;
+       return (ino_new);
+}
+
+
+static struct archive_string_conv *
+get_sconv(struct archive_write *a)
+{
+       struct cpio *cpio;
+       struct archive_string_conv *sconv;
+
+       cpio = (struct cpio *)a->format_data;
+       sconv = cpio->opt_sconv;
+       if (sconv == NULL) {
+               if (!cpio->init_default_conversion) {
+                       cpio->sconv_default =
+                           archive_string_default_conversion_for_write(
+                             &(a->archive));
+                       cpio->init_default_conversion = 1;
+               }
+               sconv = cpio->sconv_default;
+       }
+       return (sconv);
+}
+
+static int
+archive_write_binary_header(struct archive_write *a, struct archive_entry *entry)
+{
+       const char *path;
+       size_t len;
+
+       if (archive_entry_filetype(entry) == 0 && archive_entry_hardlink(entry) == NULL) {
+               archive_set_error(&a->archive, -1, "Filetype required");
+               return (ARCHIVE_FAILED);
+       }
+
+       if (archive_entry_pathname_l(entry, &path, &len, get_sconv(a)) != 0
+           && errno == ENOMEM) {
+               archive_set_error(&a->archive, ENOMEM,
+                   "Can't allocate memory for Pathname");
+               return (ARCHIVE_FATAL);
+       }
+       if (len == 0 || path == NULL || path[0] == '\0') {
+               archive_set_error(&a->archive, -1, "Pathname required");
+               return (ARCHIVE_FAILED);
+       }
+
+       if (!archive_entry_size_is_set(entry) || archive_entry_size(entry) < 0) {
+               archive_set_error(&a->archive, -1, "Size required");
+               return (ARCHIVE_FAILED);
+       }
+       return write_header(a, entry);
+}
+
+static int
+write_header(struct archive_write *a, struct archive_entry *entry)
+{
+       struct cpio *cpio;
+       const char *p, *path;
+       int pathlength, ret, ret_final;
+       int64_t ino;
+       struct cpio_binary_header h;
+       struct archive_string_conv *sconv;
+       struct archive_entry *entry_main;
+       size_t len;
+
+       cpio = (struct cpio *)a->format_data;
+       ret_final = ARCHIVE_OK;
+       sconv = get_sconv(a);
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+       /* Make sure the path separators in pathname, hardlink and symlink
+        * are all slash '/', not the Windows path separator '\'. */
+       entry_main = __la_win_entry_in_posix_pathseparator(entry);
+       if (entry_main == NULL) {
+               archive_set_error(&a->archive, ENOMEM,
+                   "Can't allocate ustar data");
+               return(ARCHIVE_FATAL);
+       }
+       if (entry != entry_main)
+               entry = entry_main;
+       else
+               entry_main = NULL;
+#else
+       entry_main = NULL;
+#endif
+
+       ret = archive_entry_pathname_l(entry, &path, &len, sconv);
+       if (ret != 0) {
+               if (errno == ENOMEM) {
+                       archive_set_error(&a->archive, ENOMEM,
+                           "Can't allocate memory for Pathname");
+                       ret_final = ARCHIVE_FATAL;
+                       goto exit_write_header;
+               }
+               archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+                   "Can't translate pathname '%s' to %s",
+                   archive_entry_pathname(entry),
+                   archive_string_conversion_charset_name(sconv));
+               ret_final = ARCHIVE_WARN;
+       }
+       /* Include trailing null */
+       pathlength = (int)len + 1;
+
+       h.h_magic = swap16(070707);
+       h.h_dev = swap16(archive_entry_dev(entry));
+
+       ino = synthesize_ino_value(cpio, entry);
+       if (ino < 0) {
+               archive_set_error(&a->archive, ENOMEM,
+                   "No memory for ino translation table");
+               ret_final = ARCHIVE_FATAL;
+               goto exit_write_header;
+       } else if (ino > 077777) {
+               archive_set_error(&a->archive, ERANGE,
+                   "Too many files for this cpio format");
+               ret_final = ARCHIVE_FATAL;
+               goto exit_write_header;
+       }
+       h.h_ino = swap16(ino);
+
+       h.h_mode = archive_entry_mode(entry);
+       if (((h.h_mode & AE_IFMT) == AE_IFSOCK) || ((h.h_mode & AE_IFMT) == AE_IFIFO)) {
+               archive_set_error(&a->archive, EINVAL,
+                                 "sockets and fifos cannot be represented in the binary cpio formats");
+               ret_final = ARCHIVE_FATAL;
+               goto exit_write_header;
+       }
+       if (a->archive.archive_format == ARCHIVE_FORMAT_CPIO_PWB) {
+               if ((h.h_mode & AE_IFMT) == AE_IFLNK) {
+                       archive_set_error(&a->archive, EINVAL,
+                                         "symbolic links cannot be represented in the PWB cpio format");
+                       ret_final = ARCHIVE_FATAL;
+                       goto exit_write_header;
+               }
+               /* we could turn off AE_IFREG here, but it does no harm, */
+               /* and allows v7 cpio to read the entry without confusion */
+       }
+       h.h_mode = swap16(h.h_mode);
+
+       h.h_uid = swap16(archive_entry_uid(entry));
+       h.h_gid = swap16(archive_entry_gid(entry));
+       h.h_nlink = swap16(archive_entry_nlink(entry));
+
+       if (archive_entry_filetype(entry) == AE_IFBLK
+           || archive_entry_filetype(entry) == AE_IFCHR)
+               h.h_majmin = swap16(archive_entry_rdev(entry));
+       else
+               h.h_majmin = 0;
+
+       h.h_mtime = swap32(archive_entry_mtime(entry));
+       h.h_namesize = swap16(pathlength);
+
+       /* Non-regular files don't store bodies. */
+       if (archive_entry_filetype(entry) != AE_IFREG)
+               archive_entry_set_size(entry, 0);
+
+       /* Symlinks get the link written as the body of the entry. */
+       ret = archive_entry_symlink_l(entry, &p, &len, sconv);
+       if (ret != 0) {
+               if (errno == ENOMEM) {
+                       archive_set_error(&a->archive, ENOMEM,
+                           "Can't allocate memory for Linkname");
+                       ret_final = ARCHIVE_FATAL;
+                       goto exit_write_header;
+               }
+               archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+                   "Can't translate linkname '%s' to %s",
+                   archive_entry_symlink(entry),
+                   archive_string_conversion_charset_name(sconv));
+               ret_final = ARCHIVE_WARN;
+       }
+
+       if (len > 0 && p != NULL  &&  *p != '\0') {
+               if (a->archive.archive_format == ARCHIVE_FORMAT_CPIO_PWB) {
+                       archive_set_error(&a->archive, EINVAL,
+                                         "symlinks are not supported by UNIX V6 or by PWB cpio");
+                       ret_final = ARCHIVE_FATAL;
+                       goto exit_write_header;
+               }
+               h.h_filesize = swap32(strlen(p)); /* symlink */
+       } else {
+               if ((a->archive.archive_format == ARCHIVE_FORMAT_CPIO_PWB) &&
+                   (archive_entry_size(entry) > 256*256*256-1)) {
+                       archive_set_error(&a->archive, ERANGE,
+                                         "File is too large for PWB binary cpio format.");
+                       ret_final = ARCHIVE_FAILED;
+                       goto exit_write_header;
+               } else if (archive_entry_size(entry) > INT32_MAX) {
+                       archive_set_error(&a->archive, ERANGE,
+                                         "File is too large for binary cpio format.");
+                       ret_final = ARCHIVE_FAILED;
+                       goto exit_write_header;
+               }
+               h.h_filesize = swap32(archive_entry_size(entry)); /* file */
+       }
+
+       ret = __archive_write_output(a, &h, HSIZE);
+       if (ret != ARCHIVE_OK) {
+               ret_final = ARCHIVE_FATAL;
+               goto exit_write_header;
+       }
+
+       ret = __archive_write_output(a, path, pathlength);
+       if ((ret == ARCHIVE_OK) && ((pathlength % 2) != 0))
+               ret = __archive_write_nulls(a, 1);
+       if (ret != ARCHIVE_OK) {
+               ret_final = ARCHIVE_FATAL;
+               goto exit_write_header;
+       }
+
+       cpio->entry_bytes_remaining = archive_entry_size(entry);
+       if ((cpio->entry_bytes_remaining % 2) != 0)
+               cpio->entry_bytes_remaining++;
+
+       /* Write the symlink now. */
+       if (p != NULL  &&  *p != '\0') {
+               ret = __archive_write_output(a, p, strlen(p));
+               if ((ret == ARCHIVE_OK) && ((strlen(p) % 2) != 0))
+                       ret = __archive_write_nulls(a, 1);
+               if (ret != ARCHIVE_OK) {
+                       ret_final = ARCHIVE_FATAL;
+                       goto exit_write_header;
+               }
+       }
+
+exit_write_header:
+       archive_entry_free(entry_main);
+       return (ret_final);
+}
+
+static ssize_t
+archive_write_binary_data(struct archive_write *a, const void *buff, size_t s)
+{
+       struct cpio *cpio;
+       int ret;
+
+       cpio = (struct cpio *)a->format_data;
+       if (s > cpio->entry_bytes_remaining)
+               s = (size_t)cpio->entry_bytes_remaining;
+
+       ret = __archive_write_output(a, buff, s);
+       cpio->entry_bytes_remaining -= s;
+       if (ret >= 0)
+               return (s);
+       else
+               return (ret);
+}
+
+static int
+archive_write_binary_close(struct archive_write *a)
+{
+       int er;
+       struct archive_entry *trailer;
+
+       trailer = archive_entry_new2(NULL);
+       /* nlink = 1 here for GNU cpio compat. */
+       archive_entry_set_nlink(trailer, 1);
+       archive_entry_set_size(trailer, 0);
+       archive_entry_set_pathname(trailer, "TRAILER!!!");
+       er = write_header(a, trailer);
+       archive_entry_free(trailer);
+       return (er);
+}
+
+static int
+archive_write_binary_free(struct archive_write *a)
+{
+       struct cpio *cpio;
+
+       cpio = (struct cpio *)a->format_data;
+       free(cpio->ino_list);
+       free(cpio);
+       a->format_data = NULL;
+       return (ARCHIVE_OK);
+}
+
+static int
+archive_write_binary_finish_entry(struct archive_write *a)
+{
+       struct cpio *cpio;
+
+       cpio = (struct cpio *)a->format_data;
+       return (__archive_write_nulls(a,
+               (size_t)cpio->entry_bytes_remaining));
+}
diff --git a/Utilities/cmlibarchive/libarchive/archive_write_set_format_cpio_odc.c b/Utilities/cmlibarchive/libarchive/archive_write_set_format_cpio_odc.c
new file mode 100644 (file)
index 0000000..091925a
--- /dev/null
@@ -0,0 +1,500 @@
+/*-
+ * Copyright (c) 2003-2007 Tim Kientzle
+ * Copyright (c) 2011-2012 Michihiro NAKAJIMA
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "archive_platform.h"
+__FBSDID("$FreeBSD: head/lib/libarchive/archive_write_set_format_cpio.c 201170 2009-12-29 06:34:23Z kientzle $");
+
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#include <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#include "archive.h"
+#include "archive_entry.h"
+#include "archive_entry_locale.h"
+#include "archive_private.h"
+#include "archive_write_private.h"
+#include "archive_write_set_format_private.h"
+
+static ssize_t archive_write_odc_data(struct archive_write *,
+                   const void *buff, size_t s);
+static int     archive_write_odc_close(struct archive_write *);
+static int     archive_write_odc_free(struct archive_write *);
+static int     archive_write_odc_finish_entry(struct archive_write *);
+static int     archive_write_odc_header(struct archive_write *,
+                   struct archive_entry *);
+static int     archive_write_odc_options(struct archive_write *,
+                   const char *, const char *);
+static int     format_octal(int64_t, void *, int);
+static int64_t format_octal_recursive(int64_t, char *, int);
+static int     write_header(struct archive_write *, struct archive_entry *);
+
+struct cpio {
+       uint64_t          entry_bytes_remaining;
+
+       int64_t           ino_next;
+
+       struct           { int64_t old; int new;} *ino_list;
+       size_t            ino_list_size;
+       size_t            ino_list_next;
+
+       struct archive_string_conv *opt_sconv;
+       struct archive_string_conv *sconv_default;
+       int               init_default_conversion;
+};
+
+#define        c_magic_offset 0
+#define        c_magic_size 6
+#define        c_dev_offset 6
+#define        c_dev_size 6
+#define        c_ino_offset 12
+#define        c_ino_size 6
+#define        c_mode_offset 18
+#define        c_mode_size 6
+#define        c_uid_offset 24
+#define        c_uid_size 6
+#define        c_gid_offset 30
+#define        c_gid_size 6
+#define        c_nlink_offset 36
+#define        c_nlink_size 6
+#define        c_rdev_offset 42
+#define        c_rdev_size 6
+#define        c_mtime_offset 48
+#define        c_mtime_size 11
+#define        c_namesize_offset 59
+#define        c_namesize_size 6
+#define        c_filesize_offset 65
+#define        c_filesize_size 11
+
+/*
+ * Set output format to 'cpio' format.
+ */
+int
+archive_write_set_format_cpio_odc(struct archive *_a)
+{
+       struct archive_write *a = (struct archive_write *)_a;
+       struct cpio *cpio;
+
+       archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,
+           ARCHIVE_STATE_NEW, "archive_write_set_format_cpio_odc");
+
+       /* If someone else was already registered, unregister them. */
+       if (a->format_free != NULL)
+               (a->format_free)(a);
+
+       cpio = (struct cpio *)calloc(1, sizeof(*cpio));
+       if (cpio == NULL) {
+               archive_set_error(&a->archive, ENOMEM, "Can't allocate cpio data");
+               return (ARCHIVE_FATAL);
+       }
+       a->format_data = cpio;
+       a->format_name = "cpio";
+       a->format_options = archive_write_odc_options;
+       a->format_write_header = archive_write_odc_header;
+       a->format_write_data = archive_write_odc_data;
+       a->format_finish_entry = archive_write_odc_finish_entry;
+       a->format_close = archive_write_odc_close;
+       a->format_free = archive_write_odc_free;
+       a->archive.archive_format = ARCHIVE_FORMAT_CPIO_POSIX;
+       a->archive.archive_format_name = "POSIX cpio";
+       return (ARCHIVE_OK);
+}
+
+static int
+archive_write_odc_options(struct archive_write *a, const char *key,
+    const char *val)
+{
+       struct cpio *cpio = (struct cpio *)a->format_data;
+       int ret = ARCHIVE_FAILED;
+
+       if (strcmp(key, "hdrcharset")  == 0) {
+               if (val == NULL || val[0] == 0)
+                       archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+                           "%s: hdrcharset option needs a character-set name",
+                           a->format_name);
+               else {
+                       cpio->opt_sconv = archive_string_conversion_to_charset(
+                           &a->archive, val, 0);
+                       if (cpio->opt_sconv != NULL)
+                               ret = ARCHIVE_OK;
+                       else
+                               ret = ARCHIVE_FATAL;
+               }
+               return (ret);
+       }
+
+       /* Note: The "warn" return is just to inform the options
+        * supervisor that we didn't handle it.  It will generate
+        * a suitable error if no one used this option. */
+       return (ARCHIVE_WARN);
+}
+
+/*
+ * Ino values are as long as 64 bits on some systems; cpio format
+ * only allows 18 bits and relies on the ino values to identify hardlinked
+ * files.  So, we can't merely "hash" the ino numbers since collisions
+ * would corrupt the archive.  Instead, we generate synthetic ino values
+ * to store in the archive and maintain a map of original ino values to
+ * synthetic ones so we can preserve hardlink information.
+ *
+ * TODO: Make this more efficient.  It's not as bad as it looks (most
+ * files don't have any hardlinks and we don't do any work here for those),
+ * but it wouldn't be hard to do better.
+ *
+ * TODO: Work with dev/ino pairs here instead of just ino values.
+ */
+static int
+synthesize_ino_value(struct cpio *cpio, struct archive_entry *entry)
+{
+       int64_t ino = archive_entry_ino64(entry);
+       int ino_new;
+       size_t i;
+
+       /*
+        * If no index number was given, don't assign one.  In
+        * particular, this handles the end-of-archive marker
+        * correctly by giving it a zero index value.  (This is also
+        * why we start our synthetic index numbers with one below.)
+        */
+       if (ino == 0)
+               return (0);
+
+       /* Don't store a mapping if we don't need to. */
+       if (archive_entry_nlink(entry) < 2) {
+               return (int)(++cpio->ino_next);
+       }
+
+       /* Look up old ino; if we have it, this is a hardlink
+        * and we reuse the same value. */
+       for (i = 0; i < cpio->ino_list_next; ++i) {
+               if (cpio->ino_list[i].old == ino)
+                       return (cpio->ino_list[i].new);
+       }
+
+       /* Assign a new index number. */
+       ino_new = (int)(++cpio->ino_next);
+
+       /* Ensure space for the new mapping. */
+       if (cpio->ino_list_size <= cpio->ino_list_next) {
+               size_t newsize = cpio->ino_list_size < 512
+                   ? 512 : cpio->ino_list_size * 2;
+               void *newlist = realloc(cpio->ino_list,
+                   sizeof(cpio->ino_list[0]) * newsize);
+               if (newlist == NULL)
+                       return (-1);
+
+               cpio->ino_list_size = newsize;
+               cpio->ino_list = newlist;
+       }
+
+       /* Record and return the new value. */
+       cpio->ino_list[cpio->ino_list_next].old = ino;
+       cpio->ino_list[cpio->ino_list_next].new = ino_new;
+       ++cpio->ino_list_next;
+       return (ino_new);
+}
+
+
+static struct archive_string_conv *
+get_sconv(struct archive_write *a)
+{
+       struct cpio *cpio;
+       struct archive_string_conv *sconv;
+
+       cpio = (struct cpio *)a->format_data;
+       sconv = cpio->opt_sconv;
+       if (sconv == NULL) {
+               if (!cpio->init_default_conversion) {
+                       cpio->sconv_default =
+                           archive_string_default_conversion_for_write(
+                             &(a->archive));
+                       cpio->init_default_conversion = 1;
+               }
+               sconv = cpio->sconv_default;
+       }
+       return (sconv);
+}
+
+static int
+archive_write_odc_header(struct archive_write *a, struct archive_entry *entry)
+{
+       const char *path;
+       size_t len;
+
+       if (archive_entry_filetype(entry) == 0 && archive_entry_hardlink(entry) == NULL) {
+               archive_set_error(&a->archive, -1, "Filetype required");
+               return (ARCHIVE_FAILED);
+       }
+
+       if (archive_entry_pathname_l(entry, &path, &len, get_sconv(a)) != 0
+           && errno == ENOMEM) {
+               archive_set_error(&a->archive, ENOMEM,
+                   "Can't allocate memory for Pathname");
+               return (ARCHIVE_FATAL);
+       }
+       if (len == 0 || path == NULL || path[0] == '\0') {
+               archive_set_error(&a->archive, -1, "Pathname required");
+               return (ARCHIVE_FAILED);
+       }
+
+       if (!archive_entry_size_is_set(entry) || archive_entry_size(entry) < 0) {
+               archive_set_error(&a->archive, -1, "Size required");
+               return (ARCHIVE_FAILED);
+       }
+       return write_header(a, entry);
+}
+
+static int
+write_header(struct archive_write *a, struct archive_entry *entry)
+{
+       struct cpio *cpio;
+       const char *p, *path;
+       int pathlength, ret, ret_final;
+       int64_t ino;
+       char h[76];
+       struct archive_string_conv *sconv;
+       struct archive_entry *entry_main;
+       size_t len;
+
+       cpio = (struct cpio *)a->format_data;
+       ret_final = ARCHIVE_OK;
+       sconv = get_sconv(a);
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+       /* Make sure the path separators in pathname, hardlink and symlink
+        * are all slash '/', not the Windows path separator '\'. */
+       entry_main = __la_win_entry_in_posix_pathseparator(entry);
+       if (entry_main == NULL) {
+               archive_set_error(&a->archive, ENOMEM,
+                   "Can't allocate ustar data");
+               return(ARCHIVE_FATAL);
+       }
+       if (entry != entry_main)
+               entry = entry_main;
+       else
+               entry_main = NULL;
+#else
+       entry_main = NULL;
+#endif
+
+       ret = archive_entry_pathname_l(entry, &path, &len, sconv);
+       if (ret != 0) {
+               if (errno == ENOMEM) {
+                       archive_set_error(&a->archive, ENOMEM,
+                           "Can't allocate memory for Pathname");
+                       ret_final = ARCHIVE_FATAL;
+                       goto exit_write_header;
+               }
+               archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+                   "Can't translate pathname '%s' to %s",
+                   archive_entry_pathname(entry),
+                   archive_string_conversion_charset_name(sconv));
+               ret_final = ARCHIVE_WARN;
+       }
+       /* Include trailing null. */
+       pathlength = (int)len + 1;
+
+       memset(h, 0, sizeof(h));
+       format_octal(070707, h + c_magic_offset, c_magic_size);
+       format_octal(archive_entry_dev(entry), h + c_dev_offset, c_dev_size);
+
+       ino = synthesize_ino_value(cpio, entry);
+       if (ino < 0) {
+               archive_set_error(&a->archive, ENOMEM,
+                   "No memory for ino translation table");
+               ret_final = ARCHIVE_FATAL;
+               goto exit_write_header;
+       } else if (ino > 0777777) {
+               archive_set_error(&a->archive, ERANGE,
+                   "Too many files for this cpio format");
+               ret_final = ARCHIVE_FATAL;
+               goto exit_write_header;
+       }
+       format_octal(ino & 0777777, h + c_ino_offset, c_ino_size);
+
+       /* TODO: Set ret_final to ARCHIVE_WARN if any of these overflow. */
+       format_octal(archive_entry_mode(entry), h + c_mode_offset, c_mode_size);
+       format_octal(archive_entry_uid(entry), h + c_uid_offset, c_uid_size);
+       format_octal(archive_entry_gid(entry), h + c_gid_offset, c_gid_size);
+       format_octal(archive_entry_nlink(entry), h + c_nlink_offset, c_nlink_size);
+       if (archive_entry_filetype(entry) == AE_IFBLK
+           || archive_entry_filetype(entry) == AE_IFCHR)
+           format_octal(archive_entry_rdev(entry), h + c_rdev_offset, c_rdev_size);
+       else
+           format_octal(0, h + c_rdev_offset, c_rdev_size);
+       format_octal(archive_entry_mtime(entry), h + c_mtime_offset, c_mtime_size);
+       format_octal(pathlength, h + c_namesize_offset, c_namesize_size);
+
+       /* Non-regular files don't store bodies. */
+       if (archive_entry_filetype(entry) != AE_IFREG)
+               archive_entry_set_size(entry, 0);
+
+       /* Symlinks get the link written as the body of the entry. */
+       ret = archive_entry_symlink_l(entry, &p, &len, sconv);
+       if (ret != 0) {
+               if (errno == ENOMEM) {
+                       archive_set_error(&a->archive, ENOMEM,
+                           "Can't allocate memory for Linkname");
+                       ret_final = ARCHIVE_FATAL;
+                       goto exit_write_header;
+               }
+               archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+                   "Can't translate linkname '%s' to %s",
+                   archive_entry_symlink(entry),
+                   archive_string_conversion_charset_name(sconv));
+               ret_final = ARCHIVE_WARN;
+       }
+       if (len > 0 && p != NULL  &&  *p != '\0')
+               ret = format_octal(strlen(p), h + c_filesize_offset,
+                   c_filesize_size);
+       else
+               ret = format_octal(archive_entry_size(entry),
+                   h + c_filesize_offset, c_filesize_size);
+       if (ret) {
+               archive_set_error(&a->archive, ERANGE,
+                   "File is too large for cpio format.");
+               ret_final = ARCHIVE_FAILED;
+               goto exit_write_header;
+       }
+
+       ret = __archive_write_output(a, h, sizeof(h));
+       if (ret != ARCHIVE_OK) {
+               ret_final = ARCHIVE_FATAL;
+               goto exit_write_header;
+       }
+
+       ret = __archive_write_output(a, path, pathlength);
+       if (ret != ARCHIVE_OK) {
+               ret_final = ARCHIVE_FATAL;
+               goto exit_write_header;
+       }
+
+       cpio->entry_bytes_remaining = archive_entry_size(entry);
+
+       /* Write the symlink now. */
+       if (p != NULL  &&  *p != '\0') {
+               ret = __archive_write_output(a, p, strlen(p));
+               if (ret != ARCHIVE_OK) {
+                       ret_final = ARCHIVE_FATAL;
+                       goto exit_write_header;
+               }
+       }
+exit_write_header:
+       archive_entry_free(entry_main);
+       return (ret_final);
+}
+
+static ssize_t
+archive_write_odc_data(struct archive_write *a, const void *buff, size_t s)
+{
+       struct cpio *cpio;
+       int ret;
+
+       cpio = (struct cpio *)a->format_data;
+       if (s > cpio->entry_bytes_remaining)
+               s = (size_t)cpio->entry_bytes_remaining;
+
+       ret = __archive_write_output(a, buff, s);
+       cpio->entry_bytes_remaining -= s;
+       if (ret >= 0)
+               return (s);
+       else
+               return (ret);
+}
+
+/*
+ * Format a number into the specified field.
+ */
+static int
+format_octal(int64_t v, void *p, int digits)
+{
+       int64_t max;
+       int     ret;
+
+       max = (((int64_t)1) << (digits * 3)) - 1;
+       if (v >= 0  &&  v <= max) {
+           format_octal_recursive(v, (char *)p, digits);
+           ret = 0;
+       } else {
+           format_octal_recursive(max, (char *)p, digits);
+           ret = -1;
+       }
+       return (ret);
+}
+
+static int64_t
+format_octal_recursive(int64_t v, char *p, int s)
+{
+       if (s == 0)
+               return (v);
+       v = format_octal_recursive(v, p+1, s-1);
+       *p = '0' + ((char)v & 7);
+       return (v >> 3);
+}
+
+static int
+archive_write_odc_close(struct archive_write *a)
+{
+       int er;
+       struct archive_entry *trailer;
+
+       trailer = archive_entry_new2(NULL);
+       /* nlink = 1 here for GNU cpio compat. */
+       archive_entry_set_nlink(trailer, 1);
+       archive_entry_set_size(trailer, 0);
+       archive_entry_set_pathname(trailer, "TRAILER!!!");
+       er = write_header(a, trailer);
+       archive_entry_free(trailer);
+       return (er);
+}
+
+static int
+archive_write_odc_free(struct archive_write *a)
+{
+       struct cpio *cpio;
+
+       cpio = (struct cpio *)a->format_data;
+       free(cpio->ino_list);
+       free(cpio);
+       a->format_data = NULL;
+       return (ARCHIVE_OK);
+}
+
+static int
+archive_write_odc_finish_entry(struct archive_write *a)
+{
+       struct cpio *cpio;
+
+       cpio = (struct cpio *)a->format_data;
+       return (__archive_write_nulls(a,
+               (size_t)cpio->entry_bytes_remaining));
+}
index d4a52e3..dd57358 100644 (file)
@@ -279,7 +279,7 @@ Values between 0 and 9 are supported.
 The interpretation of the compression level depends on the chosen
 compression method.
 .El
-.It Format cpio
+.It Format bin
 .Bl -tag -compact -width indent
 .It Cm hdrcharset
 The value is used as a character set name that will be
@@ -519,6 +519,18 @@ XXX needs explanation XXX
 The value is used as a character set name that will be
 used when translating file names.
 .El
+.It Format odc
+.Bl -tag -compact -width indent
+.It Cm hdrcharset
+The value is used as a character set name that will be
+used when translating file names.
+.El
+.It Format pwb
+.Bl -tag -compact -width indent
+.It Cm hdrcharset
+The value is used as a character set name that will be
+used when translating file names.
+.El
 .It Format pax
 .Bl -tag -compact -width indent
 .It Cm hdrcharset
index a484618..ac651f0 100644 (file)
 #define HAVE_LIBZ 1
 #define HAVE_LIMITS_H 1
 #define HAVE_LINK 1
+#define HAVE_LINKAT 1
 #define HAVE_LOCALE_H 1
 #define HAVE_LOCALTIME_R 1
 #define HAVE_LONG_LONG_INT 1
index a91f0c5..837a456 100644 (file)
@@ -56,40 +56,44 @@ The end of the archive is indicated by a special record with
 the pathname
 .Dq TRAILER!!! .
 .Ss PWB format
-XXX Any documentation of the original PWB/UNIX 1.0 format? XXX
-.Ss Old Binary Format
-The old binary
+The PWB binary
 .Nm
-format stores numbers as 2-byte and 4-byte binary values.
+format is the original format, when cpio was introduced as part of the
+Programmer's Work Bench system, a variant of 6th Edition UNIX.  It
+stores numbers as 2-byte and 4-byte binary values.
 Each entry begins with a header in the following format:
+.Pp
 .Bd -literal -offset indent
-struct header_old_cpio {
-        unsigned short   c_magic;
-        unsigned short   c_dev;
-        unsigned short   c_ino;
-        unsigned short   c_mode;
-        unsigned short   c_uid;
-        unsigned short   c_gid;
-        unsigned short   c_nlink;
-        unsigned short   c_rdev;
-       unsigned short   c_mtime[2];
-        unsigned short   c_namesize;
-       unsigned short   c_filesize[2];
+struct header_pwb_cpio {
+        short   h_magic;
+        short   h_dev;
+        short   h_ino;
+        short   h_mode;
+        short   h_uid;
+        short   h_gid;
+        short   h_nlink;
+        short   h_majmin;
+        long    h_mtime;
+        short   h_namesize;
+        long    h_filesize;
 };
 .Ed
 .Pp
 The
-.Va unsigned short
-fields here are 16-bit integer values; the
-.Va unsigned int
-fields are 32-bit integer values.
-The fields are as follows
+.Va short
+fields here are 16-bit integer values, while the
+.Va long
+fields are 32 bit integers.  Since PWB UNIX, like the 6th Edition UNIX
+it was based on, only ran on PDP-11 computers, they
+are in PDP-endian format, which has little-endian shorts, and
+big-endian longs.  That is, the long integer whose hexadecimal
+representation is 0x12345678 would be stored in four successive bytes
+as 0x34, 0x12, 0x78, 0x56.
+The fields are as follows:
 .Bl -tag -width indent
-.It Va magic
+.It Va h_magic
 The integer value octal 070707.
-This value can be used to determine whether this archive is
-written with little-endian or big-endian integers.
-.It Va dev , Va ino
+.It Va h_dev , Va h_ino
 The device and inode numbers from the disk.
 These are used by programs that read
 .Nm
@@ -97,78 +101,138 @@ archives to determine when two entries refer to the same file.
 Programs that synthesize
 .Nm
 archives should be careful to set these to distinct values for each entry.
-.It Va mode
-The mode specifies both the regular permissions and the file type.
-It consists of several bit fields as follows:
+.It Va h_mode
+The mode specifies both the regular permissions and the file type, and
+it also holds a couple of bits that are irrelevant to the cpio format,
+because the field is actually a raw copy of the mode field in the inode
+representing the file.  These are the IALLOC flag, which shows that
+the inode entry is in use, and the ILARG flag, which shows that the
+file it represents is large enough to have indirect blocks pointers in
+the inode.
+The mode is decoded as follows:
+.Pp
 .Bl -tag -width "MMMMMMM" -compact
-.It 0170000
-This masks the file type bits.
-.It 0140000
-File type value for sockets.
-.It 0120000
-File type value for symbolic links.
-For symbolic links, the link body is stored as file data.
 .It 0100000
-File type value for regular files.
+IALLOC flag - irrelevant to cpio.
 .It 0060000
-File type value for block special devices.
+This masks the file type bits.
 .It 0040000
 File type value for directories.
 .It 0020000
 File type value for character special devices.
+.It 0060000
+File type value for block special devices.
 .It 0010000
-File type value for named pipes or FIFOs.
+ILARG flag - irrelevant to cpio.
 .It 0004000
 SUID bit.
 .It 0002000
 SGID bit.
 .It 0001000
 Sticky bit.
-On some systems, this modifies the behavior of executables and/or directories.
 .It 0000777
 The lower 9 bits specify read/write/execute permissions
 for world, group, and user following standard POSIX conventions.
 .El
-.It Va uid , Va gid
+.It Va h_uid , Va h_gid
 The numeric user id and group id of the owner.
-.It Va nlink
+.It Va h_nlink
 The number of links to this file.
 Directories always have a value of at least two here.
 Note that hardlinked files include file data with every copy in the archive.
-.It Va rdev
+.It Va h_majmin
 For block special and character special entries,
-this field contains the associated device number.
+this field contains the associated device number, with the major
+number in the high byte, and the minor number in the low byte.
 For all other entry types, it should be set to zero by writers
 and ignored by readers.
-.It Va mtime
+.It Va h_mtime
 Modification time of the file, indicated as the number
 of seconds since the start of the epoch,
 00:00:00 UTC January 1, 1970.
-The four-byte integer is stored with the most-significant 16 bits first
-followed by the least-significant 16 bits.
-Each of the two 16 bit values are stored in machine-native byte order.
-.It Va namesize
+.It Va h_namesize
 The number of bytes in the pathname that follows the header.
 This count includes the trailing NUL byte.
-.It Va filesize
-The size of the file.
-Note that this archive format is limited to
-four gigabyte file sizes.
-See
-.Va mtime
-above for a description of the storage of four-byte integers.
+.It Va h_filesize
+The size of the file.  Note that this archive format is limited to 16
+megabyte file sizes, because PWB UNIX, like 6th Edition, only used
+an unsigned 24 bit integer for the file size internally.
 .El
 .Pp
 The pathname immediately follows the fixed header.
-If the
-.Cm namesize
+If
+.Cm h_namesize
 is odd, an additional NUL byte is added after the pathname.
-The file data is then appended, padded with NUL
-bytes to an even length.
+The file data is then appended, again with an additional NUL
+appended if needed to get the next header at an even offset.
 .Pp
 Hardlinked files are not given special treatment;
 the full file contents are included with each copy of the
 file.
+.Ss New Binary Format
+The new binary
+.Nm
+format showed up when cpio was adopted into late 7th Edition UNIX.
+It is exactly like the PWB binary format, described above, except for
+three changes:
+.Pp
+First, UNIX now ran on more than one hardware type, so the endianness
+of 16 bit integers must be determined by observing the magic number at
+the start of the header.  The 32 bit integers are still always stored
+with the most significant word first, though, so each of those two, in
+the struct shown above, was stored as an array of two 16 bit integers,
+in the traditional order.  Those 16 bit integers, like all the others
+in the struct, were accessed using a macro that byte swapped them if
+necessary.
+.Pp
+Next, 7th Edition had more file types to store, and the IALLOC and ILARG
+flag bits were re-purposed to accommodate these.  The revised use of the
+various bits is as follows:
+.Pp
+.Bl -tag -width "MMMMMMM" -compact
+.It 0170000
+This masks the file type bits.
+.It 0140000
+File type value for sockets.
+.It 0120000
+File type value for symbolic links.
+For symbolic links, the link body is stored as file data.
+.It 0100000
+File type value for regular files.
+.It 0060000
+File type value for block special devices.
+.It 0040000
+File type value for directories.
+.It 0020000
+File type value for character special devices.
+.It 0010000
+File type value for named pipes or FIFOs.
+.It 0004000
+SUID bit.
+.It 0002000
+SGID bit.
+.It 0001000
+Sticky bit.
+.It 0000777
+The lower 9 bits specify read/write/execute permissions
+for world, group, and user following standard POSIX conventions.
+.El
+.Pp
+Finally, the file size field now represents a signed 32 bit integer in
+the underlying file system, so the maximum file size has increased to
+2 gigabytes.
+.Pp
+Note that there is no obvious way to tell which of the two binary
+formats an archive uses, other than to see which one makes more
+sense.  The typical error scenario is that a PWB format archive
+unpacked as if it were in the new format will create named sockets
+instead of directories, and then fail to unpack files that should
+go in those directories.  Running
+.Va bsdcpio -itv
+on an unknown archive will make it obvious which it is: if it's
+PWB format, directories will be listed with an 's' instead of
+a 'd' as the first character of the mode string, and the larger
+files will have a '?' in that position.
 .Ss Portable ASCII Format
 .St -susv2
 standardized an ASCII variant that is portable across all
@@ -180,6 +244,7 @@ format or as the
 format.
 It stores the same numeric fields as the old binary format, but
 represents them as 6-character or 11-character octal values.
+.Pp
 .Bd -literal -offset indent
 struct cpio_odc_header {
         char    c_magic[6];
@@ -196,9 +261,9 @@ struct cpio_odc_header {
 };
 .Ed
 .Pp
-The fields are identical to those in the old binary format.
+The fields are identical to those in the new binary format.
 The name and file body follow the fixed header.
-Unlike the old binary format, there is no additional padding
+Unlike the binary formats, there is no additional padding
 after the pathname or file contents.
 If the files being archived are themselves entirely ASCII, then
 the resulting archive will be entirely ASCII, except for the
@@ -207,6 +272,7 @@ NUL byte that terminates the name field.
 The "new" ASCII format uses 8-byte hexadecimal fields for
 all numbers and separates device numbers into separate fields
 for major and minor numbers.
+.Pp
 .Bd -literal -offset indent
 struct cpio_newc_header {
         char    c_magic[6];
@@ -227,7 +293,7 @@ struct cpio_newc_header {
 .Ed
 .Pp
 Except as specified below, the fields here match those specified
-for the old binary format above.
+for the new binary format above.
 .Bl -tag -width indent
 .It Va magic
 The string
@@ -288,9 +354,9 @@ while working in AT&T's Unix Support Group.
 It appeared in 1977 as part of PWB/UNIX 1.0, the
 .Dq Programmer's Work Bench
 derived from
-.At v6
+.At 6th Edition UNIX
 that was used internally at AT&T.
-Both the old binary and old character formats were in use
+Both the new binary and old character formats were in use
 by 1980, according to the System III source released
 by SCO under their
 .Dq Ancient Unix
@@ -304,9 +370,9 @@ The
 format is mis-named, as it uses a simple checksum and
 not a cyclic redundancy check.
 .Pp
-The old binary format is limited to 16 bits for user id,
-group id, device, and inode numbers.
-It is limited to 4 gigabyte file sizes.
+The binary formats are limited to 16 bits for user id, group id,
+device, and inode numbers.  They are limited to 16 megabyte and 2
+gigabyte file sizes for the older and newer variants, respectively.
 .Pp
 The old ASCII format is limited to 18 bits for
 the user id, group id, device, and inode numbers.
index 62359dd..5a118ff 100644 (file)
@@ -201,28 +201,27 @@ POSIX.1-2001 extended the ustar format to create the
 .Dq pax interchange
 format.
 .Ss Cpio Formats
-The libarchive library can read a number of common cpio variants and can write
-.Dq odc
-and
-.Dq newc
-format archives.
-A cpio archive stores each entry as a fixed-size header followed
-by a variable-length filename and variable-length data.
-Unlike the tar format, the cpio format does only minimal padding
-of the header or file data.
-There are several cpio variants, which differ primarily in
-how they store the initial header: some store the values as
-octal or hexadecimal numbers in ASCII, others as binary values of
-varying byte order and length.
+The libarchive library can read and write a number of common cpio
+variants.  A cpio archive stores each entry as a fixed-size header
+followed by a variable-length filename and variable-length data.
+Unlike the tar format, the cpio format does only minimal padding of
+the header or file data.  There are several cpio variants, which
+differ primarily in how they store the initial header: some store the
+values as octal or hexadecimal numbers in ASCII, others as binary
+values of varying byte order and length.
 .Bl -tag -width indent
 .It Cm binary
-The libarchive library transparently reads both big-endian and little-endian
-variants of the original binary cpio format.
-This format used 32-bit binary values for file size and mtime,
-and 16-bit binary values for the other fields.
+The libarchive library transparently reads both big-endian and
+little-endian variants of the the two binary cpio formats; the
+original one from PWB/UNIX, and the later, more widely used, variant.
+This format used 32-bit binary values for file size and mtime, and
+16-bit binary values for the other fields.  The formats support only
+the file types present in UNIX at the time of their creation.  File
+sizes are limited to 24 bits in the PWB format, because of the limits
+of the file system, and to 31 bits in the newer binary format, where
+signed 32 bit longs were used.
 .It Cm odc
-The libarchive library can both read and write this
-POSIX-standard format, which is officially known as the
+This is the POSIX standardized format, which is officially known as the
 .Dq cpio interchange format
 or the
 .Dq octet-oriented cpio archive format
index c6894d2..1ef4b7c 100644 (file)
@@ -105,7 +105,7 @@ POSIX
 .Dq pax interchange format
 archives,
 .It
-POSIX octet-oriented cpio archives,
+cpio archives,
 .It
 Zip archive,
 .It
index 70750ba..f96e9d9 100644 (file)
@@ -150,7 +150,11 @@ typedef struct _U32_S { U32 v; } _PACKED U32_S;
 #if GCC_VERSION >= 409
 __attribute__((__no_sanitize_undefined__))
 #endif
-static inline U32 A32(const void * x)
+#if defined(_MSC_VER)
+static __inline U32 A32(const void * x)
+#else
+static inline U32 A32(const void* x)
+#endif
 {
     return (((const U32_S *)(x))->v);
 }