diff options
207 files changed, 5013 insertions, 2478 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index b0793d0..5e4cd15 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -321,6 +321,12 @@ macro (CMAKE_BUILD_UTILITIES) add_definitions(-DLIBARCHIVE_STATIC) set(ENABLE_NETTLE OFF CACHE INTERNAL "Enable use of Nettle") set(ENABLE_OPENSSL ${CMAKE_USE_OPENSSL} CACHE INTERNAL "Enable use of OpenSSL") + set(ENABLE_LZMA OFF CACHE INTERNAL "Enable the use of the system found LZMA library if found") + set(ENABLE_ZLIB ON CACHE INTERNAL "Enable the use of the system found ZLIB library if found") + set(ENABLE_BZip2 ON CACHE INTERNAL "Enable the use of the system found BZip2 library if found") + set(ENABLE_EXPAT OFF CACHE INTERNAL "Enable the use of the system found EXPAT library if found") + set(ENABLE_PCREPOSIX OFF CACHE INTERNAL "Enable the use of the system found PCREPOSIX library if found") + set(ENABLE_LibGCC OFF CACHE INTERNAL "Enable the use of the system found LibGCC library if found") set(ENABLE_XATTR OFF CACHE INTERNAL "Enable extended attribute support") set(ENABLE_ACL OFF CACHE INTERNAL "Enable ACL support") set(ENABLE_ICONV OFF CACHE INTERNAL "Enable iconv support") diff --git a/CTestCustom.cmake.in b/CTestCustom.cmake.in index 3c589b4..f499be1 100644 --- a/CTestCustom.cmake.in +++ b/CTestCustom.cmake.in @@ -19,6 +19,7 @@ set(CTEST_CUSTOM_WARNING_EXCEPTION "Utilities.cmbzip2." "Source.CTest.Curl" "Source.CursesDialog.form" + "Source.cm_sha2.*warning.*cast increases required alignment of target type" "Utilities.cmcurl" "Utilities.cmexpat." "Utilities.cmlibarchive" @@ -55,6 +56,8 @@ set(CTEST_CUSTOM_WARNING_EXCEPTION "warning.*This version of Mac OS X is unsupported" "clang.*: warning: argument unused during compilation: .-g" "note: in expansion of macro" # diagnostic context note + "cm(StringCommand|CTestTestHandler)\\.cxx.*warning.*rand.*isn.*t random" # we do not do crypto + "cm(StringCommand|CTestTestHandler)\\.cxx.*warning.*srand.*seed choices are.*poor" # we do not do crypto # Ignore clang's summary warning, assuming prior text has matched some # other warning expression: diff --git a/CompileFlags.cmake b/CompileFlags.cmake index 873af8f..a4a4a78 100644 --- a/CompileFlags.cmake +++ b/CompileFlags.cmake @@ -34,28 +34,32 @@ else() endif() #silence duplicate symbol warnings on AIX -if(CMAKE_SYSTEM MATCHES "AIX.*") +if(CMAKE_SYSTEM_NAME MATCHES "AIX") if(NOT CMAKE_COMPILER_IS_GNUCXX) set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -bhalt:5 ") endif() endif() -if(CMAKE_SYSTEM MATCHES "IRIX.*") +if(CMAKE_SYSTEM_NAME MATCHES "IRIX") if(NOT CMAKE_COMPILER_IS_GNUCXX) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wl,-woff84 -no_auto_include") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-woff15") endif() endif() -if(CMAKE_SYSTEM MATCHES "OSF1-V.*") +if(CMAKE_SYSTEM MATCHES "OSF1-V") if(NOT CMAKE_COMPILER_IS_GNUCXX) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -timplicit_local -no_implicit_include ") endif() endif() if(CMAKE_SYSTEM_NAME MATCHES "HP-UX" AND CMAKE_CXX_COMPILER_ID MATCHES "HP") - # it is known that version 3.85 fails and 6.25 works without these flags - if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4) + # HP aCC since version 3.80 supports the flag +hpxstd98 to get ANSI C++98 + # template support. It is known that version 6.25 doesn't need that flag. + # Versions prior to 3.80 will not be able to build CMake. Current assumption: + # it is needed for every version from 3.80 to 4 to get it working. + if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4 AND + NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.80) # use new C++ library and improved template support set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -AA +hpxstd98") endif() diff --git a/Help/manual/cmake-policies.7.rst b/Help/manual/cmake-policies.7.rst index b763882..4b895fe 100644 --- a/Help/manual/cmake-policies.7.rst +++ b/Help/manual/cmake-policies.7.rst @@ -103,3 +103,4 @@ All Policies /policy/CMP0049 /policy/CMP0050 /policy/CMP0051 + /policy/CMP0052 diff --git a/Help/policy/CMP0051.rst b/Help/policy/CMP0051.rst index 7d85929..1b56cb0 100644 --- a/Help/policy/CMP0051.rst +++ b/Help/policy/CMP0051.rst @@ -10,7 +10,7 @@ returning the :prop_tgt:`SOURCES` target property. Configure-time CMake code is not able to handle generator expressions. If using the :prop_tgt:`SOURCES` target property at configure time, it may be necessary to first remove generator expressions using the -:command:`string(STRIP_GENEX)` command. Generate-time CMake code such as +:command:`string(GENEX_STRIP)` command. Generate-time CMake code such as :command:`file(GENERATE)` can handle the content without stripping. The ``OLD`` behavior for this policy is to omit ``TARGET_OBJECTS`` diff --git a/Help/policy/CMP0052.rst b/Help/policy/CMP0052.rst new file mode 100644 index 0000000..f857f36 --- /dev/null +++ b/Help/policy/CMP0052.rst @@ -0,0 +1,21 @@ +CMP0052 +------- + +Reject source and build dirs in installed INTERFACE_INCLUDE_DIRECTORIES. + +CMake 3.0 and lower allowed subdirectories of the source directory or build +directory to be in the :prop_tgt:`INTERFACE_INCLUDE_DIRECTORIES` of +installed and exported targets, if the directory was also a subdirectory of +the installation prefix. This makes the installation depend on the +existence of the source dir or binary dir, and the installation will be +broken if either are removed after installation. + +The OLD behavior for this policy is to export the content of the +:prop_tgt:`INTERFACE_INCLUDE_DIRECTORIES` with the source or binary +directory. The NEW behavior for this +policy is to issue an error if such a directory is used. + +This policy was introduced in CMake version 3.1. +CMake version |release| warns when the policy is not set and uses +``OLD`` behavior. Use the :command:`cmake_policy` command to set it +to ``OLD`` or ``NEW`` explicitly. diff --git a/Help/release/dev/CMP0052.rst b/Help/release/dev/CMP0052.rst new file mode 100644 index 0000000..adb3d44 --- /dev/null +++ b/Help/release/dev/CMP0052.rst @@ -0,0 +1,5 @@ +CMP0052 +------- + +* Policy :policy:`CMP0052` introduced to control directories in the + :prop_tgt:`INTERFACE_INCLUDE_DIRECTORIES` of exported targets. diff --git a/Help/release/dev/CMakeDetermineVSServicePack.rst b/Help/release/dev/CMakeDetermineVSServicePack.rst new file mode 100644 index 0000000..d9d7b41 --- /dev/null +++ b/Help/release/dev/CMakeDetermineVSServicePack.rst @@ -0,0 +1,6 @@ +CMakeDetermineVSServicePack +--------------------------- + +* The :module:`CMakeDetermineVSServicePack` module now warns that + it is deprecated and should not longer be used. Use the + :variable:`CMAKE_<LANG>_COMPILER_VERSION` variable instead. diff --git a/Modules/BasicConfigVersion-ExactVersion.cmake.in b/Modules/BasicConfigVersion-ExactVersion.cmake.in index 63f3f03..9fd0136 100644 --- a/Modules/BasicConfigVersion-ExactVersion.cmake.in +++ b/Modules/BasicConfigVersion-ExactVersion.cmake.in @@ -11,13 +11,13 @@ set(PACKAGE_VERSION "@CVF_VERSION@") -if("@CVF_VERSION@" MATCHES "^([0-9]+\\.[0-9]+\\.[0-9]+)\\..*") # strip the tweak version +if("@CVF_VERSION@" MATCHES "^([0-9]+\\.[0-9]+\\.[0-9]+)\\.") # strip the tweak version set(CVF_VERSION_NO_TWEAK "${CMAKE_MATCH_1}") else() set(CVF_VERSION_NO_TWEAK "@CVF_VERSION@") endif() -if("${PACKAGE_FIND_VERSION}" MATCHES "^([0-9]+\\.[0-9]+\\.[0-9]+)\\..*") # strip the tweak version +if("${PACKAGE_FIND_VERSION}" MATCHES "^([0-9]+\\.[0-9]+\\.[0-9]+)\\.") # strip the tweak version set(REQUESTED_VERSION_NO_TWEAK "${CMAKE_MATCH_1}") else() set(REQUESTED_VERSION_NO_TWEAK "${PACKAGE_FIND_VERSION}") diff --git a/Modules/BundleUtilities.cmake b/Modules/BundleUtilities.cmake index b896de2..0c733fa 100644 --- a/Modules/BundleUtilities.cmake +++ b/Modules/BundleUtilities.cmake @@ -235,8 +235,8 @@ function(get_bundle_main_executable bundle result_var) # set(eol_char "E") file(READ "${bundle}/Contents/Info.plist" info_plist) - string(REGEX REPLACE ";" "\\\\;" info_plist "${info_plist}") - string(REGEX REPLACE "\n" "${eol_char};" info_plist "${info_plist}") + string(REPLACE ";" "\\;" info_plist "${info_plist}") + string(REPLACE "\n" "${eol_char};" info_plist "${info_plist}") # Scan the lines for "<key>CFBundleExecutable</key>" - the line after that # is the name of the main executable. @@ -247,7 +247,7 @@ function(get_bundle_main_executable bundle result_var) break() endif() - if(line MATCHES "^.*<key>CFBundleExecutable</key>.*$") + if(line MATCHES "<key>CFBundleExecutable</key>") set(line_is_main_executable 1) endif() endforeach() @@ -287,7 +287,7 @@ endfunction() function(get_dotapp_dir exe dotapp_dir_var) set(s "${exe}") - if(s MATCHES "^.*/.*\\.app/.*$") + if(s MATCHES "/.*\\.app/") # If there is a ".app" parent directory, # ascend until we hit it: # (typical of a Mac bundle executable) @@ -394,7 +394,7 @@ function(get_item_key item key_var) if(WIN32) string(TOLOWER "${item_name}" item_name) endif() - string(REGEX REPLACE "\\." "_" ${key_var} "${item_name}") + string(REPLACE "." "_" ${key_var} "${item_name}") set(${key_var} ${${key_var}} PARENT_SCOPE) endfunction() diff --git a/Modules/CMakeBackwardCompatibilityCXX.cmake b/Modules/CMakeBackwardCompatibilityCXX.cmake index 343fdb2..f1db46e 100644 --- a/Modules/CMakeBackwardCompatibilityCXX.cmake +++ b/Modules/CMakeBackwardCompatibilityCXX.cmake @@ -31,15 +31,15 @@ if(NOT CMAKE_SKIP_COMPATIBILITY_TESTS) if(NOT CMAKE_COMPILER_IS_GNUCXX) include(TestCXXAcceptsFlag) set(CMAKE_TRY_ANSI_CXX_FLAGS "") - if(CMAKE_SYSTEM MATCHES "IRIX.*") + if(CMAKE_SYSTEM_NAME MATCHES "IRIX") set(CMAKE_TRY_ANSI_CXX_FLAGS "-LANG:std") endif() - if(CMAKE_SYSTEM MATCHES "OSF.*") + if(CMAKE_SYSTEM_NAME MATCHES "OSF") set(CMAKE_TRY_ANSI_CXX_FLAGS "-std strict_ansi -nopure_cname") endif() # if CMAKE_TRY_ANSI_CXX_FLAGS has something in it, see # if the compiler accepts it - if( CMAKE_TRY_ANSI_CXX_FLAGS MATCHES ".+") + if(NOT CMAKE_TRY_ANSI_CXX_FLAGS STREQUAL "") CHECK_CXX_ACCEPTS_FLAG(${CMAKE_TRY_ANSI_CXX_FLAGS} CMAKE_CXX_ACCEPTS_FLAGS) # if the compiler liked the flag then set CMAKE_ANSI_CXXFLAGS # to the flag diff --git a/Modules/CMakeDetermineASMCompiler.cmake b/Modules/CMakeDetermineASMCompiler.cmake index 1d9617f..25af3e3 100644 --- a/Modules/CMakeDetermineASMCompiler.cmake +++ b/Modules/CMakeDetermineASMCompiler.cmake @@ -18,7 +18,7 @@ include(${CMAKE_ROOT}/Modules/CMakeDetermineCompiler.cmake) if(NOT CMAKE_ASM${ASM_DIALECT}_COMPILER) # prefer the environment variable ASM - if($ENV{ASM${ASM_DIALECT}} MATCHES ".+") + if(NOT $ENV{ASM${ASM_DIALECT}} STREQUAL "") set(CMAKE_ASM${ASM_DIALECT}_COMPILER_INIT "$ENV{ASM${ASM_DIALECT}}") endif() diff --git a/Modules/CMakeDetermineCCompiler.cmake b/Modules/CMakeDetermineCCompiler.cmake index aa4cdc9..3847b75 100644 --- a/Modules/CMakeDetermineCCompiler.cmake +++ b/Modules/CMakeDetermineCCompiler.cmake @@ -48,7 +48,7 @@ else() set(CMAKE_C_COMPILER_INIT NOTFOUND) # prefer the environment variable CC - if($ENV{CC} MATCHES ".+") + if(NOT $ENV{CC} STREQUAL "") get_filename_component(CMAKE_C_COMPILER_INIT $ENV{CC} PROGRAM PROGRAM_ARGS CMAKE_C_FLAGS_ENV_INIT) if(CMAKE_C_FLAGS_ENV_INIT) set(CMAKE_C_COMPILER_ARG1 "${CMAKE_C_FLAGS_ENV_INIT}" CACHE STRING "First argument to C compiler") @@ -138,7 +138,7 @@ if (CMAKE_CROSSCOMPILING AND NOT _CMAKE_TOOLCHAIN_PREFIX) elseif("${CMAKE_C_COMPILER_ID}" MATCHES "Clang") set(_CMAKE_TOOLCHAIN_PREFIX ${CMAKE_C_COMPILER_TARGET}-) elseif(COMPILER_BASENAME MATCHES "qcc(\\.exe)?$") - if(CMAKE_C_COMPILER_TARGET MATCHES "gcc_nto([^_le]+)(le)?.*$") + if(CMAKE_C_COMPILER_TARGET MATCHES "gcc_nto([^_le]+)(le)?") set(_CMAKE_TOOLCHAIN_PREFIX nto${CMAKE_MATCH_1}-) endif() endif () diff --git a/Modules/CMakeDetermineCXXCompiler.cmake b/Modules/CMakeDetermineCXXCompiler.cmake index ef8445e..e6a9d9a 100644 --- a/Modules/CMakeDetermineCXXCompiler.cmake +++ b/Modules/CMakeDetermineCXXCompiler.cmake @@ -47,7 +47,7 @@ else() set(CMAKE_CXX_COMPILER_INIT NOTFOUND) # prefer the environment variable CXX - if($ENV{CXX} MATCHES ".+") + if(NOT $ENV{CXX} STREQUAL "") get_filename_component(CMAKE_CXX_COMPILER_INIT $ENV{CXX} PROGRAM PROGRAM_ARGS CMAKE_CXX_FLAGS_ENV_INIT) if(CMAKE_CXX_FLAGS_ENV_INIT) set(CMAKE_CXX_COMPILER_ARG1 "${CMAKE_CXX_FLAGS_ENV_INIT}" CACHE STRING "First argument to CXX compiler") @@ -135,7 +135,7 @@ if (CMAKE_CROSSCOMPILING AND NOT _CMAKE_TOOLCHAIN_PREFIX) elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") set(_CMAKE_TOOLCHAIN_PREFIX ${CMAKE_CXX_COMPILER_TARGET}-) elseif(COMPILER_BASENAME MATCHES "QCC(\\.exe)?$") - if(CMAKE_CXX_COMPILER_TARGET MATCHES "gcc_nto([^_le]+)(le)?.*$") + if(CMAKE_CXX_COMPILER_TARGET MATCHES "gcc_nto([^_le]+)(le)?") set(_CMAKE_TOOLCHAIN_PREFIX nto${CMAKE_MATCH_1}-) endif() endif () diff --git a/Modules/CMakeDetermineCompilerABI.cmake b/Modules/CMakeDetermineCompilerABI.cmake index 5d35ce3..8595b97 100644 --- a/Modules/CMakeDetermineCompilerABI.cmake +++ b/Modules/CMakeDetermineCompilerABI.cmake @@ -52,11 +52,11 @@ function(CMAKE_DETERMINE_COMPILER_ABI lang src) "Detecting ${lang} compiler ABI info compiled with the following output:\n${OUTPUT}\n\n") file(STRINGS "${BIN}" ABI_STRINGS LIMIT_COUNT 2 REGEX "INFO:[^[]*\\[") foreach(info ${ABI_STRINGS}) - if("${info}" MATCHES ".*INFO:sizeof_dptr\\[0*([^]]*)\\].*") - string(REGEX REPLACE ".*INFO:sizeof_dptr\\[0*([^]]*)\\].*" "\\1" ABI_SIZEOF_DPTR "${info}") + if("${info}" MATCHES "INFO:sizeof_dptr\\[0*([^]]*)\\]") + set(ABI_SIZEOF_DPTR "${CMAKE_MATCH_1}") endif() - if("${info}" MATCHES ".*INFO:abi\\[([^]]*)\\].*") - string(REGEX REPLACE ".*INFO:abi\\[([^]]*)\\].*" "\\1" ABI_NAME "${info}") + if("${info}" MATCHES "INFO:abi\\[([^]]*)\\]") + set(ABI_NAME "${CMAKE_MATCH_1}") endif() endforeach() diff --git a/Modules/CMakeDetermineCompilerId.cmake b/Modules/CMakeDetermineCompilerId.cmake index 067892d..f109dc4 100644 --- a/Modules/CMakeDetermineCompilerId.cmake +++ b/Modules/CMakeDetermineCompilerId.cmake @@ -27,7 +27,7 @@ function(CMAKE_DETERMINE_COMPILER_ID lang flagvar src) else() set(CMAKE_${lang}_COMPILER_ID_FLAGS $ENV{${flagvar}}) endif() - string(REGEX REPLACE " " ";" CMAKE_${lang}_COMPILER_ID_FLAGS_LIST "${CMAKE_${lang}_COMPILER_ID_FLAGS}") + string(REPLACE " " ";" CMAKE_${lang}_COMPILER_ID_FLAGS_LIST "${CMAKE_${lang}_COMPILER_ID_FLAGS}") # Compute the directory in which to run the test. set(CMAKE_${lang}_COMPILER_ID_DIR ${CMAKE_PLATFORM_INFO_DIR}/CompilerId${lang}) @@ -356,35 +356,30 @@ function(CMAKE_DETERMINE_COMPILER_ID_CHECK lang file) CMAKE_${lang}_COMPILER_ID_STRINGS LIMIT_COUNT 6 REGEX "INFO:") set(COMPILER_ID_TWICE) foreach(info ${CMAKE_${lang}_COMPILER_ID_STRINGS}) - if("${info}" MATCHES ".*INFO:compiler\\[([^]\"]*)\\].*") + if("${info}" MATCHES "INFO:compiler\\[([^]\"]*)\\]") if(COMPILER_ID) set(COMPILER_ID_TWICE 1) endif() - string(REGEX REPLACE ".*INFO:compiler\\[([^]]*)\\].*" "\\1" - COMPILER_ID "${info}") + set(COMPILER_ID "${CMAKE_MATCH_1}") endif() - if("${info}" MATCHES ".*INFO:platform\\[([^]\"]*)\\].*") - string(REGEX REPLACE ".*INFO:platform\\[([^]]*)\\].*" "\\1" - PLATFORM_ID "${info}") + if("${info}" MATCHES "INFO:platform\\[([^]\"]*)\\]") + set(PLATFORM_ID "${CMAKE_MATCH_1}") endif() - if("${info}" MATCHES ".*INFO:arch\\[([^]\"]*)\\].*") - string(REGEX REPLACE ".*INFO:arch\\[([^]]*)\\].*" "\\1" - ARCHITECTURE_ID "${info}") + if("${info}" MATCHES "INFO:arch\\[([^]\"]*)\\]") + set(ARCHITECTURE_ID "${CMAKE_MATCH_1}") endif() - if("${info}" MATCHES ".*INFO:compiler_version\\[([^]\"]*)\\].*") - string(REGEX REPLACE ".*INFO:compiler_version\\[([^]]*)\\].*" "\\1" COMPILER_VERSION "${info}") - string(REGEX REPLACE "^0+([0-9])" "\\1" COMPILER_VERSION "${COMPILER_VERSION}") + if("${info}" MATCHES "INFO:compiler_version\\[([^]\"]*)\\]") + string(REGEX REPLACE "^0+([0-9])" "\\1" COMPILER_VERSION "${CMAKE_MATCH_1}") string(REGEX REPLACE "\\.0+([0-9])" ".\\1" COMPILER_VERSION "${COMPILER_VERSION}") endif() - if("${info}" MATCHES ".*INFO:simulate\\[([^]\"]*)\\].*") + if("${info}" MATCHES "INFO:simulate\\[([^]\"]*)\\]") set(SIMULATE_ID "${CMAKE_MATCH_1}") endif() - if("${info}" MATCHES ".*INFO:simulate_version\\[([^]\"]*)\\].*") - set(SIMULATE_VERSION "${CMAKE_MATCH_1}") - string(REGEX REPLACE "^0+([0-9])" "\\1" SIMULATE_VERSION "${SIMULATE_VERSION}") + if("${info}" MATCHES "INFO:simulate_version\\[([^]\"]*)\\]") + string(REGEX REPLACE "^0+([0-9])" "\\1" SIMULATE_VERSION "${CMAKE_MATCH_1}") string(REGEX REPLACE "\\.0+([0-9])" ".\\1" SIMULATE_VERSION "${SIMULATE_VERSION}") endif() - if("${info}" MATCHES ".*INFO:qnxnto") + if("${info}" MATCHES "INFO:qnxnto") set(COMPILER_QNXNTO 1) endif() endforeach() diff --git a/Modules/CMakeDetermineFortranCompiler.cmake b/Modules/CMakeDetermineFortranCompiler.cmake index d38bf25..96df6a2 100644 --- a/Modules/CMakeDetermineFortranCompiler.cmake +++ b/Modules/CMakeDetermineFortranCompiler.cmake @@ -32,7 +32,7 @@ elseif("${CMAKE_GENERATOR}" MATCHES "Xcode") else() if(NOT CMAKE_Fortran_COMPILER) # prefer the environment variable CC - if($ENV{FC} MATCHES ".+") + if(NOT $ENV{FC} STREQUAL "") get_filename_component(CMAKE_Fortran_COMPILER_INIT $ENV{FC} PROGRAM PROGRAM_ARGS CMAKE_Fortran_FLAGS_ENV_INIT) if(CMAKE_Fortran_FLAGS_ENV_INIT) set(CMAKE_Fortran_COMPILER_ARG1 "${CMAKE_Fortran_FLAGS_ENV_INIT}" CACHE STRING "First argument to Fortran compiler") @@ -130,7 +130,7 @@ if(NOT CMAKE_Fortran_COMPILER_ID_RUN) ARGS ${CMAKE_Fortran_COMPILER_ID_FLAGS_LIST} -E "\"${CMAKE_ROOT}/Modules/CMakeTestGNU.c\"" OUTPUT_VARIABLE CMAKE_COMPILER_OUTPUT RETURN_VALUE CMAKE_COMPILER_RETURN) if(NOT CMAKE_COMPILER_RETURN) - if("${CMAKE_COMPILER_OUTPUT}" MATCHES ".*THIS_IS_GNU.*" ) + if("${CMAKE_COMPILER_OUTPUT}" MATCHES "THIS_IS_GNU") set(CMAKE_Fortran_COMPILER_ID "GNU") file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log "Determining if the Fortran compiler is GNU succeeded with " @@ -141,10 +141,10 @@ if(NOT CMAKE_Fortran_COMPILER_ID_RUN) "the following output:\n${CMAKE_COMPILER_OUTPUT}\n\n") endif() if(NOT CMAKE_Fortran_PLATFORM_ID) - if("${CMAKE_COMPILER_OUTPUT}" MATCHES ".*THIS_IS_MINGW.*" ) + if("${CMAKE_COMPILER_OUTPUT}" MATCHES "THIS_IS_MINGW") set(CMAKE_Fortran_PLATFORM_ID "MinGW") endif() - if("${CMAKE_COMPILER_OUTPUT}" MATCHES ".*THIS_IS_CYGWIN.*" ) + if("${CMAKE_COMPILER_OUTPUT}" MATCHES "THIS_IS_CYGWIN") set(CMAKE_Fortran_PLATFORM_ID "Cygwin") endif() endif() diff --git a/Modules/CMakeDetermineJavaCompiler.cmake b/Modules/CMakeDetermineJavaCompiler.cmake index 7ae7856..f657801 100644 --- a/Modules/CMakeDetermineJavaCompiler.cmake +++ b/Modules/CMakeDetermineJavaCompiler.cmake @@ -18,7 +18,7 @@ if(NOT CMAKE_Java_COMPILER) # prefer the environment variable CC - if($ENV{JAVA_COMPILER} MATCHES ".+") + if(NOT $ENV{JAVA_COMPILER} STREQUAL "") get_filename_component(CMAKE_Java_COMPILER_INIT $ENV{JAVA_COMPILER} PROGRAM PROGRAM_ARGS CMAKE_Java_FLAGS_ENV_INIT) if(CMAKE_Java_FLAGS_ENV_INIT) set(CMAKE_Java_COMPILER_ARG1 "${CMAKE_Java_FLAGS_ENV_INIT}" CACHE STRING "First argument to Java compiler") @@ -28,14 +28,14 @@ if(NOT CMAKE_Java_COMPILER) endif() endif() - if($ENV{JAVA_RUNTIME} MATCHES ".+") + if(NOT $ENV{JAVA_RUNTIME} STREQUAL "") get_filename_component(CMAKE_Java_RUNTIME_INIT $ENV{JAVA_RUNTIME} PROGRAM PROGRAM_ARGS CMAKE_Java_FLAGS_ENV_INIT) if(NOT EXISTS ${CMAKE_Java_RUNTIME_INIT}) message(SEND_ERROR "Could not find compiler set in environment variable JAVA_RUNTIME:\n$ENV{JAVA_RUNTIME}.") endif() endif() - if($ENV{JAVA_ARCHIVE} MATCHES ".+") + if(NOT $ENV{JAVA_ARCHIVE} STREQUAL "") get_filename_component(CMAKE_Java_ARCHIVE_INIT $ENV{JAVA_ARCHIVE} PROGRAM PROGRAM_ARGS CMAKE_Java_FLAGS_ENV_INIT) if(NOT EXISTS ${CMAKE_Java_ARCHIVE_INIT}) message(SEND_ERROR "Could not find compiler set in environment variable JAVA_ARCHIVE:\n$ENV{JAVA_ARCHIVE}.") diff --git a/Modules/CMakeDetermineRCCompiler.cmake b/Modules/CMakeDetermineRCCompiler.cmake index f23846e..e5414eb 100644 --- a/Modules/CMakeDetermineRCCompiler.cmake +++ b/Modules/CMakeDetermineRCCompiler.cmake @@ -20,7 +20,7 @@ # as a default compiler if(NOT CMAKE_RC_COMPILER) # prefer the environment variable RC - if($ENV{RC} MATCHES ".+") + if(NOT $ENV{RC} STREQUAL "") get_filename_component(CMAKE_RC_COMPILER_INIT $ENV{RC} PROGRAM PROGRAM_ARGS CMAKE_RC_FLAGS_ENV_INIT) if(CMAKE_RC_FLAGS_ENV_INIT) set(CMAKE_RC_COMPILER_ARG1 "${CMAKE_RC_FLAGS_ENV_INIT}" CACHE STRING "First argument to RC compiler") diff --git a/Modules/CMakeDetermineSystem.cmake b/Modules/CMakeDetermineSystem.cmake index f1bad99..1c0941a 100644 --- a/Modules/CMakeDetermineSystem.cmake +++ b/Modules/CMakeDetermineSystem.cmake @@ -72,8 +72,8 @@ if(CMAKE_HOST_UNIX) endif() set(CMAKE_UNAME ${CMAKE_UNAME} CACHE INTERNAL "uname command") # processor may have double quote in the name, and that needs to be removed - string(REGEX REPLACE "\"" "" CMAKE_HOST_SYSTEM_PROCESSOR "${CMAKE_HOST_SYSTEM_PROCESSOR}") - string(REGEX REPLACE "/" "_" CMAKE_HOST_SYSTEM_PROCESSOR "${CMAKE_HOST_SYSTEM_PROCESSOR}") + string(REPLACE "\"" "" CMAKE_HOST_SYSTEM_PROCESSOR "${CMAKE_HOST_SYSTEM_PROCESSOR}") + string(REPLACE "/" "_" CMAKE_HOST_SYSTEM_PROCESSOR "${CMAKE_HOST_SYSTEM_PROCESSOR}") endif() else() if(CMAKE_HOST_WIN32) diff --git a/Modules/CMakeDetermineVSServicePack.cmake b/Modules/CMakeDetermineVSServicePack.cmake index 353aed6..6886084 100644 --- a/Modules/CMakeDetermineVSServicePack.cmake +++ b/Modules/CMakeDetermineVSServicePack.cmake @@ -2,15 +2,15 @@ # CMakeDetermineVSServicePack # --------------------------- # -# Determine the Visual Studio service pack of the 'cl' in use. +# Deprecated. Do not use. # -# The functionality of this module has been superseded by the platform -# variable CMAKE_<LANG>_COMPILER_VERSION that contains the compiler -# version number. +# The functionality of this module has been superseded by the +# :variable:`CMAKE_<LANG>_COMPILER_VERSION` variable that contains +# the compiler version number. # -# Usage: +# Determine the Visual Studio service pack of the 'cl' in use. # -# :: +# Usage:: # # if(MSVC) # include(CMakeDetermineVSServicePack) @@ -21,14 +21,12 @@ # endif() # # Function DetermineVSServicePack sets the given variable to one of the -# following values or an empty string if unknown: -# -# :: +# following values or an empty string if unknown:: # # vc80, vc80sp1 # vc90, vc90sp1 # vc100, vc100sp1 -# vc110, vc110sp1, vc110sp2 +# vc110, vc110sp1, vc110sp2, vc110sp3, vc110sp4 #============================================================================= # Copyright 2009-2013 Kitware, Inc. @@ -45,6 +43,13 @@ # (To distribute this file outside of CMake, substitute the full # License text for the above reference.) +if(NOT CMAKE_MINIMUM_REQUIRED_VERSION VERSION_LESS 2.8.8) + message(DEPRECATION + "This module is deprecated and should not be used. " + "Use the CMAKE_<LANG>_COMPILER_VERSION variable instead." + ) +endif() + # [INTERNAL] # Please do not call this function directly function(_DetermineVSServicePackFromCompiler _OUT_VAR _cl_version) @@ -68,6 +73,8 @@ function(_DetermineVSServicePackFromCompiler _OUT_VAR _cl_version) set(_version "vc110sp2") elseif(${_cl_version} VERSION_EQUAL "17.00.60610.1") set(_version "vc110sp3") + elseif(${_cl_version} VERSION_EQUAL "17.00.61030") + set(_version "vc110sp4") else() set(_version "") endif() @@ -86,27 +93,14 @@ function(_DetermineVSServicePack_FastCheckVersionWithCompiler _SUCCESS_VAR _VER OUTPUT_QUIET ) - string(REGEX MATCH "Compiler Version [0-9]+.[0-9]+.[0-9]+.[0-9]+" - _cl_version "${_output}") - - if(_cl_version) - string(REGEX MATCHALL "[0-9]+" - _cl_version_list "${_cl_version}") - list(GET _cl_version_list 0 _major) - list(GET _cl_version_list 1 _minor) - list(GET _cl_version_list 2 _patch) - list(GET _cl_version_list 3 _tweak) - + if(_output MATCHES "Compiler Version (([0-9]+)\\.([0-9]+)\\.([0-9]+)(\\.([0-9]+))?)") + set(_cl_version ${CMAKE_MATCH_1}) + set(_major ${CMAKE_MATCH_2}) + set(_minor ${CMAKE_MATCH_3}) if("${_major}${_minor}" STREQUAL "${MSVC_VERSION}") - set(_cl_version ${_major}.${_minor}.${_patch}.${_tweak}) - else() - unset(_cl_version) - endif() - endif() - - if(_cl_version) set(${_SUCCESS_VAR} true PARENT_SCOPE) set(${_VERSION_VAR} ${_cl_version} PARENT_SCOPE) + endif() endif() endif() endfunction() @@ -127,20 +121,9 @@ function(_DetermineVSServicePack_CheckVersionWithTryCompile _SUCCESS_VAR _VERSI file(REMOVE "${CMAKE_BINARY_DIR}/return0.cc") - string(REGEX MATCH "Compiler Version [0-9]+.[0-9]+.[0-9]+.[0-9]+" - _cl_version "${_output}") - - if(_cl_version) - string(REGEX MATCHALL "[0-9]+" - _cl_version_list "${_cl_version}") - - list(GET _cl_version_list 0 _major) - list(GET _cl_version_list 1 _minor) - list(GET _cl_version_list 2 _patch) - list(GET _cl_version_list 3 _tweak) - + if(_output MATCHES "Compiler Version (([0-9]+)\\.([0-9]+)\\.([0-9]+)(\\.([0-9]+))?)") set(${_SUCCESS_VAR} true PARENT_SCOPE) - set(${_VERSION_VAR} ${_major}.${_minor}.${_patch}.${_tweak} PARENT_SCOPE) + set(${_VERSION_VAR} "${CMAKE_MATCH_1}" PARENT_SCOPE) endif() endfunction() diff --git a/Modules/CMakeExportBuildSettings.cmake b/Modules/CMakeExportBuildSettings.cmake index 90a7a89..a8dd8c2 100644 --- a/Modules/CMakeExportBuildSettings.cmake +++ b/Modules/CMakeExportBuildSettings.cmake @@ -27,7 +27,7 @@ endif() # loaded by another project using CMAKE_IMPORT_BUILD_SETTINGS. Now it # creates a file that refuses to load (with comment explaining why). macro(CMAKE_EXPORT_BUILD_SETTINGS SETTINGS_FILE) - if(${SETTINGS_FILE} MATCHES ".+") + if(NOT ${SETTINGS_FILE} STREQUAL "") configure_file(${CMAKE_ROOT}/Modules/CMakeBuildSettings.cmake.in ${SETTINGS_FILE} @ONLY) else() diff --git a/Modules/CMakeFortranCompilerABI.F b/Modules/CMakeFortranCompilerABI.F index 21ca7ff..b34c284 100644 --- a/Modules/CMakeFortranCompilerABI.F +++ b/Modules/CMakeFortranCompilerABI.F @@ -10,11 +10,15 @@ PRINT *, 'INFO:sizeof_dptr[8]' #elif defined(_M_AMD64) PRINT *, 'INFO:sizeof_dptr[8]' +#elif defined(__x86_64__) + PRINT *, 'INFO:sizeof_dptr[8]' #elif defined(_ILP32) PRINT *, 'INFO:sizeof_dptr[4]' #elif defined(_M_IX86) PRINT *, 'INFO:sizeof_dptr[4]' +#elif defined(__i386__) + PRINT *, 'INFO:sizeof_dptr[4]' #elif defined(__SIZEOF_POINTER__) && __SIZEOF_POINTER__ == 8 PRINT *, 'INFO:sizeof_dptr[8]' diff --git a/Modules/CMakeImportBuildSettings.cmake b/Modules/CMakeImportBuildSettings.cmake index 60b887a..edecc1f 100644 --- a/Modules/CMakeImportBuildSettings.cmake +++ b/Modules/CMakeImportBuildSettings.cmake @@ -17,8 +17,7 @@ # This macro used to load build settings from another project that # stored settings using the CMAKE_EXPORT_BUILD_SETTINGS macro. macro(CMAKE_IMPORT_BUILD_SETTINGS SETTINGS_FILE) - if(${SETTINGS_FILE} MATCHES ".+") - else() + if("${SETTINGS_FILE}" STREQUAL "") message(SEND_ERROR "CMAKE_IMPORT_BUILD_SETTINGS called with no argument.") endif() endmacro() diff --git a/Modules/CMakeParseImplicitLinkInfo.cmake b/Modules/CMakeParseImplicitLinkInfo.cmake index 4724a8c..bfcf455 100644 --- a/Modules/CMakeParseImplicitLinkInfo.cmake +++ b/Modules/CMakeParseImplicitLinkInfo.cmake @@ -64,10 +64,9 @@ function(CMAKE_PARSE_IMPLICIT_LINK_INFO text lib_var dir_var fwk_var log_var obj string(REGEX REPLACE "^-L" "" dir "${arg}") list(APPEND implicit_dirs_tmp ${dir}) set(log "${log} arg [${arg}] ==> dir [${dir}]\n") - elseif("${arg}" MATCHES "^-l[^:]") + elseif("${arg}" MATCHES "^-l([^:].*)$") # Unix library. - string(REGEX REPLACE "^-l" "" lib "${arg}") - list(APPEND implicit_libs_tmp ${lib}) + list(APPEND implicit_libs_tmp ${CMAKE_MATCH_1}) set(log "${log} arg [${arg}] ==> lib [${lib}]\n") elseif("${arg}" MATCHES "^(.:)?[/\\].*\\.a$") # Unix library full path. @@ -97,11 +96,10 @@ function(CMAKE_PARSE_IMPLICIT_LINK_INFO text lib_var dir_var fwk_var log_var obj endif() endforeach() break() - elseif("${line}" MATCHES "LPATH(=| is:? )") + elseif("${line}" MATCHES "LPATH(=| is:? *)(.*)$") set(log "${log} LPATH line: [${line}]\n") # HP search path. - string(REGEX REPLACE ".*LPATH(=| is:? *)" "" paths "${line}") - string(REPLACE ":" ";" paths "${paths}") + string(REPLACE ":" ";" paths "${CMAKE_MATCH_2}") list(APPEND implicit_dirs_tmp ${paths}) set(log "${log} dirs [${paths}]\n") else() diff --git a/Modules/CMakeRCInformation.cmake b/Modules/CMakeRCInformation.cmake index 8ffe50a..6bb2636 100644 --- a/Modules/CMakeRCInformation.cmake +++ b/Modules/CMakeRCInformation.cmake @@ -13,15 +13,16 @@ # License text for the above reference.) -# This file sets the basic flags for the Fortran language in CMake. +# This file sets the basic flags for the Windows Resource Compiler. # It also loads the available platform file for the system-compiler # if it exists. # make sure we don't use CMAKE_BASE_NAME from somewhere else set(CMAKE_BASE_NAME) -get_filename_component(CMAKE_BASE_NAME ${CMAKE_RC_COMPILER} NAME_WE) -if("${CMAKE_BASE_NAME}" MATCHES "windres") - set(CMAKE_BASE_NAME "windres") +if(CMAKE_RC_COMPILER MATCHES "windres[^/]*$") + set(CMAKE_BASE_NAME "windres") +else() + get_filename_component(CMAKE_BASE_NAME ${CMAKE_RC_COMPILER} NAME_WE) endif() set(CMAKE_SYSTEM_AND_RC_COMPILER_INFO_FILE ${CMAKE_ROOT}/Modules/Platform/${CMAKE_SYSTEM_NAME}-${CMAKE_BASE_NAME}.cmake) @@ -30,7 +31,7 @@ include(Platform/${CMAKE_SYSTEM_NAME}-${CMAKE_BASE_NAME} OPTIONAL) set (CMAKE_RC_FLAGS "$ENV{RCFLAGS} ${CMAKE_RC_FLAGS_INIT}" CACHE STRING - "Flags for Fortran compiler.") + "Flags for Windows Resource Compiler.") # These are the only types of flags that should be passed to the rc # command, if COMPILE_FLAGS is used on a target this will be used diff --git a/Modules/CPackDeb.cmake b/Modules/CPackDeb.cmake index b210bbb..458bbed 100644 --- a/Modules/CPackDeb.cmake +++ b/Modules/CPackDeb.cmake @@ -259,7 +259,7 @@ if(CPACK_DEBIAN_PACKAGE_SHLIBDEPS) OUTPUT_VARIABLE CPACK_DEB_INSTALL_FILES) # Convert to CMake list - string(REGEX REPLACE "\n" ";" CPACK_DEB_INSTALL_FILES ${CPACK_DEB_INSTALL_FILES}) + string(REPLACE "\n" ";" CPACK_DEB_INSTALL_FILES ${CPACK_DEB_INSTALL_FILES}) # Only dynamically linked ELF files are included # Extract only file name infront of ":" diff --git a/Modules/CPackRPM.cmake b/Modules/CPackRPM.cmake index a13a46f..2864b21 100644 --- a/Modules/CPackRPM.cmake +++ b/Modules/CPackRPM.cmake @@ -384,7 +384,7 @@ if(CPACK_RPM_PACKAGE_DEBUG) OUTPUT_VARIABLE _TMP_LSB_RELEASE_OUTPUT ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) - string(REGEX REPLACE "\n" ", " + string(REPLACE "\n" ", " LSB_RELEASE_OUTPUT ${_TMP_LSB_RELEASE_OUTPUT}) else () @@ -397,7 +397,7 @@ endif() # to shut down warning about space in buildtree # some recent RPM version should support space in different places. # not checked [yet]. -if(CPACK_TOPLEVEL_DIRECTORY MATCHES ".* .*") +if(CPACK_TOPLEVEL_DIRECTORY MATCHES " ") message(FATAL_ERROR "${RPMBUILD_EXECUTABLE} can't handle paths with spaces, use a build directory without spaces for building RPMs.") endif() diff --git a/Modules/CheckTypeSize.cmake b/Modules/CheckTypeSize.cmake index d4651b9..ad3b6b5 100644 --- a/Modules/CheckTypeSize.cmake +++ b/Modules/CheckTypeSize.cmake @@ -142,7 +142,7 @@ function(__check_type_size_impl type var map builtin language) foreach(info ${strings}) if("${info}" MATCHES "${regex_size}") # Get the type size. - string(REGEX REPLACE "${regex_size}" "\\1" size "${info}") + set(size "${CMAKE_MATCH_1}") if(first) set(${var} ${size}) elseif(NOT "${size}" STREQUAL "${${var}}") diff --git a/Modules/ExternalData.cmake b/Modules/ExternalData.cmake index 1e2698c..ee20693 100644 --- a/Modules/ExternalData.cmake +++ b/Modules/ExternalData.cmake @@ -292,8 +292,7 @@ function(ExternalData_expand_arguments target outArgsVar) foreach(piece IN LISTS pieces) if("x${piece}" MATCHES "^x${data_regex}$") # Replace this DATA{}-piece with a file path. - string(REGEX REPLACE "${data_regex}" "\\1" data "${piece}") - _ExternalData_arg("${target}" "${piece}" "${data}" file) + _ExternalData_arg("${target}" "${piece}" "${CMAKE_MATCH_1}" file) set(outArg "${outArg}${file}") else() # No replacement needed for this piece. @@ -428,10 +427,9 @@ function(_ExternalData_arg target arg options var_file) set(associated_files "") set(associated_regex "") foreach(opt ${options}) - if("x${opt}" MATCHES "^xREGEX:[^:/]+$") - # Regular expression to match associated files. - string(REGEX REPLACE "^REGEX:" "" regex "${opt}") - list(APPEND associated_regex "${regex}") + # Regular expression to match associated files. + if("x${opt}" MATCHES "^xREGEX:([^:/]+)$") + list(APPEND associated_regex "${CMAKE_MATCH_1}") elseif(opt STREQUAL ":") # Activate series matching. set(series_option "${opt}") diff --git a/Modules/ExternalProject.cmake b/Modules/ExternalProject.cmake index 0f651e9..f587985 100644 --- a/Modules/ExternalProject.cmake +++ b/Modules/ExternalProject.cmake @@ -201,11 +201,11 @@ file(STRINGS "${CMAKE_CURRENT_LIST_FILE}" lines LIMIT_COUNT ${_ep_documentation_line_count} REGEX "^# ( \\[[A-Z0-9_]+ [^]]*\\] +#.*$|[A-Za-z0-9_]+\\()") foreach(line IN LISTS lines) - if("${line}" MATCHES "^# [A-Za-z0-9_]+\\(") + if("${line}" MATCHES "^# ([A-Za-z0-9_]+)\\(") if(_ep_func) set(_ep_keywords_${_ep_func} "${_ep_keywords_${_ep_func}})$") endif() - string(REGEX REPLACE "^# ([A-Za-z0-9_]+)\\(.*" "\\1" _ep_func "${line}") + set(_ep_func "${CMAKE_MATCH_1}") #message("function [${_ep_func}]") set(_ep_keywords_${_ep_func} "^(") set(_ep_keyword_sep) @@ -907,7 +907,8 @@ function(_ep_write_initial_cache target_name script_filename args) set(regex "^([^:]+):([^=]+)=(.*)$") set(setArg "") foreach(line ${args}) - if("${line}" MATCHES "^-D") + if("${line}" MATCHES "^-D(.*)") + set(line "${CMAKE_MATCH_1}") if(setArg) # This is required to build up lists in variables, or complete an entry set(setArg "${setArg}${accumulator}\" CACHE ${type} \"Initial cache\" FORCE)") @@ -915,9 +916,7 @@ function(_ep_write_initial_cache target_name script_filename args) set(accumulator "") set(setArg "") endif() - string(REGEX REPLACE "^-D" "" line ${line}) if("${line}" MATCHES "${regex}") - string(REGEX MATCH "${regex}" match "${line}") set(name "${CMAKE_MATCH_1}") set(type "${CMAKE_MATCH_2}") set(value "${CMAKE_MATCH_3}") @@ -1352,7 +1351,7 @@ function(_ep_add_download_command name) if(cmd_set) set(work_dir ${download_dir}) elseif(cvs_repository) - find_package(CVS) + find_package(CVS QUIET) if(NOT CVS_EXECUTABLE) message(FATAL_ERROR "error: could not find cvs for checkout of ${name}") endif() @@ -1379,7 +1378,7 @@ function(_ep_add_download_command name) set(cmd ${CVS_EXECUTABLE} -d ${cvs_repository} -q co ${cvs_tag} -d ${src_name} ${cvs_module}) list(APPEND depends ${stamp_dir}/${name}-cvsinfo.txt) elseif(svn_repository) - find_package(Subversion) + find_package(Subversion QUIET) if(NOT Subversion_SVN_EXECUTABLE) message(FATAL_ERROR "error: could not find svn for checkout of ${name}") endif() @@ -1415,7 +1414,7 @@ function(_ep_add_download_command name) --non-interactive ${svn_trust_cert_args} ${svn_user_pw_args} ${src_name}) list(APPEND depends ${stamp_dir}/${name}-svninfo.txt) elseif(git_repository) - find_package(Git) + find_package(Git QUIET) if(NOT GIT_EXECUTABLE) message(FATAL_ERROR "error: could not find git for clone of ${name}") endif() @@ -1463,7 +1462,7 @@ function(_ep_add_download_command name) set(cmd ${CMAKE_COMMAND} -P ${tmp_dir}/${name}-gitclone.cmake) list(APPEND depends ${stamp_dir}/${name}-gitinfo.txt) elseif(hg_repository) - find_package(Hg) + find_package(Hg QUIET) if(NOT HG_EXECUTABLE) message(FATAL_ERROR "error: could not find hg for clone of ${name}") endif() diff --git a/Modules/FeatureSummary.cmake b/Modules/FeatureSummary.cmake index a72954c..12ea384 100644 --- a/Modules/FeatureSummary.cmake +++ b/Modules/FeatureSummary.cmake @@ -546,10 +546,10 @@ function(SET_PACKAGE_INFO _name _desc) set(_url "${ARGV2}") set(_purpose "${ARGV3}") set_property(GLOBAL PROPERTY _CMAKE_${_name}_DESCRIPTION "${_desc}" ) - if(_url MATCHES ".+") + if(NOT _url STREQUAL "") set_property(GLOBAL PROPERTY _CMAKE_${_name}_URL "${_url}" ) endif() - if(_purpose MATCHES ".+") + if(NOT _purpose STREQUAL "") set_property(GLOBAL APPEND PROPERTY _CMAKE_${_name}_PURPOSE "${_purpose}" ) endif() endfunction() diff --git a/Modules/FindBISON.cmake b/Modules/FindBISON.cmake index 9ca428e..ec3ee78 100644 --- a/Modules/FindBISON.cmake +++ b/Modules/FindBISON.cmake @@ -92,16 +92,13 @@ if(BISON_EXECUTABLE) message(SEND_ERROR "Command \"${BISON_EXECUTABLE} --version\" failed with output:\n${BISON_version_error}") else() # Bison++ - if("${BISON_version_output}" MATCHES "^bison\\+\\+") - string(REGEX REPLACE "^bison\\+\\+ Version ([^,]+).*" "\\1" - BISON_VERSION "${BISON_version_output}") + if("${BISON_version_output}" MATCHES "^bison\\+\\+ Version ([^,]+)") + set(BISON_VERSION "${CMAKE_MATCH_1}") # GNU Bison - elseif("${BISON_version_output}" MATCHES "^bison[^+]") - string(REGEX REPLACE "^bison \\(GNU Bison\\) ([^\n]+)\n.*" "\\1" - BISON_VERSION "${BISON_version_output}") - elseif("${BISON_version_output}" MATCHES "^GNU Bison ") - string(REGEX REPLACE "^GNU Bison (version )?([^\n]+).*" "\\2" - BISON_VERSION "${BISON_version_output}") + elseif("${BISON_version_output}" MATCHES "^bison \\(GNU Bison\\) ([^\n]+)\n") + set(BISON_VERSION "${CMAKE_MATCH_1}") + elseif("${BISON_version_output}" MATCHES "^GNU Bison (version )?([^\n]+)") + set(BISON_VERSION "${CMAKE_MATCH_2}") endif() endif() diff --git a/Modules/FindBLAS.cmake b/Modules/FindBLAS.cmake index 1cf9124..6a583d9 100644 --- a/Modules/FindBLAS.cmake +++ b/Modules/FindBLAS.cmake @@ -150,7 +150,7 @@ endmacro() set(BLAS_LINKER_FLAGS) set(BLAS_LIBRARIES) set(BLAS95_LIBRARIES) -if ($ENV{BLA_VENDOR} MATCHES ".+") +if (NOT $ENV{BLA_VENDOR} STREQUAL "") set(BLA_VENDOR $ENV{BLA_VENDOR}) else () if(NOT BLA_VENDOR) @@ -288,7 +288,7 @@ if (BLA_VENDOR STREQUAL "IBMESSL" OR BLA_VENDOR STREQUAL "All") endif () #BLAS in acml library? -if (BLA_VENDOR MATCHES "ACML.*" OR BLA_VENDOR STREQUAL "All") +if (BLA_VENDOR MATCHES "ACML" OR BLA_VENDOR STREQUAL "All") if( ((BLA_VENDOR STREQUAL "ACML") AND (NOT BLAS_ACML_LIB_DIRS)) OR ((BLA_VENDOR STREQUAL "ACML_MP") AND (NOT BLAS_ACML_MP_LIB_DIRS)) OR ((BLA_VENDOR STREQUAL "ACML_GPU") AND (NOT BLAS_ACML_GPU_LIB_DIRS)) @@ -465,7 +465,7 @@ if (BLA_VENDOR STREQUAL "Generic" OR BLA_VENDOR STREQUAL "All") endif () #BLAS in intel mkl 10 library? (em64t 64bit) -if (BLA_VENDOR MATCHES "Intel*" OR BLA_VENDOR STREQUAL "All") +if (BLA_VENDOR MATCHES "Intel" OR BLA_VENDOR STREQUAL "All") if (NOT WIN32) set(LM "-lm") endif () @@ -532,7 +532,7 @@ if (BLA_VENDOR MATCHES "Intel*" OR BLA_VENDOR STREQUAL "All") "mkl_blas95 mkl_intel_lp64 mkl_intel_thread mkl_core guide") # mkl >= 10.3 - if (CMAKE_C_COMPILER MATCHES ".+gcc.*") + if (CMAKE_C_COMPILER MATCHES ".+gcc") list(APPEND BLAS_SEARCH_LIBS "mkl_blas95_lp64 mkl_intel_lp64 mkl_gnu_thread mkl_core gomp") else () @@ -600,7 +600,7 @@ if (BLA_VENDOR MATCHES "Intel*" OR BLA_VENDOR STREQUAL "All") "mkl_intel_lp64 mkl_intel_thread mkl_core guide") # mkl >= 10.3 - if (CMAKE_C_COMPILER MATCHES ".+gcc.*") + if (CMAKE_C_COMPILER MATCHES ".+gcc") list(APPEND BLAS_SEARCH_LIBS "mkl_intel_lp64 mkl_gnu_thread mkl_core gomp") else () diff --git a/Modules/FindBoost.cmake b/Modules/FindBoost.cmake index d4026af..dfd4460 100644 --- a/Modules/FindBoost.cmake +++ b/Modules/FindBoost.cmake @@ -631,12 +631,12 @@ if(NOT Boost_INCLUDE_DIR) set(_boost_BOOSTIFIED_VERSION) # Transform 1.35 => 1_35 and 1.36.0 => 1_36_0 - if(_boost_VER MATCHES "[0-9]+\\.[0-9]+\\.[0-9]+") - string(REGEX REPLACE "([0-9]+)\\.([0-9]+)\\.([0-9]+)" "\\1_\\2_\\3" - _boost_BOOSTIFIED_VERSION ${_boost_VER}) - elseif(_boost_VER MATCHES "[0-9]+\\.[0-9]+") - string(REGEX REPLACE "([0-9]+)\\.([0-9]+)" "\\1_\\2" - _boost_BOOSTIFIED_VERSION ${_boost_VER}) + if(_boost_VER MATCHES "([0-9]+)\\.([0-9]+)\\.([0-9]+)") + set(_boost_BOOSTIFIED_VERSION + "${CMAKE_MATCH_1}_${CMAKE_MATCH_2}_${CMAKE_MATCH_3}") + elseif(_boost_VER MATCHES "([0-9]+)\\.([0-9]+)") + set(_boost_BOOSTIFIED_VERSION + "${CMAKE_MATCH_1}_${CMAKE_MATCH_2}") endif() list(APPEND _boost_PATH_SUFFIXES @@ -684,7 +684,7 @@ if(Boost_INCLUDE_DIR) set(_Boost_VERSION_REGEX "([0-9]+)") set(_Boost_LIB_VERSION_REGEX "\"([0-9_]+)\"") foreach(v VERSION LIB_VERSION) - if("${_boost_VERSION_HPP_CONTENTS}" MATCHES ".*#define BOOST_${v} ${_Boost_${v}_REGEX}.*") + if("${_boost_VERSION_HPP_CONTENTS}" MATCHES "#define BOOST_${v} ${_Boost_${v}_REGEX}") set(Boost_${v} "${CMAKE_MATCH_1}") endif() endforeach() diff --git a/Modules/FindCUDA.cmake b/Modules/FindCUDA.cmake index 94f82f6..c02809d 100644 --- a/Modules/FindCUDA.cmake +++ b/Modules/FindCUDA.cmake @@ -1194,7 +1194,7 @@ macro(CUDA_WRAP_SRCS cuda_target format generated_files) foreach(file ${ARGN}) # Ignore any file marked as a HEADER_FILE_ONLY get_source_file_property(_is_header ${file} HEADER_FILE_ONLY) - if(${file} MATCHES ".*\\.cu$" AND NOT _is_header) + if(${file} MATCHES "\\.cu$" AND NOT _is_header) # Allow per source file overrides of the format. get_source_file_property(_cuda_source_format ${file} CUDA_SOURCE_PROPERTY_FORMAT) diff --git a/Modules/FindCUDA/make2cmake.cmake b/Modules/FindCUDA/make2cmake.cmake index 1b53d17..c433fa8 100644 --- a/Modules/FindCUDA/make2cmake.cmake +++ b/Modules/FindCUDA/make2cmake.cmake @@ -37,12 +37,11 @@ file(READ ${input_file} depend_text) -if (${depend_text} MATCHES ".+") +if (NOT "${depend_text}" STREQUAL "") # message("FOUND DEPENDS") - # Remember, four backslashes is escaped to one backslash in the string. - string(REGEX REPLACE "\\\\ " " " depend_text ${depend_text}) + string(REPLACE "\\ " " " depend_text ${depend_text}) # This works for the nvcc -M generated dependency files. string(REGEX REPLACE "^.* : " "" depend_text ${depend_text}) diff --git a/Modules/FindCUDA/parse_cubin.cmake b/Modules/FindCUDA/parse_cubin.cmake index 94be7e2..626c8a2 100644 --- a/Modules/FindCUDA/parse_cubin.cmake +++ b/Modules/FindCUDA/parse_cubin.cmake @@ -37,11 +37,10 @@ file(READ ${input_file} file_text) -if (${file_text} MATCHES ".+") +if (NOT "${file_text}" STREQUAL "") - # Remember, four backslashes is escaped to one backslash in the string. - string(REGEX REPLACE ";" "\\\\;" file_text ${file_text}) - string(REGEX REPLACE "\ncode" ";code" file_text ${file_text}) + string(REPLACE ";" "\\;" file_text ${file_text}) + string(REPLACE "\ncode" ";code" file_text ${file_text}) list(LENGTH file_text len) @@ -57,7 +56,7 @@ if (${file_text} MATCHES ".+") # Extract kernel names. if (${entry} MATCHES "[^g]name = ([^ ]+)") - string(REGEX REPLACE ".* = ([^ ]+)" "\\1" entry ${entry}) + set(entry "${CMAKE_MATCH_1}") # Check to see if the kernel name starts with "_" set(skip FALSE) @@ -76,19 +75,19 @@ if (${file_text} MATCHES ".+") # Registers if (${entry} MATCHES "reg([ ]+)=([ ]+)([^ ]+)") - string(REGEX REPLACE ".*([ ]+)=([ ]+)([^ ]+)" "\\3" entry ${entry}) + set(entry "${CMAKE_MATCH_3}") message("Registers: ${entry}") endif() # Local memory if (${entry} MATCHES "lmem([ ]+)=([ ]+)([^ ]+)") - string(REGEX REPLACE ".*([ ]+)=([ ]+)([^ ]+)" "\\3" entry ${entry}) + set(entry "${CMAKE_MATCH_3}") message("Local: ${entry}") endif() # Shared memory if (${entry} MATCHES "smem([ ]+)=([ ]+)([^ ]+)") - string(REGEX REPLACE ".*([ ]+)=([ ]+)([^ ]+)" "\\3" entry ${entry}) + set(entry "${CMAKE_MATCH_3}") message("Shared: ${entry}") endif() diff --git a/Modules/FindCups.cmake b/Modules/FindCups.cmake index 61353ca..51eb7c5 100644 --- a/Modules/FindCups.cmake +++ b/Modules/FindCups.cmake @@ -52,9 +52,8 @@ if (CUPS_INCLUDE_DIR AND EXISTS "${CUPS_INCLUDE_DIR}/cups/cups.h") unset(CUPS_VERSION_STRING) foreach(VPART MAJOR MINOR PATCH) foreach(VLINE ${cups_version_str}) - if(VLINE MATCHES "^#[\t ]*define[\t ]+CUPS_VERSION_${VPART}") - string(REGEX REPLACE "^#[\t ]*define[\t ]+CUPS_VERSION_${VPART}[\t ]+([0-9]+)$" "\\1" - CUPS_VERSION_PART "${VLINE}") + if(VLINE MATCHES "^#[\t ]*define[\t ]+CUPS_VERSION_${VPART}[\t ]+([0-9]+)$") + set(CUPS_VERSION_PART "${CMAKE_MATCH_1}") if(CUPS_VERSION_STRING) set(CUPS_VERSION_STRING "${CUPS_VERSION_STRING}.${CUPS_VERSION_PART}") else() diff --git a/Modules/FindEXPAT.cmake b/Modules/FindEXPAT.cmake index 6183af8..653094c 100644 --- a/Modules/FindEXPAT.cmake +++ b/Modules/FindEXPAT.cmake @@ -38,9 +38,8 @@ if (EXPAT_INCLUDE_DIR AND EXISTS "${EXPAT_INCLUDE_DIR}/expat.h") unset(EXPAT_VERSION_STRING) foreach(VPART MAJOR MINOR MICRO) foreach(VLINE ${expat_version_str}) - if(VLINE MATCHES "^#[\t ]*define[\t ]+XML_${VPART}_VERSION") - string(REGEX REPLACE "^#[\t ]*define[\t ]+XML_${VPART}_VERSION[\t ]+([0-9]+)$" "\\1" - EXPAT_VERSION_PART "${VLINE}") + if(VLINE MATCHES "^#[\t ]*define[\t ]+XML_${VPART}_VERSION[\t ]+([0-9]+)$") + set(EXPAT_VERSION_PART "${CMAKE_MATCH_1}") if(EXPAT_VERSION_STRING) set(EXPAT_VERSION_STRING "${EXPAT_VERSION_STRING}.${EXPAT_VERSION_PART}") else() diff --git a/Modules/FindFLTK.cmake b/Modules/FindFLTK.cmake index b87bc7f..76f702e 100644 --- a/Modules/FindFLTK.cmake +++ b/Modules/FindFLTK.cmake @@ -285,9 +285,7 @@ endif() OUTPUT_VARIABLE FLTK_IMAGES_LDFLAGS) set(FLTK_LIBS_EXTRACT_REGEX ".*-lfltk_images (.*) -lfltk.*") if("${FLTK_IMAGES_LDFLAGS}" MATCHES "${FLTK_LIBS_EXTRACT_REGEX}") - string(REGEX REPLACE "${FLTK_LIBS_EXTRACT_REGEX}" "\\1" - FLTK_IMAGES_LIBS "${FLTK_IMAGES_LDFLAGS}") - string(REGEX REPLACE " +" ";" FLTK_IMAGES_LIBS "${FLTK_IMAGES_LIBS}") + string(REGEX REPLACE " +" ";" FLTK_IMAGES_LIBS "${CMAKE_MATCH_1}") # The EXEC_PROGRAM will not be inherited into subdirectories from # the file that originally included this module. Save the answer. set(FLTK_IMAGES_LIBS "${FLTK_IMAGES_LIBS}" CACHE INTERNAL diff --git a/Modules/FindFLTK2.cmake b/Modules/FindFLTK2.cmake index 4deffda..930acca 100644 --- a/Modules/FindFLTK2.cmake +++ b/Modules/FindFLTK2.cmake @@ -226,9 +226,7 @@ if(FLTK2_DIR) OUTPUT_VARIABLE FLTK2_IMAGES_LDFLAGS) set(FLTK2_LIBS_EXTRACT_REGEX ".*-lfltk2_images (.*) -lfltk2.*") if("${FLTK2_IMAGES_LDFLAGS}" MATCHES "${FLTK2_LIBS_EXTRACT_REGEX}") - string(REGEX REPLACE "${FLTK2_LIBS_EXTRACT_REGEX}" "\\1" - FLTK2_IMAGES_LIBS "${FLTK2_IMAGES_LDFLAGS}") - string(REGEX REPLACE " +" ";" FLTK2_IMAGES_LIBS "${FLTK2_IMAGES_LIBS}") + string(REGEX REPLACE " +" ";" FLTK2_IMAGES_LIBS "${CMAKE_MATCH_1}") # The EXEC_PROGRAM will not be inherited into subdirectories from # the file that originally included this module. Save the answer. set(FLTK2_IMAGES_LIBS "${FLTK2_IMAGES_LIBS}" CACHE INTERNAL diff --git a/Modules/FindFreetype.cmake b/Modules/FindFreetype.cmake index f0f9fe1..1779b78 100644 --- a/Modules/FindFreetype.cmake +++ b/Modules/FindFreetype.cmake @@ -117,9 +117,8 @@ if(FREETYPE_INCLUDE_DIR_freetype2 AND FREETYPE_H) unset(FREETYPE_VERSION_STRING) foreach(VPART MAJOR MINOR PATCH) foreach(VLINE ${freetype_version_str}) - if(VLINE MATCHES "^#[\t ]*define[\t ]+FREETYPE_${VPART}") - string(REGEX REPLACE "^#[\t ]*define[\t ]+FREETYPE_${VPART}[\t ]+([0-9]+)$" "\\1" - FREETYPE_VERSION_PART "${VLINE}") + if(VLINE MATCHES "^#[\t ]*define[\t ]+FREETYPE_${VPART}[\t ]+([0-9]+)$") + set(FREETYPE_VERSION_PART "${CMAKE_MATCH_1}") if(FREETYPE_VERSION_STRING) set(FREETYPE_VERSION_STRING "${FREETYPE_VERSION_STRING}.${FREETYPE_VERSION_PART}") else() diff --git a/Modules/FindGDAL.cmake b/Modules/FindGDAL.cmake index 4e04c31..bf374f9 100644 --- a/Modules/FindGDAL.cmake +++ b/Modules/FindGDAL.cmake @@ -90,9 +90,9 @@ if(UNIX) exec_program(${GDAL_CONFIG} ARGS --libs OUTPUT_VARIABLE GDAL_CONFIG_LIBS) if(GDAL_CONFIG_LIBS) string(REGEX MATCHALL "-l[^ ]+" _gdal_dashl ${GDAL_CONFIG_LIBS}) - string(REGEX REPLACE "-l" "" _gdal_lib "${_gdal_dashl}") + string(REPLACE "-l" "" _gdal_lib "${_gdal_dashl}") string(REGEX MATCHALL "-L[^ ]+" _gdal_dashL ${GDAL_CONFIG_LIBS}) - string(REGEX REPLACE "-L" "" _gdal_libpath "${_gdal_dashL}") + string(REPLACE "-L" "" _gdal_libpath "${_gdal_dashL}") endif() endif() endif() diff --git a/Modules/FindGettext.cmake b/Modules/FindGettext.cmake index 6a1e36e..7ab867b 100644 --- a/Modules/FindGettext.cmake +++ b/Modules/FindGettext.cmake @@ -71,8 +71,8 @@ if(GETTEXT_MSGMERGE_EXECUTABLE) OUTPUT_VARIABLE gettext_version ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) - if (gettext_version MATCHES "^msgmerge \\(.*\\) [0-9]") - string(REGEX REPLACE "^msgmerge \\([^\\)]*\\) ([0-9\\.]+[^ \n]*).*" "\\1" GETTEXT_VERSION_STRING "${gettext_version}") + if (gettext_version MATCHES "^msgmerge \\([^\\)]*\\) ([0-9\\.]+[^ \n]*)") + set(GETTEXT_VERSION_STRING "${CMAKE_MATCH_1}") endif() unset(gettext_version) endif() diff --git a/Modules/FindHDF5.cmake b/Modules/FindHDF5.cmake index 2903bf8..0d58e13 100644 --- a/Modules/FindHDF5.cmake +++ b/Modules/FindHDF5.cmake @@ -162,7 +162,7 @@ macro( _HDF5_parse_compile_line ) foreach( IPATH ${include_path_flags} ) string( REGEX REPLACE "^-I" "" IPATH ${IPATH} ) - string( REGEX REPLACE "//" "/" IPATH ${IPATH} ) + string( REPLACE "//" "/" IPATH ${IPATH} ) list( APPEND ${include_paths} ${IPATH} ) endforeach() @@ -179,7 +179,7 @@ macro( _HDF5_parse_compile_line foreach( LPATH ${library_path_flags} ) string( REGEX REPLACE "^-L" "" LPATH ${LPATH} ) - string( REGEX REPLACE "//" "/" LPATH ${LPATH} ) + string( REPLACE "//" "/" LPATH ${LPATH} ) list( APPEND ${library_paths} ${LPATH} ) endforeach() @@ -253,7 +253,7 @@ if( NOT HDF5_FOUND ) list( APPEND HDF5_DEFINITIONS ${HDF5_${LANGUAGE}_DEFINITIONS} ) # find the HDF5 include directories - if(${LANGUAGE} MATCHES "Fortran.*") + if(${LANGUAGE} MATCHES "Fortran") set(HDF5_INCLUDE_FILENAME hdf5.mod) else() set(HDF5_INCLUDE_FILENAME hdf5.h) diff --git a/Modules/FindIcotool.cmake b/Modules/FindIcotool.cmake index e29fe2e..a7c5a64 100644 --- a/Modules/FindIcotool.cmake +++ b/Modules/FindIcotool.cmake @@ -37,7 +37,7 @@ if(ICOTOOL_EXECUTABLE) ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE ) - if("${_icotool_version}" MATCHES "^icotool \\([^\\)]*\\) ([0-9\\.]+[^ \n]*).*") + if("${_icotool_version}" MATCHES "^icotool \\([^\\)]*\\) ([0-9\\.]+[^ \n]*)") set( ICOTOOL_VERSION_STRING "${CMAKE_MATCH_1}" ) diff --git a/Modules/FindImageMagick.cmake b/Modules/FindImageMagick.cmake index 1e7bda5..4f0e687 100644 --- a/Modules/FindImageMagick.cmake +++ b/Modules/FindImageMagick.cmake @@ -221,8 +221,8 @@ if(ImageMagick_mogrify_EXECUTABLE) OUTPUT_VARIABLE imagemagick_version ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) - if(imagemagick_version MATCHES "^Version: ImageMagick [0-9]") - string(REGEX REPLACE "^Version: ImageMagick ([-0-9\\.]+).*" "\\1" ImageMagick_VERSION_STRING "${imagemagick_version}") + if(imagemagick_version MATCHES "^Version: ImageMagick ([-0-9\\.]+)") + set(ImageMagick_VERSION_STRING "${CMAKE_MATCH_1}") endif() unset(imagemagick_version) endif() diff --git a/Modules/FindJava.cmake b/Modules/FindJava.cmake index a488c46..0bd7eb0 100644 --- a/Modules/FindJava.cmake +++ b/Modules/FindJava.cmake @@ -128,18 +128,15 @@ if(Java_JAVA_EXECUTABLE) # 3. GCJ 1.5 # 4. Kaffe 1.4.2 # 5. OpenJDK 1.7.x on OpenBSD - if(var MATCHES "java version \"[0-9]+\\.[0-9]+\\.[0-9_.]+.*\".*") + if(var MATCHES "java version \"([0-9]+\\.[0-9]+\\.[0-9_.]+.*)\"") # This is most likely Sun / OpenJDK, or maybe GCJ-java compat layer - string( REGEX REPLACE ".* version \"([0-9]+\\.[0-9]+\\.[0-9_.]+.*)\".*" - "\\1" Java_VERSION_STRING "${var}" ) - elseif(var MATCHES "java full version \"kaffe-[0-9]+\\.[0-9]+\\.[0-9_]+\".*") + set(Java_VERSION_STRING "${CMAKE_MATCH_1}") + elseif(var MATCHES "java full version \"kaffe-([0-9]+\\.[0-9]+\\.[0-9_]+)\"") # Kaffe style - string( REGEX REPLACE "java full version \"kaffe-([0-9]+\\.[0-9]+\\.[0-9_]+).*" - "\\1" Java_VERSION_STRING "${var}" ) - elseif(var MATCHES "openjdk version \"[0-9]+\\.[0-9]+\\.[0-9_]+\".*") + set(Java_VERSION_STRING "${CMAKE_MATCH_1}") + elseif(var MATCHES "openjdk version \"([0-9]+\\.[0-9]+\\.[0-9_]+)\"") # OpenJDK ver 1.7.x on OpenBSD - string( REGEX REPLACE "openjdk version \"([0-9]+\\.[0-9]+\\.[0-9_]+).*" - "\\1" Java_VERSION_STRING "${var}" ) + set(Java_VERSION_STRING "${CMAKE_MATCH_1}") else() if(NOT Java_FIND_QUIETLY) message(WARNING "regex not supported: ${var}. Please report") diff --git a/Modules/FindKDE3.cmake b/Modules/FindKDE3.cmake index 159e29c..ea898a6 100644 --- a/Modules/FindKDE3.cmake +++ b/Modules/FindKDE3.cmake @@ -192,7 +192,7 @@ if(KDECONFIG_EXECUTABLE) if ("${kde_version}" MATCHES "KDE: 3\\.") execute_process(COMMAND ${KDECONFIG_EXECUTABLE} --prefix OUTPUT_VARIABLE kdedir ) - string(REGEX REPLACE "\n" "" KDE3PREFIX "${kdedir}") + string(REPLACE "\n" "" KDE3PREFIX "${kdedir}") endif () endif() diff --git a/Modules/FindLAPACK.cmake b/Modules/FindLAPACK.cmake index 33f4f0c..b11edc3 100644 --- a/Modules/FindLAPACK.cmake +++ b/Modules/FindLAPACK.cmake @@ -159,7 +159,7 @@ endif() if(BLAS_FOUND) set(LAPACK_LINKER_FLAGS ${BLAS_LINKER_FLAGS}) - if ($ENV{BLA_VENDOR} MATCHES ".+") + if (NOT $ENV{BLA_VENDOR} STREQUAL "") set(BLA_VENDOR $ENV{BLA_VENDOR}) else () if(NOT BLA_VENDOR) @@ -183,7 +183,7 @@ endif () #acml lapack - if (BLA_VENDOR MATCHES "ACML.*" OR BLA_VENDOR STREQUAL "All") + if (BLA_VENDOR MATCHES "ACML" OR BLA_VENDOR STREQUAL "All") if (BLAS_LIBRARIES MATCHES ".+acml.+") set (LAPACK_LIBRARIES ${BLAS_LIBRARIES}) endif () @@ -233,7 +233,7 @@ if (BLA_VENDOR STREQUAL "Generic" OR endif () endif () #intel lapack -if (BLA_VENDOR MATCHES "Intel*" OR BLA_VENDOR STREQUAL "All") +if (BLA_VENDOR MATCHES "Intel" OR BLA_VENDOR STREQUAL "All") if (NOT WIN32) set(LM "-lm") endif () diff --git a/Modules/FindMPI.cmake b/Modules/FindMPI.cmake index c8d46ba..6e15f3b 100644 --- a/Modules/FindMPI.cmake +++ b/Modules/FindMPI.cmake @@ -330,7 +330,7 @@ function (interrogate_mpi_compiler lang try_libs) string(REGEX MATCHALL "(^| )-I([^\" ]+|\"[^\"]+\")" MPI_ALL_INCLUDE_PATHS "${MPI_COMPILE_CMDLINE}") foreach(IPATH ${MPI_ALL_INCLUDE_PATHS}) string(REGEX REPLACE "^ ?-I" "" IPATH ${IPATH}) - string(REGEX REPLACE "//" "/" IPATH ${IPATH}) + string(REPLACE "//" "/" IPATH ${IPATH}) list(APPEND MPI_INCLUDE_PATH_WORK ${IPATH}) endforeach() @@ -354,7 +354,7 @@ function (interrogate_mpi_compiler lang try_libs) set(MPI_LINK_PATH) foreach(LPATH ${MPI_ALL_LINK_PATHS}) string(REGEX REPLACE "^(| |-Wl,)-L" "" LPATH ${LPATH}) - string(REGEX REPLACE "//" "/" LPATH ${LPATH}) + string(REPLACE "//" "/" LPATH ${LPATH}) list(APPEND MPI_LINK_PATH ${LPATH}) endforeach() @@ -378,19 +378,14 @@ function (interrogate_mpi_compiler lang try_libs) # Extract the set of libraries to link against from the link command # line string(REGEX MATCHALL "(^| )-l([^\" ]+|\"[^\"]+\")" MPI_LIBNAMES "${MPI_LINK_CMDLINE}") + # add the compiler implicit directories because some compilers # such as the intel compiler have libraries that show up # in the showme list that can only be found in the implicit - # link directories of the compiler. Do this for C++ and C - # compilers if the implicit link directories are defined. - if (DEFINED CMAKE_CXX_IMPLICIT_LINK_DIRECTORIES) - set(MPI_LINK_PATH - "${MPI_LINK_PATH};${CMAKE_CXX_IMPLICIT_LINK_DIRECTORIES}") - endif () - - if (DEFINED CMAKE_C_IMPLICIT_LINK_DIRECTORIES) + # link directories of the compiler. + if (DEFINED CMAKE_${lang}_IMPLICIT_LINK_DIRECTORIES) set(MPI_LINK_PATH - "${MPI_LINK_PATH};${CMAKE_C_IMPLICIT_LINK_DIRECTORIES}") + "${MPI_LINK_PATH};${CMAKE_${lang}_IMPLICIT_LINK_DIRECTORIES}") endif () # Determine full path names for all of the libraries that one needs diff --git a/Modules/FindPNG.cmake b/Modules/FindPNG.cmake index 873c3de..fa04bf0 100644 --- a/Modules/FindPNG.cmake +++ b/Modules/FindPNG.cmake @@ -56,10 +56,8 @@ if(ZLIB_FOUND) list(APPEND PNG_NAMES png libpng) unset(PNG_NAMES_DEBUG) set(_PNG_VERSION_SUFFIXES 17 16 15 14 12) - if (PNG_FIND_VERSION MATCHES "^[0-9]+\\.[0-9]+(\\..*)?$") - string(REGEX REPLACE - "^([0-9]+)\\.([0-9]+).*" "\\1\\2" - _PNG_VERSION_SUFFIX_MIN "${PNG_FIND_VERSION}") + if (PNG_FIND_VERSION MATCHES "^([0-9]+)\\.([0-9]+)(\\..*)?$") + set(_PNG_VERSION_SUFFIX_MIN "${CMAKE_MATCH_1}${CMAKE_MATCH_2}") if (PNG_FIND_VERSION_EXACT) set(_PNG_VERSION_SUFFIXES ${_PNG_VERSION_SUFFIX_MIN}) else () diff --git a/Modules/FindPackageMessage.cmake b/Modules/FindPackageMessage.cmake index b6a58e4..a0349d3 100644 --- a/Modules/FindPackageMessage.cmake +++ b/Modules/FindPackageMessage.cmake @@ -42,7 +42,7 @@ function(FIND_PACKAGE_MESSAGE pkg msg details) # Avoid printing a message repeatedly for the same find result. if(NOT ${pkg}_FIND_QUIETLY) - string(REGEX REPLACE "[\n]" "" details "${details}") + string(REPLACE "\n" "" details "${details}") set(DETAILS_VAR FIND_PACKAGE_MESSAGE_DETAILS_${pkg}) if(NOT "${details}" STREQUAL "${${DETAILS_VAR}}") # The message has not yet been printed. diff --git a/Modules/FindPerl.cmake b/Modules/FindPerl.cmake index 3fd5d8e..70284b6 100644 --- a/Modules/FindPerl.cmake +++ b/Modules/FindPerl.cmake @@ -70,9 +70,9 @@ if(PERL_EXECUTABLE) OUTPUT_STRIP_TRAILING_WHITESPACE ) if(NOT PERL_VERSION_RESULT_VARIABLE AND PERL_VERSION_OUTPUT_VARIABLE MATCHES "This is perl.*[ \\(]v([0-9\\._]+)[ \\)]") - string(REGEX REPLACE ".*This is perl.*[ \\(]v([0-9\\._]+)[ \\)].*" "\\1" PERL_VERSION_STRING ${PERL_VERSION_OUTPUT_VARIABLE}) + set(PERL_VERSION_STRING "${CMAKE_MATCH_1}") elseif(NOT PERL_VERSION_RESULT_VARIABLE AND PERL_VERSION_OUTPUT_VARIABLE MATCHES "This is perl, version ([0-9\\._]+) +") - string(REGEX REPLACE ".*This is perl, version ([0-9\\._]+) +.*" "\\1" PERL_VERSION_STRING ${PERL_VERSION_OUTPUT_VARIABLE}) + set(PERL_VERSION_STRING "${CMAKE_MATCH_1}") endif() endif() endif() diff --git a/Modules/FindPkgConfig.cmake b/Modules/FindPkgConfig.cmake index 8327143..d728324 100644 --- a/Modules/FindPkgConfig.cmake +++ b/Modules/FindPkgConfig.cmake @@ -277,10 +277,10 @@ macro(_pkg_check_modules_internal _is_required _is_silent _no_cmake_path _no_cma set(_pkg_check_modules_exist_query) # check whether version is given - if (_pkg_check_modules_pkg MATCHES ".*(>=|=|<=).*") - string(REGEX REPLACE "(.*[^><])(>=|=|<=)(.*)" "\\1" _pkg_check_modules_pkg_name "${_pkg_check_modules_pkg}") - string(REGEX REPLACE "(.*[^><])(>=|=|<=)(.*)" "\\2" _pkg_check_modules_pkg_op "${_pkg_check_modules_pkg}") - string(REGEX REPLACE "(.*[^><])(>=|=|<=)(.*)" "\\3" _pkg_check_modules_pkg_ver "${_pkg_check_modules_pkg}") + if (_pkg_check_modules_pkg MATCHES "(.*[^><])(>=|=|<=)(.*)") + set(_pkg_check_modules_pkg_name "${CMAKE_MATCH_1}") + set(_pkg_check_modules_pkg_op "${CMAKE_MATCH_2}") + set(_pkg_check_modules_pkg_ver "${CMAKE_MATCH_3}") else() set(_pkg_check_modules_pkg_name "${_pkg_check_modules_pkg}") set(_pkg_check_modules_pkg_op) diff --git a/Modules/FindPythonInterp.cmake b/Modules/FindPythonInterp.cmake index c41f3a7..5e5c7b9 100644 --- a/Modules/FindPythonInterp.cmake +++ b/Modules/FindPythonInterp.cmake @@ -138,8 +138,8 @@ if(PYTHON_EXECUTABLE) string(REGEX REPLACE " .*" "" PYTHON_VERSION_STRING "${_VERSION}") string(REGEX REPLACE "^([0-9]+)\\.[0-9]+.*" "\\1" PYTHON_VERSION_MAJOR "${PYTHON_VERSION_STRING}") string(REGEX REPLACE "^[0-9]+\\.([0-9])+.*" "\\1" PYTHON_VERSION_MINOR "${PYTHON_VERSION_STRING}") - if(PYTHON_VERSION_STRING MATCHES "^[0-9]+\\.[0-9]+\\.[0-9]+.*") - string(REGEX REPLACE "^[0-9]+\\.[0-9]+\\.([0-9]+).*" "\\1" PYTHON_VERSION_PATCH "${PYTHON_VERSION_STRING}") + if(PYTHON_VERSION_STRING MATCHES "^[0-9]+\\.[0-9]+\\.([0-9]+)") + set(PYTHON_VERSION_PATCH "${CMAKE_MATCH_1}") else() set(PYTHON_VERSION_PATCH "0") endif() diff --git a/Modules/FindQt.cmake b/Modules/FindQt.cmake index e893c7a..1bc0940 100644 --- a/Modules/FindQt.cmake +++ b/Modules/FindQt.cmake @@ -87,7 +87,7 @@ find_program(QT_QMAKE_EXECUTABLE_FINDQT NAMES qmake PATHS "${QT_SEARCH_PATH}/bin if(QT_QMAKE_EXECUTABLE_FINDQT) exec_program(${QT_QMAKE_EXECUTABLE_FINDQT} ARGS "-query QT_VERSION" OUTPUT_VARIABLE QTVERSION) - if(QTVERSION MATCHES "4.*") + if(QTVERSION MATCHES "4") set(QT_QMAKE_EXECUTABLE ${QT_QMAKE_EXECUTABLE_FINDQT} CACHE PATH "Qt4 qmake program.") set(QT4_INSTALLED TRUE) endif() @@ -154,12 +154,12 @@ else() endif() endif() -if(DESIRED_QT_VERSION MATCHES 3) +if(DESIRED_QT_VERSION EQUAL 3) set(Qt3_FIND_REQUIRED ${Qt_FIND_REQUIRED}) set(Qt3_FIND_QUIETLY ${Qt_FIND_QUIETLY}) include(${CMAKE_CURRENT_LIST_DIR}/FindQt3.cmake) endif() -if(DESIRED_QT_VERSION MATCHES 4) +if(DESIRED_QT_VERSION EQUAL 4) set(Qt4_FIND_REQUIRED ${Qt_FIND_REQUIRED}) set(Qt4_FIND_QUIETLY ${Qt_FIND_QUIETLY}) include(${CMAKE_CURRENT_LIST_DIR}/FindQt4.cmake) diff --git a/Modules/FindQt3.cmake b/Modules/FindQt3.cmake index 6cd12c6..4fc6829 100644 --- a/Modules/FindQt3.cmake +++ b/Modules/FindQt3.cmake @@ -295,12 +295,12 @@ if(QT_UIC_EXECUTABLE) endif() set(_QT_UIC_VERSION_3 FALSE) -if("${QTVERSION_UIC}" MATCHES ".* 3..*") +if("${QTVERSION_UIC}" MATCHES " 3.") set(_QT_UIC_VERSION_3 TRUE) endif() set(_QT_MOC_VERSION_3 FALSE) -if("${QTVERSION_MOC}" MATCHES ".* 3..*") +if("${QTVERSION_MOC}" MATCHES " 3.") set(_QT_MOC_VERSION_3 TRUE) endif() diff --git a/Modules/FindSquish.cmake b/Modules/FindSquish.cmake index 5cff122..4076521 100644 --- a/Modules/FindSquish.cmake +++ b/Modules/FindSquish.cmake @@ -184,7 +184,7 @@ if(SQUISH_CLIENT_EXECUTABLE) execute_process(COMMAND "${SQUISH_CLIENT_EXECUTABLE}" --version OUTPUT_VARIABLE _squishVersionOutput ERROR_QUIET ) - if("${_squishVersionOutput}" MATCHES "([0-9]+)\\.([0-9]+)\\.([0-9]+).*$") + if("${_squishVersionOutput}" MATCHES "([0-9]+)\\.([0-9]+)\\.([0-9]+)") set(SQUISH_VERSION_MAJOR "${CMAKE_MATCH_1}") set(SQUISH_VERSION_MINOR "${CMAKE_MATCH_2}") set(SQUISH_VERSION_PATCH "${CMAKE_MATCH_3}") diff --git a/Modules/FindThreads.cmake b/Modules/FindThreads.cmake index 6d1c65d..6050dcd 100644 --- a/Modules/FindThreads.cmake +++ b/Modules/FindThreads.cmake @@ -41,7 +41,7 @@ set(CMAKE_REQUIRED_QUIET_SAVE ${CMAKE_REQUIRED_QUIET}) set(CMAKE_REQUIRED_QUIET ${Threads_FIND_QUIETLY}) # Do we have sproc? -if(CMAKE_SYSTEM MATCHES IRIX AND NOT CMAKE_THREAD_PREFER_PTHREAD) +if(CMAKE_SYSTEM_NAME MATCHES IRIX AND NOT CMAKE_THREAD_PREFER_PTHREAD) CHECK_INCLUDE_FILES("sys/types.h;sys/prctl.h" CMAKE_HAVE_SPROC_H) endif() @@ -138,13 +138,13 @@ if(CMAKE_THREAD_LIBS_INIT OR CMAKE_HAVE_LIBC_CREATE) set(Threads_FOUND TRUE) endif() -if(CMAKE_SYSTEM MATCHES "Windows") +if(CMAKE_SYSTEM_NAME MATCHES "Windows") set(CMAKE_USE_WIN32_THREADS_INIT 1) set(Threads_FOUND TRUE) endif() if(CMAKE_USE_PTHREADS_INIT) - if(CMAKE_SYSTEM MATCHES "HP-UX-*") + if(CMAKE_SYSTEM_NAME MATCHES "HP-UX") # Use libcma if it exists and can be used. It provides more # symbols than the plain pthread library. CMA threads # have actually been deprecated: @@ -162,12 +162,12 @@ if(CMAKE_USE_PTHREADS_INIT) set(CMAKE_USE_PTHREADS_INIT 1) endif() - if(CMAKE_SYSTEM MATCHES "OSF1-V*") + if(CMAKE_SYSTEM MATCHES "OSF1-V") set(CMAKE_USE_PTHREADS_INIT 0) set(CMAKE_THREAD_LIBS_INIT ) endif() - if(CMAKE_SYSTEM MATCHES "CYGWIN_NT*") + if(CMAKE_SYSTEM MATCHES "CYGWIN_NT") set(CMAKE_USE_PTHREADS_INIT 1) set(Threads_FOUND TRUE) set(CMAKE_THREAD_LIBS_INIT ) diff --git a/Modules/FindXMLRPC.cmake b/Modules/FindXMLRPC.cmake index e855050..1491754 100644 --- a/Modules/FindXMLRPC.cmake +++ b/Modules/FindXMLRPC.cmake @@ -77,10 +77,9 @@ if(XMLRPC_FOUND) # Look for -I options. set(XMLRPC_INCLUDE_DIRS) foreach(flag ${XMLRPC_C_CONFIG_CFLAGS}) - if("${flag}" MATCHES "^-I") - string(REGEX REPLACE "^-I" "" DIR "${flag}") - file(TO_CMAKE_PATH "${DIR}" DIR) - set(XMLRPC_INCLUDE_DIRS ${XMLRPC_INCLUDE_DIRS} "${DIR}") + if("${flag}" MATCHES "^-I(.+)") + file(TO_CMAKE_PATH "${CMAKE_MATCH_1}" DIR) + list(APPEND XMLRPC_INCLUDE_DIRS "${DIR}") endif() endforeach() else() @@ -115,13 +114,11 @@ if(XMLRPC_FOUND) set(XMLRPC_LIBRARY_DIRS) set(XMLRPC_LIBRARY_NAMES) foreach(flag ${XMLRPC_C_CONFIG_LIBS}) - if("${flag}" MATCHES "^-L") - string(REGEX REPLACE "^-L" "" DIR "${flag}") - file(TO_CMAKE_PATH "${DIR}" DIR) - set(XMLRPC_LIBRARY_DIRS ${XMLRPC_LIBRARY_DIRS} "${DIR}") - elseif("${flag}" MATCHES "^-l") - string(REGEX REPLACE "^-l" "" NAME "${flag}") - set(XMLRPC_LIBRARY_NAMES ${XMLRPC_LIBRARY_NAMES} "${NAME}") + if("${flag}" MATCHES "^-L(.+)") + file(TO_CMAKE_PATH "${CMAKE_MATCH_1}" DIR) + list(APPEND XMLRPC_LIBRARY_DIRS "${DIR}") + elseif("${flag}" MATCHES "^-l(.+)") + list(APPEND XMLRPC_LIBRARY_NAMES "${CMAKE_MATCH_1}") endif() endforeach() diff --git a/Modules/FindZLIB.cmake b/Modules/FindZLIB.cmake index 75b0076..8cc382c 100644 --- a/Modules/FindZLIB.cmake +++ b/Modules/FindZLIB.cmake @@ -85,7 +85,7 @@ if(ZLIB_INCLUDE_DIR AND EXISTS "${ZLIB_INCLUDE_DIR}/zlib.h") # only append a TWEAK version if it exists: set(ZLIB_VERSION_TWEAK "") - if( "${ZLIB_H}" MATCHES "^.*ZLIB_VERSION \"[0-9]+\\.[0-9]+\\.[0-9]+\\.([0-9]+).*$") + if( "${ZLIB_H}" MATCHES "ZLIB_VERSION \"[0-9]+\\.[0-9]+\\.[0-9]+\\.([0-9]+)") set(ZLIB_VERSION_TWEAK "${CMAKE_MATCH_1}") set(ZLIB_VERSION_STRING "${ZLIB_VERSION_STRING}.${ZLIB_VERSION_TWEAK}") endif() diff --git a/Modules/FindwxWidgets.cmake b/Modules/FindwxWidgets.cmake index 3c664e7..45596a0 100644 --- a/Modules/FindwxWidgets.cmake +++ b/Modules/FindwxWidgets.cmake @@ -560,7 +560,7 @@ if(wxWidgets_FIND_STYLE STREQUAL "win32") if(WX_LIB_DIR) # If building shared libs, define WXUSINGDLL to use dllimport. - if(WX_LIB_DIR MATCHES ".*[dD][lL][lL].*") + if(WX_LIB_DIR MATCHES "[dD][lL][lL]") set(wxWidgets_DEFINITIONS WXUSINGDLL) DBG_MSG_V("detected SHARED/DLL tree WX_LIB_DIR=${WX_LIB_DIR}") endif() @@ -668,7 +668,7 @@ else() if(_wx_result EQUAL 0) foreach(_opt_name debug static unicode universal) string(TOUPPER ${_opt_name} _upper_opt_name) - if(_wx_selected_config MATCHES ".*${_opt_name}.*") + if(_wx_selected_config MATCHES "${_opt_name}") set(wxWidgets_DEFAULT_${_upper_opt_name} ON) else() set(wxWidgets_DEFAULT_${_upper_opt_name} OFF) diff --git a/Modules/FortranCInterface.cmake b/Modules/FortranCInterface.cmake index dccb26f..27f8a82 100644 --- a/Modules/FortranCInterface.cmake +++ b/Modules/FortranCInterface.cmake @@ -328,7 +328,7 @@ function(FortranCInterface_VERIFY) # Error if compilers are incompatible. if(NOT FortranCInterface_VERIFIED_${lang} AND NOT quiet) file(READ "${FortranCInterface_BINARY_DIR}/Verify${lang}/output.txt" _output) - string(REGEX REPLACE "\n" "\n " _output "${_output}") + string(REPLACE "\n" "\n " _output "${_output}") message(FATAL_ERROR "The Fortran compiler:\n ${CMAKE_Fortran_COMPILER}\n" "and the ${lang} compiler:\n ${CMAKE_${lang}_COMPILER}\n" diff --git a/Modules/FortranCInterface/Detect.cmake b/Modules/FortranCInterface/Detect.cmake index afeb9c5..ceb1db4 100644 --- a/Modules/FortranCInterface/Detect.cmake +++ b/Modules/FortranCInterface/Detect.cmake @@ -69,9 +69,8 @@ if(FortranCInterface_EXE) file(STRINGS "${FortranCInterface_EXE}" _info_strings LIMIT_COUNT 8 REGEX "INFO:[^[]*\\[") foreach(info ${_info_strings}) - if("${info}" MATCHES ".*INFO:symbol\\[([^]]*)\\].*") - string(REGEX REPLACE ".*INFO:symbol\\[([^]]*)\\].*" "\\1" symbol "${info}") - list(APPEND FortranCInterface_SYMBOLS ${symbol}) + if("${info}" MATCHES "INFO:symbol\\[([^]]*)\\]") + list(APPEND FortranCInterface_SYMBOLS ${CMAKE_MATCH_1}) endif() endforeach() elseif(NOT _result) diff --git a/Modules/GetPrerequisites.cmake b/Modules/GetPrerequisites.cmake index ac649e9..05c2edb 100644 --- a/Modules/GetPrerequisites.cmake +++ b/Modules/GetPrerequisites.cmake @@ -509,10 +509,10 @@ function(gp_resolved_file_type original_file file exepath dirs type_var) if(WIN32) string(TOLOWER "$ENV{SystemRoot}" sysroot) - string(REGEX REPLACE "\\\\" "/" sysroot "${sysroot}") + file(TO_CMAKE_PATH "${sysroot}" sysroot) string(TOLOWER "$ENV{windir}" windir) - string(REGEX REPLACE "\\\\" "/" windir "${windir}") + file(TO_CMAKE_PATH "${windir}" windir) if(lower MATCHES "^(${sysroot}/sys(tem|wow)|${windir}/sys(tem|wow)|(.*/)*msvc[^/]+dll)") set(is_system 1) @@ -772,8 +772,8 @@ function(get_prerequisites target prerequisites_var exclude_system recurse exepa # Convert to a list of lines: # - string(REGEX REPLACE ";" "\\\\;" candidates "${gp_cmd_ov}") - string(REGEX REPLACE "\n" "${eol_char};" candidates "${candidates}") + string(REPLACE ";" "\\;" candidates "${gp_cmd_ov}") + string(REPLACE "\n" "${eol_char};" candidates "${candidates}") # check for install id and remove it from list, since otool -L can include a # reference to itself diff --git a/Modules/Platform/Android.cmake b/Modules/Platform/Android.cmake deleted file mode 100644 index a4c122d..0000000 --- a/Modules/Platform/Android.cmake +++ /dev/null @@ -1,5 +0,0 @@ -include(Platform/Linux) -set(CMAKE_SHARED_LIBRARY_SONAME_C_FLAG "") -# RPath is useless on Android, because we can't determine the installation -# location ahead of time. -set(CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG "") diff --git a/Modules/Platform/Darwin.cmake b/Modules/Platform/Darwin.cmake index fc3f87e..df0756b 100644 --- a/Modules/Platform/Darwin.cmake +++ b/Modules/Platform/Darwin.cmake @@ -203,7 +203,7 @@ endif() # Make sure the combination of SDK and Deployment Target are allowed if(CMAKE_OSX_DEPLOYMENT_TARGET) - if("${_CMAKE_OSX_SYSROOT_PATH}" MATCHES "^.*/MacOSX([0-9]+\\.[0-9]+)[^/]*\\.sdk") + if("${_CMAKE_OSX_SYSROOT_PATH}" MATCHES "/MacOSX([0-9]+\\.[0-9]+)[^/]*\\.sdk") set(_sdk_ver "${CMAKE_MATCH_1}") elseif("${_CMAKE_OSX_SYSROOT_ORIG}" MATCHES "^macosx([0-9]+\\.[0-9]+)$") set(_sdk_ver "${CMAKE_MATCH_1}") diff --git a/Modules/Platform/OSF1.cmake b/Modules/Platform/OSF1.cmake index 9c3255e..f2ad612 100644 --- a/Modules/Platform/OSF1.cmake +++ b/Modules/Platform/OSF1.cmake @@ -2,7 +2,7 @@ set(CMAKE_DL_LIBS "") if(CMAKE_SYSTEM MATCHES "OSF1-1.[012]") endif() -if(CMAKE_SYSTEM MATCHES "OSF1-1.*") +if(CMAKE_SYSTEM MATCHES "OSF1-1") # OSF/1 1.3 from OSF using ELF, and derivatives, including AD2 set(CMAKE_C_COMPILE_OPTIONS_PIC "-fpic") set(CMAKE_C_COMPILE_OPTIONS_PIE "-fpie") @@ -12,7 +12,7 @@ endif() -if(CMAKE_SYSTEM MATCHES "OSF1-V.*") +if(CMAKE_SYSTEM MATCHES "OSF1-V") set(CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS "-shared -Wl,-expect_unresolved,\\*") # -shared if(CMAKE_COMPILER_IS_GNUCXX) set(CMAKE_SHARED_LIBRARY_RUNTIME_CXX_FLAG "-Wl,-rpath,") diff --git a/Modules/Platform/OpenBSD.cmake b/Modules/Platform/OpenBSD.cmake index 53cabed..a4f6114 100644 --- a/Modules/Platform/OpenBSD.cmake +++ b/Modules/Platform/OpenBSD.cmake @@ -10,7 +10,7 @@ if(NOT CMAKE_PLATFORM_RUNTIME_PATH) ERROR_QUIET) string(REGEX REPLACE ".*search\\ directories:\\ ([^\n]*).*" "\\1" LDCONFIG_HINTS "${LDCONFIG_HINTS}") - string(REGEX REPLACE ":" ";" + string(REPLACE ":" ";" CMAKE_PLATFORM_RUNTIME_PATH "${LDCONFIG_HINTS}") endif() diff --git a/Modules/Platform/SunOS.cmake b/Modules/Platform/SunOS.cmake index da20f97..aaa79c4 100644 --- a/Modules/Platform/SunOS.cmake +++ b/Modules/Platform/SunOS.cmake @@ -1,4 +1,4 @@ -if(CMAKE_SYSTEM MATCHES "SunOS-4.*") +if(CMAKE_SYSTEM MATCHES "SunOS-4") set(CMAKE_C_COMPILE_OPTIONS_PIC "-PIC") set(CMAKE_C_COMPILE_OPTIONS_PIE "-PIE") set(CMAKE_SHARED_LIBRARY_C_FLAGS "-PIC") diff --git a/Modules/Platform/Windows-GNU.cmake b/Modules/Platform/Windows-GNU.cmake index 5c5b360..990acea 100644 --- a/Modules/Platform/Windows-GNU.cmake +++ b/Modules/Platform/Windows-GNU.cmake @@ -67,8 +67,8 @@ macro(__windows_compiler_gnu lang) if(MSYS OR MINGW) # Create archiving rules to support large object file lists for static libraries. - set(CMAKE_${lang}_ARCHIVE_CREATE "<CMAKE_AR> cr <TARGET> <LINK_FLAGS> <OBJECTS>") - set(CMAKE_${lang}_ARCHIVE_APPEND "<CMAKE_AR> r <TARGET> <LINK_FLAGS> <OBJECTS>") + set(CMAKE_${lang}_ARCHIVE_CREATE "<CMAKE_AR> cq <TARGET> <LINK_FLAGS> <OBJECTS>") + set(CMAKE_${lang}_ARCHIVE_APPEND "<CMAKE_AR> q <TARGET> <LINK_FLAGS> <OBJECTS>") set(CMAKE_${lang}_ARCHIVE_FINISH "<CMAKE_RANLIB> <TARGET>") # Initialize C link type selection flags. These flags are used when @@ -113,9 +113,9 @@ macro(__windows_compiler_gnu lang) # Binary link rules. set(CMAKE_${lang}_CREATE_SHARED_MODULE - "<CMAKE_${lang}_COMPILER> <CMAKE_SHARED_MODULE_${lang}_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_MODULE_CREATE_${lang}_FLAGS> -o <TARGET> ${CMAKE_GNULD_IMAGE_VERSION} <OBJECTS> <LINK_LIBRARIES>") + "<CMAKE_${lang}_COMPILER> <CMAKE_SHARED_MODULE_${lang}_FLAGS> <LANGUAGE_COMPILE_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_MODULE_CREATE_${lang}_FLAGS> -o <TARGET> ${CMAKE_GNULD_IMAGE_VERSION} <OBJECTS> <LINK_LIBRARIES>") set(CMAKE_${lang}_CREATE_SHARED_LIBRARY - "<CMAKE_${lang}_COMPILER> <CMAKE_SHARED_LIBRARY_${lang}_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_${lang}_FLAGS> -o <TARGET> -Wl,--out-implib,<TARGET_IMPLIB> ${CMAKE_GNULD_IMAGE_VERSION} <OBJECTS> <LINK_LIBRARIES>") + "<CMAKE_${lang}_COMPILER> <CMAKE_SHARED_LIBRARY_${lang}_FLAGS> <LANGUAGE_COMPILE_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_${lang}_FLAGS> -o <TARGET> -Wl,--out-implib,<TARGET_IMPLIB> ${CMAKE_GNULD_IMAGE_VERSION} <OBJECTS> <LINK_LIBRARIES>") set(CMAKE_${lang}_LINK_EXECUTABLE "<CMAKE_${lang}_COMPILER> <FLAGS> <CMAKE_${lang}_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> -Wl,--out-implib,<TARGET_IMPLIB> ${CMAKE_GNULD_IMAGE_VERSION} <LINK_LIBRARIES>") diff --git a/Modules/Platform/Windows-wcl386.cmake b/Modules/Platform/Windows-wcl386.cmake index 72a5929..ac410de 100644 --- a/Modules/Platform/Windows-wcl386.cmake +++ b/Modules/Platform/Windows-wcl386.cmake @@ -51,7 +51,7 @@ set(CMAKE_C_CREATE_IMPORT_LIBRARY set(CMAKE_CXX_CREATE_IMPORT_LIBRARY ${CMAKE_C_CREATE_IMPORT_LIBRARY}) set(CMAKE_C_LINK_EXECUTABLE - "wlink ${CMAKE_START_TEMP_FILE} ${CMAKE_WLINK_QUIET} name '<TARGET_UNQUOTED>' <LINK_FLAGS> file {<OBJECTS>} <LINK_LIBRARIES> ${CMAKE_END_TEMP_FILE}") + "wlink ${CMAKE_START_TEMP_FILE} ${CMAKE_WLINK_QUIET} name <TARGET> <LINK_FLAGS> file {<OBJECTS>} <LINK_LIBRARIES> ${CMAKE_END_TEMP_FILE}") set(CMAKE_CXX_LINK_EXECUTABLE ${CMAKE_C_LINK_EXECUTABLE}) @@ -73,7 +73,7 @@ set(CMAKE_CXX_CREATE_PREPROCESSED_SOURCE "<CMAKE_CXX_COMPILER> ${CMAKE_START_TEMP_FILE} ${CMAKE_WCL_QUIET} <FLAGS> -d+ <DEFINES> -fo<PREPROCESSED_SOURCE> -pl -cc++ <SOURCE>${CMAKE_END_TEMP_FILE}") set(CMAKE_CXX_CREATE_SHARED_LIBRARY - "wlink ${CMAKE_START_TEMP_FILE} ${CMAKE_WLINK_QUIET} name '<TARGET_UNQUOTED>' <LINK_FLAGS> option implib=<TARGET_IMPLIB> file {<OBJECTS>} <LINK_LIBRARIES> ${CMAKE_END_TEMP_FILE}") + "wlink ${CMAKE_START_TEMP_FILE} ${CMAKE_WLINK_QUIET} name <TARGET> <LINK_FLAGS> option implib=<TARGET_IMPLIB> file {<OBJECTS>} <LINK_LIBRARIES> ${CMAKE_END_TEMP_FILE}") string(REPLACE " option implib=<TARGET_IMPLIB>" "" CMAKE_CXX_CREATE_SHARED_MODULE "${CMAKE_CXX_CREATE_SHARED_LIBRARY}") diff --git a/Modules/Qt4Macros.cmake b/Modules/Qt4Macros.cmake index 23c4fc0..b1b12d6 100644 --- a/Modules/Qt4Macros.cmake +++ b/Modules/Qt4Macros.cmake @@ -65,8 +65,8 @@ macro (QT4_MAKE_OUTPUT_FILE infile prefix ext outfile ) else() file(RELATIVE_PATH rel ${CMAKE_CURRENT_SOURCE_DIR} ${infile}) endif() - if(WIN32 AND rel MATCHES "^[a-zA-Z]:") # absolute path - string(REGEX REPLACE "^([a-zA-Z]):(.*)$" "\\1_\\2" rel "${rel}") + if(WIN32 AND rel MATCHES "^([a-zA-Z]):(.*)$") # absolute path + set(rel "${CMAKE_MATCH_1}_${CMAKE_MATCH_2}") endif() set(_outfile "${CMAKE_CURRENT_BINARY_DIR}/${rel}") string(REPLACE ".." "__" _outfile ${_outfile}) diff --git a/Modules/UseSWIG.cmake b/Modules/UseSWIG.cmake index 23bf933..fa11585 100644 --- a/Modules/UseSWIG.cmake +++ b/Modules/UseSWIG.cmake @@ -181,7 +181,7 @@ macro(SWIG_ADD_MODULE name language) set(swig_dot_i_sources) set(swig_other_sources) foreach(it ${ARGN}) - if(${it} MATCHES ".*\\.i$") + if(${it} MATCHES "\\.i$") set(swig_dot_i_sources ${swig_dot_i_sources} "${it}") else() set(swig_other_sources ${swig_other_sources} "${it}") diff --git a/Modules/UseVTKConfig40.cmake b/Modules/UseVTKConfig40.cmake index 554b8c4..c5022e4 100644 --- a/Modules/UseVTKConfig40.cmake +++ b/Modules/UseVTKConfig40.cmake @@ -312,7 +312,7 @@ else() if(CMAKE_ANSI_CFLAGS) set(VTK_REQUIRED_C_FLAGS "${VTK_REQUIRED_C_FLAGS} ${CMAKE_ANSI_CFLAGS}") endif() - if(CMAKE_SYSTEM MATCHES "OSF1-V.*") + if(CMAKE_SYSTEM MATCHES "OSF1-V") set(VTK_REQUIRED_CXX_FLAGS "${VTK_REQUIRED_CXX_FLAGS} -timplicit_local -no_implicit_include") endif() diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index 49e2cf3..a6be93f 100644 --- a/Source/CMakeVersion.cmake +++ b/Source/CMakeVersion.cmake @@ -1,5 +1,5 @@ # CMake version number components. set(CMake_VERSION_MAJOR 3) set(CMake_VERSION_MINOR 0) -set(CMake_VERSION_PATCH 20140407) +set(CMake_VERSION_PATCH 20140415) #set(CMake_VERSION_RC 1) diff --git a/Source/CMakeVersionSource.cmake b/Source/CMakeVersionSource.cmake index 05e265c..888f557 100644 --- a/Source/CMakeVersionSource.cmake +++ b/Source/CMakeVersionSource.cmake @@ -30,8 +30,8 @@ if(EXISTS ${CMake_SOURCE_DIR}/.git/HEAD) elseif(EXISTS ${CMake_SOURCE_DIR}/CVS/Repository) file(READ ${CMake_SOURCE_DIR}/CVS/Repository repo) set(branch "") - if("${repo}" MATCHES "\\.git/") - string(REGEX REPLACE ".*\\.git/([^\r\n]*).*" "-\\1" branch "${repo}") + if("${repo}" MATCHES "\\.git/([^\r\n]*)") + set(branch "${CMAKE_MATCH_1}") endif() set(CMake_VERSION_SOURCE "cvs${branch}") endif() diff --git a/Source/cmCommandArgumentLexer.cxx b/Source/cmCommandArgumentLexer.cxx index e62e53e..e23ef8a 100644 --- a/Source/cmCommandArgumentLexer.cxx +++ b/Source/cmCommandArgumentLexer.cxx @@ -1069,7 +1069,7 @@ case YY_STATE_EOF(NOESCAPES): "fatal flex scanner internal error--no action found" ); } /* end of action switch */ } /* end of scanning one token */ -return 0; /* this should not happend but it should silence a warning */ +return 0; /* this should not happen but it quiets some compilers */ } /* end of cmCommandArgument_yylex */ /* yy_get_next_buffer - try to read in a new buffer diff --git a/Source/cmCryptoHash.cxx b/Source/cmCryptoHash.cxx index 0d3c6bb..74e17b6 100644 --- a/Source/cmCryptoHash.cxx +++ b/Source/cmCryptoHash.cxx @@ -38,7 +38,7 @@ cmsys::auto_ptr<cmCryptoHash> cmCryptoHash::New(const char* algo) std::string cmCryptoHash::HashString(const std::string& input) { this->Initialize(); - this->Append(reinterpret_cast<unsigned char const*>(&input[0]), + this->Append(reinterpret_cast<unsigned char const*>(input.c_str()), static_cast<int>(input.size())); return this->Finalize(); } diff --git a/Source/cmDependsJavaLexer.cxx b/Source/cmDependsJavaLexer.cxx index 1e505a5..f7676d9 100644 --- a/Source/cmDependsJavaLexer.cxx +++ b/Source/cmDependsJavaLexer.cxx @@ -1591,7 +1591,7 @@ case YY_STATE_EOF(string): "fatal flex scanner internal error--no action found" ); } /* end of action switch */ } /* end of scanning one token */ -return 0; /* this should not happen but it silences a warning*/ +return 0; /* this should not happen but it quiets some compilers */ } /* end of cmDependsJava_yylex */ /* yy_get_next_buffer - try to read in a new buffer diff --git a/Source/cmELF.cxx b/Source/cmELF.cxx index dc6772c..cab23b7 100644 --- a/Source/cmELF.cxx +++ b/Source/cmELF.cxx @@ -124,7 +124,7 @@ public: virtual unsigned int GetNumberOfSections() const = 0; virtual unsigned int GetDynamicEntryCount() = 0; virtual unsigned long GetDynamicEntryPosition(int j) = 0; - virtual StringEntry const* GetDynamicSectionString(int tag) = 0; + virtual StringEntry const* GetDynamicSectionString(unsigned int tag) = 0; virtual void PrintInfo(std::ostream& os) const = 0; bool ReadBytes(unsigned long pos, unsigned long size, char* buf) @@ -187,7 +187,7 @@ protected: } // Store string table entry states. - std::map<int, StringEntry> DynamicSectionStrings; + std::map<unsigned int, StringEntry> DynamicSectionStrings; }; //---------------------------------------------------------------------------- @@ -198,6 +198,7 @@ struct cmELFTypes32 typedef Elf32_Shdr ELF_Shdr; typedef Elf32_Dyn ELF_Dyn; typedef Elf32_Half ELF_Half; + typedef cmIML_INT_uint32_t tagtype; static const char* GetName() { return "32-bit"; } }; @@ -208,6 +209,7 @@ struct cmELFTypes64 typedef Elf64_Shdr ELF_Shdr; typedef Elf64_Dyn ELF_Dyn; typedef Elf64_Half ELF_Half; + typedef cmIML_INT_uint64_t tagtype; static const char* GetName() { return "64-bit"; } }; @@ -222,6 +224,7 @@ public: typedef typename Types::ELF_Shdr ELF_Shdr; typedef typename Types::ELF_Dyn ELF_Dyn; typedef typename Types::ELF_Half ELF_Half; + typedef typename Types::tagtype tagtype; // Construct with a stream and byte swap indicator. cmELFInternalImpl(cmELF* external, @@ -239,7 +242,7 @@ public: virtual unsigned long GetDynamicEntryPosition(int j); // Lookup a string from the dynamic section with the given tag. - virtual StringEntry const* GetDynamicSectionString(int tag); + virtual StringEntry const* GetDynamicSectionString(unsigned int tag); // Print information about the ELF file. virtual void PrintInfo(std::ostream& os) const @@ -624,10 +627,10 @@ unsigned long cmELFInternalImpl<Types>::GetDynamicEntryPosition(int j) //---------------------------------------------------------------------------- template <class Types> cmELF::StringEntry const* -cmELFInternalImpl<Types>::GetDynamicSectionString(int tag) +cmELFInternalImpl<Types>::GetDynamicSectionString(unsigned int tag) { // Short-circuit if already checked. - std::map<int, StringEntry>::iterator dssi = + std::map<unsigned int, StringEntry>::iterator dssi = this->DynamicSectionStrings.find(tag); if(dssi != this->DynamicSectionStrings.end()) { @@ -665,7 +668,7 @@ cmELFInternalImpl<Types>::GetDynamicSectionString(int tag) di != this->DynamicSectionEntries.end(); ++di) { ELF_Dyn& dyn = *di; - if(dyn.d_tag == tag) + if(static_cast<tagtype>(dyn.d_tag) == static_cast<tagtype>(tag)) { // We found the tag requested. // Make sure the position given is within the string section. diff --git a/Source/cmExportFileGenerator.cxx b/Source/cmExportFileGenerator.cxx index b38c48b..42fce6d 100644 --- a/Source/cmExportFileGenerator.cxx +++ b/Source/cmExportFileGenerator.cxx @@ -279,7 +279,43 @@ static bool checkInterfaceDirs(const std::string &prepro, } if (isSubDirectory(li->c_str(), installDir)) { - continue; + // The include directory is inside the install tree. If the + // install tree is not inside the source tree or build tree then + // fall through to the checks below that the include directory is not + // also inside the source tree or build tree. + bool shouldContinue = + isSubDirectory(installDir, topBinaryDir) + || isSubDirectory(installDir, topSourceDir); + + if (!shouldContinue) + { + switch(target->GetPolicyStatusCMP0052()) + { + case cmPolicies::WARN: + { + cmOStringStream s; + s << target->GetMakefile()->GetPolicies() + ->GetPolicyWarning(cmPolicies::CMP0052) << "\n"; + s << "Directory:\n \"" << *li << "\"\nin " + "INTERFACE_INCLUDE_DIRECTORIES of target \"" + << target->GetName() << "\" is a subdirectory of the install " + "directory:\n \"" << installDir << "\""; + target->GetMakefile()->IssueMessage(cmake::AUTHOR_WARNING, + s.str()); + } + case cmPolicies::OLD: + shouldContinue = true; + break; + case cmPolicies::REQUIRED_ALWAYS: + case cmPolicies::REQUIRED_IF_USED: + case cmPolicies::NEW: + break; + } + } + if (shouldContinue) + { + continue; + } } if (isSubDirectory(li->c_str(), topBinaryDir)) { diff --git a/Source/cmExprLexer.cxx b/Source/cmExprLexer.cxx index aa384cd..4704f03 100644 --- a/Source/cmExprLexer.cxx +++ b/Source/cmExprLexer.cxx @@ -976,7 +976,7 @@ case YY_STATE_EOF(INITIAL): "fatal flex scanner internal error--no action found" ); } /* end of action switch */ } /* end of scanning one token */ -return 0; /* this should not happen but it silences a warning*/ +return 0; /* this should not happen but it quiets some compilers */ } /* end of cmExpr_yylex */ /* yy_get_next_buffer - try to read in a new buffer diff --git a/Source/cmExtraCodeLiteGenerator.cxx b/Source/cmExtraCodeLiteGenerator.cxx index 33ffc90..8acc5b4 100644 --- a/Source/cmExtraCodeLiteGenerator.cxx +++ b/Source/cmExtraCodeLiteGenerator.cxx @@ -23,8 +23,8 @@ #include <cmsys/SystemTools.hxx> #include <cmsys/SystemInformation.hxx> #include <cmsys/Directory.hxx> +#include "cmStandardIncludes.h" #include "cmXMLSafe.h" -#include <sstream> //---------------------------------------------------------------------------- void cmExtraCodeLiteGenerator::GetDocumentation(cmDocumentationEntry& entry, diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index 0d25a00..ec5ce9e 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -610,6 +610,7 @@ private: std::set<cmSourceFile*> SourcesQueued; typedef std::map<std::string, cmSourceFile*> NameMapType; NameMapType NameMap; + std::vector<std::string> NewSources; void QueueSource(cmSourceFile* sf); void FollowName(std::string const& name); @@ -698,6 +699,8 @@ void cmTargetTraceDependencies::Trace() } } this->CurrentEntry = 0; + + this->Target->AddTracedSources(this->NewSources); } //---------------------------------------------------------------------------- @@ -707,8 +710,8 @@ void cmTargetTraceDependencies::QueueSource(cmSourceFile* sf) { this->SourceQueue.push(sf); - // Make sure this file is in the target. - this->Target->AddSource(sf->GetFullPath()); + // Make sure this file is in the target at the end. + this->NewSources.push_back(sf->GetFullPath()); } } diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index 528b1dc..f375b5f 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -689,6 +689,7 @@ void cmLocalGenerator::AddBuildTargetRule(const std::string& llang, std::string createRule = "CMAKE_"; createRule += llang; createRule += target.GetCreateRuleVariable(); + bool useWatcomQuote = this->Makefile->IsOn(createRule+"_USE_WATCOM_QUOTE"); std::string targetName = target.Target->GetFullName(); // Executable : // Shared Library: @@ -700,7 +701,7 @@ void cmLocalGenerator::AddBuildTargetRule(const std::string& llang, std::string flags; // should be set std::string linkFlags; // should be set this->GetTargetFlags(linkLibs, frameworkPath, linkPath, flags, linkFlags, - &target); + &target, useWatcomQuote); linkLibs = frameworkPath + linkPath + linkLibs; cmLocalGenerator::RuleVariables vars; vars.Language = llang.c_str(); @@ -1622,7 +1623,8 @@ void cmLocalGenerator::GetTargetFlags(std::string& linkLibs, std::string& linkFlags, std::string& frameworkPath, std::string& linkPath, - cmGeneratorTarget* target) + cmGeneratorTarget* target, + bool useWatcomQuote) { std::string buildType = this->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE"); @@ -1686,7 +1688,7 @@ void cmLocalGenerator::GetTargetFlags(std::string& linkLibs, } } this->OutputLinkLibraries(linkLibs, frameworkPath, linkPath, - *target, false, false); + *target, false, false, useWatcomQuote); } break; case cmTarget::EXECUTABLE: @@ -1711,7 +1713,7 @@ void cmLocalGenerator::GetTargetFlags(std::string& linkLibs, } this->AddLanguageFlags(flags, linkLanguage, buildType); this->OutputLinkLibraries(linkLibs, frameworkPath, linkPath, - *target, false, false); + *target, false, false, useWatcomQuote); if(cmSystemTools::IsOn (this->Makefile->GetDefinition("BUILD_SHARED_LIBS"))) { @@ -1770,9 +1772,8 @@ std::string cmLocalGenerator::ConvertToLinkReference(std::string const& lib, OutputFormat format) { #if defined(_WIN32) && !defined(__CYGWIN__) - // Work-ardound command line parsing limitations in MSVC 6.0 and - // Watcom. - if(this->Makefile->IsOn("MSVC60") || this->Makefile->IsOn("WATCOM")) + // Work-ardound command line parsing limitations in MSVC 6.0 + if(this->Makefile->IsOn("MSVC60")) { // Search for the last space. std::string::size_type pos = lib.rfind(' '); @@ -1809,9 +1810,11 @@ void cmLocalGenerator::OutputLinkLibraries(std::string& linkLibraries, std::string& linkPath, cmGeneratorTarget &tgt, bool relink, - bool forResponseFile) + bool forResponseFile, + bool useWatcomQuote) { - OutputFormat shellFormat = forResponseFile? RESPONSE : SHELL; + OutputFormat shellFormat = (forResponseFile) ? RESPONSE : + ((useWatcomQuote) ? WATCOMQUOTE : SHELL); bool escapeAllowMakeVars = !forResponseFile; cmOStringStream fout; const char* config = this->Makefile->GetDefinition("CMAKE_BUILD_TYPE"); @@ -2633,7 +2636,7 @@ std::string cmLocalGenerator::ConvertToOutputFormat(const std::string& source, { result = cmSystemTools::ConvertToOutputPath(result.c_str()); } - else if( output == SHELL) + else if(output == SHELL || output == WATCOMQUOTE) { // For the MSYS shell convert drive letters to posix paths, so // that c:/some/path becomes /c/some/path. This is needed to @@ -2655,11 +2658,11 @@ std::string cmLocalGenerator::ConvertToOutputFormat(const std::string& source, pos++; } } - result = this->EscapeForShell(result, true, false); + result = this->EscapeForShell(result, true, false, output == WATCOMQUOTE); } else if(output == RESPONSE) { - result = this->EscapeForShell(result, false, false); + result = this->EscapeForShell(result, false, false, false); } return result; } @@ -3286,7 +3289,8 @@ static bool cmLocalGeneratorIsShellOperator(const std::string& str) //---------------------------------------------------------------------------- std::string cmLocalGenerator::EscapeForShell(const std::string& str, bool makeVars, - bool forEcho) + bool forEcho, + bool useWatcomQuote) { // Do not escape shell operators. if(cmLocalGeneratorIsShellOperator(str)) @@ -3312,6 +3316,10 @@ std::string cmLocalGenerator::EscapeForShell(const std::string& str, { flags |= cmsysSystem_Shell_Flag_EchoWindows; } + if(useWatcomQuote) + { + flags |= cmsysSystem_Shell_Flag_WatcomQuote; + } if(this->WatcomWMake) { flags |= cmsysSystem_Shell_Flag_WatcomWMake; diff --git a/Source/cmLocalGenerator.h b/Source/cmLocalGenerator.h index 12a94e4..cf754aa 100644 --- a/Source/cmLocalGenerator.h +++ b/Source/cmLocalGenerator.h @@ -106,7 +106,7 @@ public: * path setting */ enum RelativeRoot { NONE, FULL, HOME, START, HOME_OUTPUT, START_OUTPUT }; - enum OutputFormat { UNCHANGED, MAKEFILE, SHELL, RESPONSE }; + enum OutputFormat { UNCHANGED, MAKEFILE, SHELL, WATCOMQUOTE, RESPONSE }; std::string ConvertToOutputFormat(const std::string& source, OutputFormat output); std::string Convert(const std::string& remote, RelativeRoot local, @@ -290,7 +290,8 @@ public: escapes for the special case of passing to the native echo command. */ std::string EscapeForShell(const std::string& str, bool makeVars = false, - bool forEcho = false); + bool forEcho = false, + bool useWatcomQuote = false); /** Backwards-compatibility version of EscapeForShell. */ std::string EscapeForShellOldStyle(const std::string& str); @@ -372,7 +373,8 @@ public: std::string& linkFlags, std::string& frameworkPath, std::string& linkPath, - cmGeneratorTarget* target); + cmGeneratorTarget* target, + bool useWatcomQuote); virtual void ComputeObjectFilenames( std::map<cmSourceFile const*, std::string>& mapping, @@ -385,7 +387,8 @@ protected: std::string& linkPath, cmGeneratorTarget &, bool relink, - bool forResponseFile); + bool forResponseFile, + bool useWatcomQuote); // Expand rule variables in CMake of the type found in language rules void ExpandRuleVariables(std::string& string, diff --git a/Source/cmMakefileExecutableTargetGenerator.cxx b/Source/cmMakefileExecutableTargetGenerator.cxx index 701d5a0..fc52ccc 100644 --- a/Source/cmMakefileExecutableTargetGenerator.cxx +++ b/Source/cmMakefileExecutableTargetGenerator.cxx @@ -290,7 +290,6 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink) linkRuleVar += linkLanguage; linkRuleVar += "_LINK_EXECUTABLE"; std::string linkRule = this->GetLinkRule(linkRuleVar); - bool useWatcomQuote = this->Makefile->IsOn(linkRuleVar+"_USE_WATCOM_QUOTE"); std::vector<std::string> commands1; cmSystemTools::ExpandListArgument(linkRule, real_link_commands); if(this->Target->IsExecutableWithExports()) @@ -333,12 +332,15 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink) // Expand the rule variables. { + bool useWatcomQuote = this->Makefile->IsOn(linkRuleVar+"_USE_WATCOM_QUOTE"); + // Set path conversion for link script shells. this->LocalGenerator->SetLinkScriptShell(useLinkScript); // Collect up flags to link in needed libraries. std::string linkLibs; - this->CreateLinkLibs(linkLibs, relink, useResponseFileForLibs, depends); + this->CreateLinkLibs(linkLibs, relink, useResponseFileForLibs, depends, + useWatcomQuote); // Construct object file lists that may be needed to expand the // rule. @@ -357,7 +359,12 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink) cmLocalGenerator::START_OUTPUT, cmLocalGenerator::SHELL); vars.ObjectDir = objectDir.c_str(); - vars.Target = targetOutPathReal.c_str(); + cmLocalGenerator::OutputFormat output = (useWatcomQuote) ? + cmLocalGenerator::WATCOMQUOTE : cmLocalGenerator::SHELL; + std::string target = this->Convert(targetFullPathReal, + cmLocalGenerator::START_OUTPUT, + output); + vars.Target = target.c_str(); vars.TargetPDB = targetOutPathPDB.c_str(); // Setup the target version. diff --git a/Source/cmMakefileLibraryTargetGenerator.cxx b/Source/cmMakefileLibraryTargetGenerator.cxx index 754f62f..7ac0256 100644 --- a/Source/cmMakefileLibraryTargetGenerator.cxx +++ b/Source/cmMakefileLibraryTargetGenerator.cxx @@ -458,8 +458,6 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules this->Target); } - bool useWatcomQuote = this->Makefile->IsOn(linkRuleVar+"_USE_WATCOM_QUOTE"); - // Determine whether a link script will be used. bool useLinkScript = this->GlobalGenerator->GetUseLinkScript(); @@ -541,6 +539,8 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules // Expand the rule variables. std::vector<std::string> real_link_commands; { + bool useWatcomQuote = this->Makefile->IsOn(linkRuleVar+"_USE_WATCOM_QUOTE"); + // Set path conversion for link script shells. this->LocalGenerator->SetLinkScriptShell(useLinkScript); @@ -548,7 +548,8 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules std::string linkLibs; if(this->Target->GetType() != cmTarget::STATIC_LIBRARY) { - this->CreateLinkLibs(linkLibs, relink, useResponseFileForLibs, depends); + this->CreateLinkLibs(linkLibs, relink, useResponseFileForLibs, depends, + useWatcomQuote); } // Construct object file lists that may be needed to expand the @@ -587,7 +588,12 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules cmLocalGenerator::START_OUTPUT, cmLocalGenerator::SHELL); vars.ObjectDir = objectDir.c_str(); - vars.Target = targetOutPathReal.c_str(); + cmLocalGenerator::OutputFormat output = (useWatcomQuote) ? + cmLocalGenerator::WATCOMQUOTE : cmLocalGenerator::SHELL; + std::string target = this->Convert(targetFullPathReal, + cmLocalGenerator::START_OUTPUT, + output); + vars.Target = target.c_str(); vars.LinkLibraries = linkLibs.c_str(); vars.ObjectsQuoted = buildObjs.c_str(); if (this->Target->HasSOName(this->ConfigName)) diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index f940ac4..d4723ad 100644 --- a/Source/cmMakefileTargetGenerator.cxx +++ b/Source/cmMakefileTargetGenerator.cxx @@ -1826,14 +1826,16 @@ void cmMakefileTargetGenerator ::CreateLinkLibs(std::string& linkLibs, bool relink, bool useResponseFile, - std::vector<std::string>& makefile_depends) + std::vector<std::string>& makefile_depends, + bool useWatcomQuote) { std::string frameworkPath; std::string linkPath; this->LocalGenerator ->OutputLinkLibraries(linkLibs, frameworkPath, linkPath, *this->GeneratorTarget, relink, - useResponseFile); + useResponseFile, + useWatcomQuote); linkLibs = frameworkPath + linkPath + linkLibs; if(useResponseFile) diff --git a/Source/cmMakefileTargetGenerator.h b/Source/cmMakefileTargetGenerator.h index ff94660..9fac574 100644 --- a/Source/cmMakefileTargetGenerator.h +++ b/Source/cmMakefileTargetGenerator.h @@ -168,7 +168,8 @@ protected: /** Create list of flags for link libraries. */ void CreateLinkLibs(std::string& linkLibs, bool relink, bool useResponseFile, - std::vector<std::string>& makefile_depends); + std::vector<std::string>& makefile_depends, + bool useWatcomQuote); /** Create lists of object files for linking and cleaning. */ void CreateObjectLists(bool useLinkScript, bool useArchiveRules, diff --git a/Source/cmNinjaNormalTargetGenerator.cxx b/Source/cmNinjaNormalTargetGenerator.cxx index 1d0336a..b467d22 100644 --- a/Source/cmNinjaNormalTargetGenerator.cxx +++ b/Source/cmNinjaNormalTargetGenerator.cxx @@ -232,13 +232,11 @@ cmNinjaNormalTargetGenerator vars.LinkFlags = "$LINK_FLAGS"; std::string langFlags; - if (targetType != cmTarget::EXECUTABLE) { - this->GetLocalGenerator()->AddLanguageFlags(langFlags, - this->TargetLinkLanguage, - this->GetConfigName()); - langFlags += " $ARCH_FLAGS"; + if (targetType != cmTarget::EXECUTABLE) + { + langFlags += "$LANGUAGE_COMPILE_FLAGS $ARCH_FLAGS"; vars.LanguageCompileFlags = langFlags.c_str(); - } + } // Rule for linking library/executable. std::vector<std::string> linkCmds = this->ComputeLinkCmd(); @@ -363,25 +361,39 @@ cmNinjaNormalTargetGenerator return std::vector<std::string>(); } -void cmNinjaNormalTargetGenerator::WriteLinkStatement() + +static int calculateCommandLineLengthLimit(int linkRuleLength) { - cmTarget::TargetType targetType = this->GetTarget()->GetType(); +#ifdef _WIN32 + return 8000 - linkRuleLength; +#elif defined(__linux) || defined(__APPLE__) || defined(__HAIKU__) + // for instance ARG_MAX is 2096152 on Ubuntu or 262144 on Mac + return ((int)sysconf(_SC_ARG_MAX)) - linkRuleLength - 1000; +#else + (void)linkRuleLength; + return -1; +#endif +} + +void cmNinjaNormalTargetGenerator::WriteLinkStatement() +{ + cmTarget& target = *this->GetTarget(); + const std::string cfgName = this->GetConfigName(); std::string targetOutput = ConvertToNinjaPath( - this->GetTarget()->GetFullPath(this->GetConfigName()).c_str()); + target.GetFullPath(cfgName).c_str()); std::string targetOutputReal = ConvertToNinjaPath( - this->GetTarget()->GetFullPath(this->GetConfigName(), - /*implib=*/false, - /*realpath=*/true).c_str()); + target.GetFullPath(cfgName, + /*implib=*/false, + /*realpath=*/true).c_str()); std::string targetOutputImplib = ConvertToNinjaPath( - this->GetTarget()->GetFullPath(this->GetConfigName(), - /*implib=*/true).c_str()); + target.GetFullPath(cfgName, + /*implib=*/true).c_str()); - if (this->GetTarget()->IsAppBundleOnApple()) + if (target.IsAppBundleOnApple()) { // Create the app bundle - std::string outpath = - this->GetTarget()->GetDirectory(this->GetConfigName()); + std::string outpath = target.GetDirectory(cfgName); this->OSXBundleGenerator->CreateAppBundle(this->TargetNameOut, outpath); // Calculate the output path @@ -394,23 +406,22 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement() targetOutputReal += this->TargetNameReal; targetOutputReal = this->ConvertToNinjaPath(targetOutputReal.c_str()); } - else if (this->GetTarget()->IsFrameworkOnApple()) + else if (target.IsFrameworkOnApple()) { // Create the library framework. - std::string outpath = - this->GetTarget()->GetDirectory(this->GetConfigName()); - this->OSXBundleGenerator->CreateFramework(this->TargetNameOut, outpath); + this->OSXBundleGenerator->CreateFramework(this->TargetNameOut, + target.GetDirectory(cfgName)); } - else if(this->GetTarget()->IsCFBundleOnApple()) + else if(target.IsCFBundleOnApple()) { // Create the core foundation bundle. - std::string outpath = - this->GetTarget()->GetDirectory(this->GetConfigName()); - this->OSXBundleGenerator->CreateCFBundle(this->TargetNameOut, outpath); + this->OSXBundleGenerator->CreateCFBundle(this->TargetNameOut, + target.GetDirectory(cfgName)); } // Write comments. cmGlobalNinjaGenerator::WriteDivider(this->GetBuildFileStream()); + const cmTarget::TargetType targetType = target.GetType(); this->GetBuildFileStream() << "# Link build statements for " << cmTarget::GetTargetTypeName(targetType) @@ -423,8 +434,8 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement() // Compute the comment. cmOStringStream comment; - comment << "Link the " << this->GetVisibleTypeName() << " " - << targetOutputReal; + comment << + "Link the " << this->GetVisibleTypeName() << " " << targetOutputReal; // Compute outputs. cmNinjaDeps outputs; @@ -438,15 +449,21 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement() std::string frameworkPath; std::string linkPath; - cmGeneratorTarget* gtarget = this->GetGeneratorTarget(); - this->GetLocalGenerator()->GetTargetFlags(vars["LINK_LIBRARIES"], - vars["FLAGS"], - vars["LINK_FLAGS"], - frameworkPath, - linkPath, - gtarget); - - this->addPoolNinjaVariable("JOB_POOL_LINK", this->GetTarget(), vars); + cmGeneratorTarget& genTarget = *this->GetGeneratorTarget(); + + std::string createRule = "CMAKE_"; + createRule += this->TargetLinkLanguage + genTarget.GetCreateRuleVariable(); + bool useWatcomQuote = mf->IsOn(createRule+"_USE_WATCOM_QUOTE"); + cmLocalNinjaGenerator& localGen = *this->GetLocalGenerator(); + localGen.GetTargetFlags(vars["LINK_LIBRARIES"], + vars["FLAGS"], + vars["LINK_FLAGS"], + frameworkPath, + linkPath, + &genTarget, + useWatcomQuote); + + this->addPoolNinjaVariable("JOB_POOL_LINK", &target, vars); this->AddModuleDefinitionFlag(vars["LINK_FLAGS"]); vars["LINK_FLAGS"] = cmGlobalNinjaGenerator @@ -457,42 +474,47 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement() // Compute architecture specific link flags. Yes, these go into a different // variable for executables, probably due to a mistake made when duplicating // code between the Makefile executable and library generators. - std::string flags = (targetType == cmTarget::EXECUTABLE - ? vars["FLAGS"] - : vars["ARCH_FLAGS"]); - this->GetLocalGenerator()->AddArchitectureFlags(flags, - gtarget, - this->TargetLinkLanguage, - this->GetConfigName()); - if (targetType == cmTarget::EXECUTABLE) { - vars["FLAGS"] = flags; - } else { - vars["ARCH_FLAGS"] = flags; - } - if (this->GetTarget()->HasSOName(this->GetConfigName())) { - vars["SONAME_FLAG"] = - mf->GetSONameFlag(this->TargetLinkLanguage); + if (targetType == cmTarget::EXECUTABLE) + { + std::string t = vars["FLAGS"]; + localGen.AddArchitectureFlags(t, &genTarget, TargetLinkLanguage, cfgName); + vars["FLAGS"] = t; + } + else + { + std::string t = vars["ARCH_FLAGS"]; + localGen.AddArchitectureFlags(t, &genTarget, TargetLinkLanguage, cfgName); + vars["ARCH_FLAGS"] = t; + t = ""; + localGen.AddLanguageFlags(t, TargetLinkLanguage, cfgName); + vars["LANGUAGE_COMPILE_FLAGS"] = t; + } + + if (target.HasSOName(cfgName)) + { + vars["SONAME_FLAG"] = mf->GetSONameFlag(this->TargetLinkLanguage); vars["SONAME"] = this->TargetNameSO; - if (targetType == cmTarget::SHARED_LIBRARY) { - std::string install_name_dir = this->GetTarget() - ->GetInstallNameDirForBuildTree(this->GetConfigName()); - - if (!install_name_dir.empty()) { - vars["INSTALLNAME_DIR"] = - this->GetLocalGenerator()->Convert(install_name_dir, - cmLocalGenerator::NONE, - cmLocalGenerator::SHELL, false); + if (targetType == cmTarget::SHARED_LIBRARY) + { + std::string install_dir = target.GetInstallNameDirForBuildTree(cfgName); + if (!install_dir.empty()) + { + vars["INSTALLNAME_DIR"] = localGen.Convert(install_dir, + cmLocalGenerator::NONE, + cmLocalGenerator::SHELL, + false); + } } } - } - if (!this->TargetNameImport.empty()) { - const std::string impLibPath = this->GetLocalGenerator() - ->ConvertToOutputFormat(targetOutputImplib, - cmLocalGenerator::SHELL); + if (!this->TargetNameImport.empty()) + { + const std::string impLibPath = localGen.ConvertToOutputFormat( + targetOutputImplib, + cmLocalGenerator::SHELL); vars["TARGET_IMPLIB"] = impLibPath; EnsureParentDirectoryExists(impLibPath); - } + } if (!this->SetMsvcTargetPdbVariable(vars)) { @@ -501,11 +523,13 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement() std::string prefix; std::string base; std::string suffix; - this->GetTarget()->GetFullNameComponents(prefix, base, suffix); + target.GetFullNameComponents(prefix, base, suffix); std::string dbg_suffix = ".dbg"; // TODO: Where to document? if (mf->GetDefinition("CMAKE_DEBUG_SYMBOL_SUFFIX")) + { dbg_suffix = mf->GetDefinition("CMAKE_DEBUG_SYMBOL_SUFFIX"); + } vars["TARGET_PDB"] = base + suffix + dbg_suffix; } @@ -517,12 +541,14 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement() // ar.exe can't handle backslashes in rsp files (implicitly used by gcc) std::string& linkLibraries = vars["LINK_LIBRARIES"]; std::replace(linkLibraries.begin(), linkLibraries.end(), '\\', '/'); + std::string& link_path = vars["LINK_PATH"]; + std::replace(link_path.begin(), link_path.end(), '\\', '/'); } const std::vector<cmCustomCommand> *cmdLists[3] = { - &this->GetTarget()->GetPreBuildCommands(), - &this->GetTarget()->GetPreLinkCommands(), - &this->GetTarget()->GetPostBuildCommands() + &target.GetPreBuildCommands(), + &target.GetPreLinkCommands(), + &target.GetPostBuildCommands() }; std::vector<std::string> preLinkCmdLines, postBuildCmdLines; @@ -532,100 +558,97 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement() &postBuildCmdLines }; - for (unsigned i = 0; i != 3; ++i) { + for (unsigned i = 0; i != 3; ++i) + { for (std::vector<cmCustomCommand>::const_iterator ci = cmdLists[i]->begin(); - ci != cmdLists[i]->end(); ++ci) { - cmCustomCommandGenerator ccg(*ci, this->GetConfigName(), mf); - this->GetLocalGenerator()->AppendCustomCommandLines(ccg, - *cmdLineLists[i]); + ci != cmdLists[i]->end(); ++ci) + { + cmCustomCommandGenerator ccg(*ci, cfgName, mf); + localGen.AppendCustomCommandLines(ccg, *cmdLineLists[i]); + } } - } // If we have any PRE_LINK commands, we need to go back to HOME_OUTPUT for // the link commands. - if (!preLinkCmdLines.empty()) { - const std::string homeOutDir = this->GetLocalGenerator() - ->ConvertToOutputFormat(mf->GetHomeOutputDirectory(), - cmLocalGenerator::SHELL); + if (!preLinkCmdLines.empty()) + { + const std::string homeOutDir = localGen.ConvertToOutputFormat( + mf->GetHomeOutputDirectory(), + cmLocalGenerator::SHELL); preLinkCmdLines.push_back("cd " + homeOutDir); - } + } - vars["PRE_LINK"] = - this->GetLocalGenerator()->BuildCommandLine(preLinkCmdLines); - std::string postBuildCmdLine = - this->GetLocalGenerator()->BuildCommandLine(postBuildCmdLines); + vars["PRE_LINK"] = localGen.BuildCommandLine(preLinkCmdLines); + std::string postBuildCmdLine = localGen.BuildCommandLine(postBuildCmdLines); cmNinjaVars symlinkVars; - if (targetOutput == targetOutputReal) { + if (targetOutput == targetOutputReal) + { vars["POST_BUILD"] = postBuildCmdLine; - } else { + } + else + { vars["POST_BUILD"] = ":"; symlinkVars["POST_BUILD"] = postBuildCmdLine; - } + } - int linkRuleLength = this->GetGlobalGenerator()-> - GetRuleCmdLength(this->LanguageLinkerRule()); + cmGlobalNinjaGenerator& globalGen = *this->GetGlobalGenerator(); int commandLineLengthLimit = 1; const char* forceRspFile = "CMAKE_NINJA_FORCE_RESPONSE_FILE"; if (!mf->IsDefinitionSet(forceRspFile) && - cmSystemTools::GetEnv(forceRspFile) == 0) { -#ifdef _WIN32 - commandLineLengthLimit = 8000 - linkRuleLength; -#elif defined(__linux) || defined(__APPLE__) || defined(__HAIKU__) - // for instance ARG_MAX is 2096152 on Ubuntu or 262144 on Mac - commandLineLengthLimit = ((int)sysconf(_SC_ARG_MAX))-linkRuleLength-1000; -#else - (void)linkRuleLength; - commandLineLengthLimit = -1; -#endif - } - - //Get the global generator as we are going to be call WriteBuild numerous - //times in the following section - cmGlobalNinjaGenerator* globalGenerator = this->GetGlobalGenerator(); - + cmSystemTools::GetEnv(forceRspFile) == 0) + { + commandLineLengthLimit = calculateCommandLineLengthLimit( + globalGen.GetRuleCmdLength(this->LanguageLinkerRule())); + } - const std::string rspfile = std::string - (cmake::GetCMakeFilesDirectoryPostSlash()) + - this->GetTarget()->GetName() + ".rsp"; + const std::string rspfile = + std::string(cmake::GetCMakeFilesDirectoryPostSlash()) + + target.GetName() + ".rsp"; // Write the build statement for this target. - globalGenerator->WriteBuild(this->GetBuildFileStream(), - comment.str(), - this->LanguageLinkerRule(), - outputs, - explicitDeps, - implicitDeps, - emptyDeps, - vars, - rspfile, - commandLineLengthLimit); - - if (targetOutput != targetOutputReal && - !this->GetTarget()->IsFrameworkOnApple()) { - if (targetType == cmTarget::EXECUTABLE) { - globalGenerator->WriteBuild(this->GetBuildFileStream(), - "Create executable symlink " + targetOutput, - "CMAKE_SYMLINK_EXECUTABLE", - cmNinjaDeps(1, targetOutput), - cmNinjaDeps(1, targetOutputReal), - emptyDeps, - emptyDeps, - symlinkVars); - } else { + globalGen.WriteBuild(this->GetBuildFileStream(), + comment.str(), + this->LanguageLinkerRule(), + outputs, + explicitDeps, + implicitDeps, + emptyDeps, + vars, + rspfile, + commandLineLengthLimit); + + if (targetOutput != targetOutputReal && !target.IsFrameworkOnApple()) + { + if (targetType == cmTarget::EXECUTABLE) + { + globalGen.WriteBuild(this->GetBuildFileStream(), + "Create executable symlink " + targetOutput, + "CMAKE_SYMLINK_EXECUTABLE", + cmNinjaDeps(1, targetOutput), + cmNinjaDeps(1, targetOutputReal), + emptyDeps, + emptyDeps, + symlinkVars); + } + else + { cmNinjaDeps symlinks; const std::string soName = this->GetTargetFilePath(this->TargetNameSO); // If one link has to be created. - if (targetOutputReal == soName || targetOutput == soName) { + if (targetOutputReal == soName || targetOutput == soName) + { symlinkVars["SONAME"] = soName; - } else { + } + else + { symlinkVars["SONAME"] = ""; symlinks.push_back(soName); - } + } symlinks.push_back(targetOutput); - globalGenerator->WriteBuild(this->GetBuildFileStream(), + globalGen.WriteBuild(this->GetBuildFileStream(), "Create library symlink " + targetOutput, "CMAKE_SYMLINK_LIBRARY", symlinks, @@ -633,23 +656,22 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement() emptyDeps, emptyDeps, symlinkVars); + } } - } - if (!this->TargetNameImport.empty()) { + if (!this->TargetNameImport.empty()) + { // Since using multiple outputs would mess up the $out variable, use an // alias for the import library. - globalGenerator->WritePhonyBuild(this->GetBuildFileStream(), - "Alias for import library.", - cmNinjaDeps(1, targetOutputImplib), - cmNinjaDeps(1, targetOutputReal)); - } + globalGen.WritePhonyBuild(this->GetBuildFileStream(), + "Alias for import library.", + cmNinjaDeps(1, targetOutputImplib), + cmNinjaDeps(1, targetOutputReal)); + } // Add aliases for the file name and the target name. - globalGenerator->AddTargetAlias(this->TargetNameOut, - this->GetTarget()); - globalGenerator->AddTargetAlias(this->GetTargetName(), - this->GetTarget()); + globalGen.AddTargetAlias(this->TargetNameOut, &target); + globalGen.AddTargetAlias(this->GetTargetName(), &target); } //---------------------------------------------------------------------------- diff --git a/Source/cmPolicies.cxx b/Source/cmPolicies.cxx index 759df91..309f280 100644 --- a/Source/cmPolicies.cxx +++ b/Source/cmPolicies.cxx @@ -348,6 +348,12 @@ cmPolicies::cmPolicies() CMP0051, "CMP0051", "List TARGET_OBJECTS in SOURCES target property.", 3,1,0, cmPolicies::WARN); + + this->DefinePolicy( + CMP0052, "CMP0052", + "Reject source and build dirs in installed " + "INTERFACE_INCLUDE_DIRECTORIES.", + 3,1,0, cmPolicies::WARN); } cmPolicies::~cmPolicies() diff --git a/Source/cmPolicies.h b/Source/cmPolicies.h index 7a08a34..60f35c2 100644 --- a/Source/cmPolicies.h +++ b/Source/cmPolicies.h @@ -105,6 +105,8 @@ public: CMP0049, ///< Do not expand variables in target source entries CMP0050, ///< Disallow add_custom_command SOURCE signatures CMP0051, ///< List TARGET_OBJECTS in SOURCES target property + CMP0052, ///< Reject source and build dirs in installed + /// INTERFACE_INCLUDE_DIRECTORIES /** \brief Always the last entry. * diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx index c1c33f2..c27b561 100644 --- a/Source/cmSystemTools.cxx +++ b/Source/cmSystemTools.cxx @@ -1616,8 +1616,8 @@ long copy_data(struct archive *ar, struct archive *aw) return (r); } } -#if !defined(__clang__) - return r; /* this should not happen but it silences a warning */ +#if !defined(__clang__) && !defined(__HP_aCC) + return r; /* this should not happen but it quiets some compilers */ #endif } diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index 1d4d84c..ee6cb44 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -235,6 +235,7 @@ cmTarget::cmTarget() this->DebugCompileFeaturesDone = false; this->DebugCompileDefinitionsDone = false; this->DebugSourcesDone = false; + this->LinkImplementationLanguageIsContextDependent = true; } //---------------------------------------------------------------------------- @@ -469,6 +470,7 @@ void cmTarget::FinishConfigure() //---------------------------------------------------------------------------- void cmTarget::ClearLinkMaps() { + this->LinkImplementationLanguageIsContextDependent = true; this->Internal->LinkImplMap.clear(); this->Internal->LinkInterfaceMap.clear(); this->Internal->LinkClosureMap.clear(); @@ -560,7 +562,7 @@ bool cmTarget::IsBundleOnApple() const } //---------------------------------------------------------------------------- -static void processSources(cmTarget const* tgt, +static bool processSources(cmTarget const* tgt, const std::vector<cmTargetInternals::TargetPropertyEntry*> &entries, std::vector<std::string> &srcs, std::set<std::string> &uniqueSrcs, @@ -570,6 +572,8 @@ static void processSources(cmTarget const* tgt, { cmMakefile *mf = tgt->GetMakefile(); + bool contextDependent = false; + for (std::vector<cmTargetInternals::TargetPropertyEntry*>::const_iterator it = entries.begin(), end = entries.end(); it != end; ++it) { @@ -584,8 +588,12 @@ static void processSources(cmTarget const* tgt, tgt, dagChecker), entrySources); - if (mf->IsGeneratingBuildSystem() - && !(*it)->ge->GetHadContextSensitiveCondition()) + + if ((*it)->ge->GetHadContextSensitiveCondition()) + { + contextDependent = true; + } + else if (mf->IsGeneratingBuildSystem()) { cacheSources = true; } @@ -606,7 +614,7 @@ static void processSources(cmTarget const* tgt, cm->IssueMessage(cmake::FATAL_ERROR, e, tgt->GetBacktrace()); } - return; + return contextDependent; } } if (cacheSources) @@ -637,6 +645,7 @@ static void processSources(cmTarget const* tgt, + usedSources, (*it)->ge->GetBacktrace()); } } + return contextDependent; } //---------------------------------------------------------------------------- @@ -646,6 +655,38 @@ void cmTarget::GetSourceFiles(std::vector<std::string> &files, { assert(this->GetType() != INTERFACE_LIBRARY); + if (this->Makefile->GetGeneratorTargets().empty()) + { + // At configure-time, this method can be called as part of getting the + // LOCATION property or to export() a file to be include()d. However + // there is no cmGeneratorTarget at configure-time, so search the SOURCES + // for TARGET_OBJECTS instead for backwards compatibility with OLD + // behavior of CMP0024 and CMP0026 only. + + typedef cmTargetInternals::TargetPropertyEntry + TargetPropertyEntry; + for(std::vector<TargetPropertyEntry*>::const_iterator + i = this->Internal->SourceEntries.begin(); + i != this->Internal->SourceEntries.end(); ++i) + { + std::string entry = (*i)->ge->GetInput(); + + std::vector<std::string> items; + cmSystemTools::ExpandListArgument(entry, items); + for (std::vector<std::string>::const_iterator + li = items.begin(); li != items.end(); ++li) + { + if(cmHasLiteralPrefix(*li, "$<TARGET_OBJECTS:") && + (*li)[li->size() - 1] == '>') + { + continue; + } + files.push_back(*li); + } + } + return; + } + std::vector<std::string> debugProperties; const char *debugProp = this->Makefile->GetDefinition("CMAKE_DEBUG_TARGET_PROPERTIES"); @@ -672,7 +713,7 @@ void cmTarget::GetSourceFiles(std::vector<std::string> &files, "SOURCES", 0, 0); std::set<std::string> uniqueSrcs; - processSources(this, + bool contextDependentDirectSources = processSources(this, this->Internal->SourceEntries, files, uniqueSrcs, @@ -724,7 +765,8 @@ void cmTarget::GetSourceFiles(std::vector<std::string> &files, } } - processSources(this, + std::vector<std::string>::size_type numFilesBefore = files.size(); + bool contextDependentInterfaceSources = processSources(this, this->Internal->CachedLinkInterfaceSourcesEntries[config], files, uniqueSrcs, @@ -733,6 +775,12 @@ void cmTarget::GetSourceFiles(std::vector<std::string> &files, config, debugSources); + if (!contextDependentDirectSources + && !(contextDependentInterfaceSources && numFilesBefore < files.size())) + { + this->LinkImplementationLanguageIsContextDependent = false; + } + if (!this->Makefile->IsGeneratingBuildSystem()) { deleteAndClear(this->Internal->CachedLinkInterfaceSourcesEntries); @@ -809,6 +857,12 @@ void cmTarget::GetSourceFiles(std::vector<cmSourceFile*> &files, // Lookup any existing link implementation for this configuration. TargetConfigPair key(head, cmSystemTools::UpperCase(config)); + if(!this->LinkImplementationLanguageIsContextDependent) + { + files = this->Internal->SourceFilesMap.begin()->second; + return; + } + cmTargetInternals::SourceFilesMapType::iterator it = this->Internal->SourceFilesMap.find(key); if(it != this->Internal->SourceFilesMap.end()) @@ -836,6 +890,33 @@ void cmTarget::GetSourceFiles(std::vector<cmSourceFile*> &files, } //---------------------------------------------------------------------------- +void cmTarget::AddTracedSources(std::vector<std::string> const& srcs) +{ + std::string srcFiles; + const char* sep = ""; + for(std::vector<std::string>::const_iterator i = srcs.begin(); + i != srcs.end(); ++i) + { + std::string filename = *i; + srcFiles += sep; + srcFiles += filename; + sep = ";"; + } + if (!srcFiles.empty()) + { + this->Internal->SourceFilesMap.clear(); + this->LinkImplementationLanguageIsContextDependent = true; + cmListFileBacktrace lfbt; + this->Makefile->GetBacktrace(lfbt); + cmGeneratorExpression ge(lfbt); + cmsys::auto_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(srcFiles); + cge->SetEvaluateForBuildsystem(true); + this->Internal->SourceEntries.push_back( + new cmTargetInternals::TargetPropertyEntry(cge)); + } +} + +//---------------------------------------------------------------------------- void cmTarget::AddSources(std::vector<std::string> const& srcs) { std::string srcFiles; @@ -862,6 +943,7 @@ void cmTarget::AddSources(std::vector<std::string> const& srcs) if (!srcFiles.empty()) { this->Internal->SourceFilesMap.clear(); + this->LinkImplementationLanguageIsContextDependent = true; cmListFileBacktrace lfbt; this->Makefile->GetBacktrace(lfbt); cmGeneratorExpression ge(lfbt); @@ -997,6 +1079,7 @@ cmSourceFile* cmTarget::AddSource(const std::string& src) == this->Internal->SourceEntries.end()) { this->Internal->SourceFilesMap.clear(); + this->LinkImplementationLanguageIsContextDependent = true; cmListFileBacktrace lfbt; this->Makefile->GetBacktrace(lfbt); cmGeneratorExpression ge(lfbt); @@ -5450,6 +5533,45 @@ bool cmTarget::IsLinkInterfaceDependentNumberMaxProperty(const std::string &p, } //---------------------------------------------------------------------------- +void +cmTarget::GetObjectLibrariesCMP0026(std::vector<cmTarget*>& objlibs) const +{ + // At configure-time, this method can be called as part of getting the + // LOCATION property or to export() a file to be include()d. However + // there is no cmGeneratorTarget at configure-time, so search the SOURCES + // for TARGET_OBJECTS instead for backwards compatibility with OLD + // behavior of CMP0024 and CMP0026 only. + typedef cmTargetInternals::TargetPropertyEntry + TargetPropertyEntry; + for(std::vector<TargetPropertyEntry*>::const_iterator + i = this->Internal->SourceEntries.begin(); + i != this->Internal->SourceEntries.end(); ++i) + { + std::string entry = (*i)->ge->GetInput(); + + std::vector<std::string> files; + cmSystemTools::ExpandListArgument(entry, files); + for (std::vector<std::string>::const_iterator + li = files.begin(); li != files.end(); ++li) + { + if(cmHasLiteralPrefix(*li, "$<TARGET_OBJECTS:") && + (*li)[li->size() - 1] == '>') + { + std::string objLibName = li->substr(17, li->size()-18); + + if (cmGeneratorExpression::Find(objLibName) != std::string::npos) + { + continue; + } + cmTarget *objLib = this->Makefile->FindTargetToUse(objLibName.c_str()); + assert(objLib); + objlibs.push_back(objLib); + } + } + } +} + +//---------------------------------------------------------------------------- void cmTarget::GetLanguages(std::set<std::string>& languages, const std::string& config, cmTarget const* head) const @@ -5470,26 +5592,7 @@ void cmTarget::GetLanguages(std::set<std::string>& languages, std::vector<cmSourceFile const*> externalObjects; if (this->Makefile->GetGeneratorTargets().empty()) { - // At configure-time, this method can be called as part of getting the - // LOCATION property or to export() a file to be include()d. However - // there is no cmGeneratorTarget at configure-time, so search the SOURCES - // for TARGET_OBJECTS instead for backwards compatibility with OLD - // behavior of CMP0024 and CMP0026 only. - std::vector<std::string> srcs; - cmSystemTools::ExpandListArgument(this->GetProperty("SOURCES"), srcs); - for(std::vector<std::string>::const_iterator it = srcs.begin(); - it != srcs.end(); ++it) - { - if (cmHasLiteralPrefix(*it, "$<TARGET_OBJECTS:") - && cmHasLiteralSuffix(*it, ">")) - { - std::string objLibName = it->substr(17, it->size()-18); - if (cmTarget* tgt = this->Makefile->FindTargetToUse(objLibName)) - { - objectLibraries.push_back(tgt); - } - } - } + this->GetObjectLibrariesCMP0026(objectLibraries); } else { diff --git a/Source/cmTarget.h b/Source/cmTarget.h index 8984649..4d8022e 100644 --- a/Source/cmTarget.h +++ b/Source/cmTarget.h @@ -30,7 +30,8 @@ F(CMP0038) \ F(CMP0041) \ F(CMP0042) \ - F(CMP0046) + F(CMP0046) \ + F(CMP0052) class cmake; class cmMakefile; @@ -144,6 +145,7 @@ public: * Add sources to the target. */ void AddSources(std::vector<std::string> const& srcs); + void AddTracedSources(std::vector<std::string> const& srcs); cmSourceFile* AddSourceCMP0049(const std::string& src); cmSourceFile* AddSource(const std::string& src); @@ -239,6 +241,8 @@ public: bool IsImported() const {return this->IsImportedTarget;} + void GetObjectLibrariesCMP0026(std::vector<cmTarget*>& objlibs) const; + /** The link interface specifies transitive library dependencies and other information needed by targets that link to this target. */ struct LinkInterface @@ -787,6 +791,8 @@ private: std::string const& suffix, std::string const& name, const char* version) const; + + mutable bool LinkImplementationLanguageIsContextDependent; }; typedef std::map<std::string,cmTarget> cmTargets; diff --git a/Source/cmake.cxx b/Source/cmake.cxx index 2cf636c..71ea3f5 100644 --- a/Source/cmake.cxx +++ b/Source/cmake.cxx @@ -600,7 +600,7 @@ bool cmake::FindPackage(const std::vector<std::string>& args) gg->CreateGeneratorTargets(mf); cmGeneratorTarget *gtgt = gg->GetGeneratorTarget(tgt); lg->GetTargetFlags(linkLibs, frameworkPath, linkPath, flags, linkFlags, - gtgt); + gtgt, false); linkLibs = frameworkPath + linkPath + linkLibs; printf("%s\n", linkLibs.c_str() ); diff --git a/Source/kwsys/CMakeLists.txt b/Source/kwsys/CMakeLists.txt index 977d57b..5e6a226 100644 --- a/Source/kwsys/CMakeLists.txt +++ b/Source/kwsys/CMakeLists.txt @@ -299,6 +299,13 @@ IF(NOT CMAKE_COMPILER_IS_GNUCXX) ENDIF(CMAKE_SYSTEM MATCHES "OSF1-V.*") IF(CMAKE_SYSTEM MATCHES "HP-UX") SET(KWSYS_PLATFORM_CXX_TEST_EXTRA_FLAGS "+p") + IF(CMAKE_CXX_COMPILER_ID MATCHES "HP") + # it is known that version 3.85 fails and 6.25 works without these flags + IF(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4) + # use new C++ library and improved template support + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -AA +hpxstd98") + ENDIF() + ENDIF() ENDIF(CMAKE_SYSTEM MATCHES "HP-UX") ENDIF(NOT CMAKE_COMPILER_IS_GNUCXX) diff --git a/Source/kwsys/MD5.c b/Source/kwsys/MD5.c index 56776a3..a147057 100644 --- a/Source/kwsys/MD5.c +++ b/Source/kwsys/MD5.c @@ -478,11 +478,16 @@ void kwsysMD5_Initialize(kwsysMD5* md5) /*--------------------------------------------------------------------------*/ void kwsysMD5_Append(kwsysMD5* md5, unsigned char const* data, int length) { + size_t dlen; if(length < 0) { - length = (int)strlen((char const*)data); + dlen = strlen((char const*)data); } - md5_append(&md5->md5_state, (md5_byte_t const*)data, (size_t)length); + else + { + dlen = (size_t)length; + } + md5_append(&md5->md5_state, (md5_byte_t const*)data, dlen); } /*--------------------------------------------------------------------------*/ diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt index c1d5cde..12bd3b2 100644 --- a/Tests/CMakeLists.txt +++ b/Tests/CMakeLists.txt @@ -816,7 +816,7 @@ ${CMake_BINARY_DIR}/bin/cmake -DDIR=dev -P ${CMake_SOURCE_DIR}/Utilities/Release set(CTEST_package_X11_TEST ${CTEST_TEST_CPACK}) set(CTEST_RUN_CPackComponentsForAll ${CTEST_TEST_CPACK}) - if (CMAKE_SYSTEM_NAME MATCHES "Linux" AND NOT CMAKE_CURRENT_BINARY_DIR MATCHES ".* .*") + if (CMAKE_SYSTEM_NAME MATCHES "Linux" AND NOT CMAKE_CURRENT_BINARY_DIR MATCHES " ") find_program(RPMBUILD NAMES rpmbuild) endif() # Do not try to build RPM @@ -917,7 +917,7 @@ ${CMake_BINARY_DIR}/bin/cmake -DDIR=dev -P ${CMake_SOURCE_DIR}/Utilities/Release if(APPLE) list(APPEND GENLST "DragNDrop") endif() - if (NOT CMAKE_CURRENT_BINARY_DIR MATCHES ".* .*") + if (NOT CMAKE_CURRENT_BINARY_DIR MATCHES " ") list(FIND ACTIVE_CPACK_GENERATORS "RPM" RPM_ACTIVE) if (NOT ${RPM_ACTIVE} EQUAL -1) list(APPEND GENLST "RPM") diff --git a/Tests/CMakeTests/CheckCMakeTest.cmake b/Tests/CMakeTests/CheckCMakeTest.cmake index 7be7b30..1565394 100644 --- a/Tests/CMakeTests/CheckCMakeTest.cmake +++ b/Tests/CMakeTests/CheckCMakeTest.cmake @@ -9,8 +9,8 @@ function(check_cmake_test_single prefix test testfile) ERROR_VARIABLE stderr RESULT_VARIABLE result ) - string(REGEX REPLACE "\n" "\n out> " out " out> ${stdout}") - string(REGEX REPLACE "\n" "\n err> " err " err> ${stderr}") + string(REPLACE "\n" "\n out> " out " out> ${stdout}") + string(REPLACE "\n" "\n err> " err " err> ${stderr}") if(NOT "${result}" STREQUAL "${${test}-RESULT}") message(FATAL_ERROR "Test ${test} result is [${result}], not [${${test}-RESULT}].\n" diff --git a/Tests/CMakeTests/ExecuteScriptTests.cmake b/Tests/CMakeTests/ExecuteScriptTests.cmake index c71585a..bceac33 100644 --- a/Tests/CMakeTests/ExecuteScriptTests.cmake +++ b/Tests/CMakeTests/ExecuteScriptTests.cmake @@ -52,9 +52,9 @@ function(execute_all_script_tests scriptname result) foreach(line ${script}) if(line MATCHES "${regex}") + set(testname "${CMAKE_MATCH_2}") + set(expected_result "${CMAKE_MATCH_3}") math(EXPR count "${count} + 1") - string(REGEX REPLACE "${regex}" "\\2" testname "${line}") - string(REGEX REPLACE "${regex}" "\\3" expected_result "${line}") execute_one_script_test(${scriptname} ${testname} ${expected_result}) endif() endforeach() diff --git a/Tests/CTestUpdateCommon.cmake b/Tests/CTestUpdateCommon.cmake index 642a618..857c6f5 100644 --- a/Tests/CTestUpdateCommon.cmake +++ b/Tests/CTestUpdateCommon.cmake @@ -9,7 +9,7 @@ function(run_child) ERROR_STRIP_TRAILING_WHITESPACE ) if(FAILED) - string(REGEX REPLACE "\n" "\n " OUTPUT "${OUTPUT}") + string(REPLACE "\n" "\n " OUTPUT "${OUTPUT}") message(FATAL_ERROR "Child failed (${FAILED}), output is\n ${OUTPUT}\n" "Command = [${ARGN}]\n") endif() @@ -108,7 +108,7 @@ function(check_updates build) ${TOP}/${build}/Testing/Temporary/LastUpdate*.log) if(UPDATE_LOG_FILE) file(READ ${UPDATE_LOG_FILE} UPDATE_LOG LIMIT ${max_update_xml_size}) - string(REGEX REPLACE "\n" "\n " UPDATE_LOG "${UPDATE_LOG}") + string(REPLACE "\n" "\n " UPDATE_LOG "${UPDATE_LOG}") set(MSG "${MSG}Update log:\n ${UPDATE_LOG}") else() set(MSG "${MSG}No update log found!") diff --git a/Tests/Complex/CMakeLists.txt b/Tests/Complex/CMakeLists.txt index fcde44d..d250f53 100644 --- a/Tests/Complex/CMakeLists.txt +++ b/Tests/Complex/CMakeLists.txt @@ -36,7 +36,7 @@ ASSERT(Complex_BINARY_DIR "The PROJECT command is broken") # macro(TEST_ARGC value1 value2) add_definitions(${value1} ${value2}) - if (${ARGC} MATCHES 4) + if (${ARGC} EQUAL 4) add_definitions(${ARGV2} ${ARGV3}) endif () endmacro() @@ -70,7 +70,7 @@ if(NOT 2.4 EQUAL 2.4) message(FATAL_ERROR "Failed: NOT 2.4 EQUAL 2.4") endif() -if(CMAKE_SYSTEM MATCHES "OSF1-V.*") +if(CMAKE_SYSTEM MATCHES "OSF1-V") if(NOT CMAKE_COMPILER_IS_GNUCXX) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -timplicit_local -no_implicit_include ") endif() diff --git a/Tests/ComplexOneConfig/CMakeLists.txt b/Tests/ComplexOneConfig/CMakeLists.txt index a4a0e0e..bb00341 100644 --- a/Tests/ComplexOneConfig/CMakeLists.txt +++ b/Tests/ComplexOneConfig/CMakeLists.txt @@ -36,7 +36,7 @@ ASSERT(Complex_BINARY_DIR "The PROJECT command is broken") # macro(TEST_ARGC value1 value2) add_definitions(${value1} ${value2}) - if (${ARGC} MATCHES 4) + if (${ARGC} EQUAL 4) add_definitions(${ARGV2} ${ARGV3}) endif () endmacro() @@ -70,7 +70,7 @@ if(NOT 2.4 EQUAL 2.4) message(FATAL_ERROR "Failed: NOT 2.4 EQUAL 2.4") endif() -if(CMAKE_SYSTEM MATCHES "OSF1-V.*") +if(CMAKE_SYSTEM MATCHES "OSF1-V") if(NOT CMAKE_COMPILER_IS_GNUCXX) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -timplicit_local -no_implicit_include ") endif() diff --git a/Tests/CustomCommand/CMakeLists.txt b/Tests/CustomCommand/CMakeLists.txt index a194a5f..e0854ce 100644 --- a/Tests/CustomCommand/CMakeLists.txt +++ b/Tests/CustomCommand/CMakeLists.txt @@ -367,8 +367,8 @@ endif() foreach(arg ${CHECK_ARGS} "") set(ARG "${arg}") - string(REGEX REPLACE "\\\\" "\\\\\\\\" ARG "${ARG}") - string(REGEX REPLACE "\"" "\\\\\"" ARG "${ARG}") + string(REPLACE "\\" "\\\\" ARG "${ARG}") + string(REPLACE "\"" "\\\"" ARG "${ARG}") set(EXPECTED_ARGUMENTS "${EXPECTED_ARGUMENTS} \"${ARG}\", ") diff --git a/Tests/FindPackageModeMakefileTest/CMakeLists.txt b/Tests/FindPackageModeMakefileTest/CMakeLists.txt index 5d1b376..8e21c32 100644 --- a/Tests/FindPackageModeMakefileTest/CMakeLists.txt +++ b/Tests/FindPackageModeMakefileTest/CMakeLists.txt @@ -10,7 +10,7 @@ if(UNIX AND "${CMAKE_GENERATOR}" MATCHES "Makefile") ERROR_QUIET TIMEOUT 10) string(TOUPPER "${makeVersionOutput}" MAKE_VERSION_OUTPUT) - if("${MAKE_VERSION_OUTPUT}" MATCHES ".*GNU MAKE.*") + if("${MAKE_VERSION_OUTPUT}" MATCHES "GNU MAKE") # build a library which we can search during the test add_library(foo STATIC foo.cpp) diff --git a/Tests/PerConfig/perconfig.cmake b/Tests/PerConfig/perconfig.cmake index 6a710ca..0731041 100644 --- a/Tests/PerConfig/perconfig.cmake +++ b/Tests/PerConfig/perconfig.cmake @@ -30,7 +30,7 @@ endif() # Verify that the implementation files are named correctly. foreach(lib pcStatic pcShared) file(STRINGS "${${lib}_file}" info LIMIT_COUNT 1 REGEX "INFO:[^[]*\\[") - if(NOT "${info}" MATCHES ".*INFO:symbol\\[${lib}\\].*") + if(NOT "${info}" MATCHES "INFO:symbol\\[${lib}\\]") message(SEND_ERROR "No INFO:symbol[${lib}] found in:\n ${${lib}_file}") endif() endforeach() diff --git a/Tests/RunCMake/RunCMake.cmake b/Tests/RunCMake/RunCMake.cmake index ed3afc5..4ed2f43 100644 --- a/Tests/RunCMake/RunCMake.cmake +++ b/Tests/RunCMake/RunCMake.cmake @@ -25,7 +25,9 @@ function(run_cmake test) unset(expect_std${o}) endif() endforeach() - set(RunCMake_TEST_SOURCE_DIR "${top_src}") + if (NOT RunCMake_TEST_SOURCE_DIR) + set(RunCMake_TEST_SOURCE_DIR "${top_src}") + endif() if(NOT RunCMake_TEST_BINARY_DIR) set(RunCMake_TEST_BINARY_DIR "${top_bin}/${test}-build") endif() @@ -36,6 +38,9 @@ function(run_cmake test) if(NOT DEFINED RunCMake_TEST_OPTIONS) set(RunCMake_TEST_OPTIONS "") endif() + if (NOT RunCMake_TEST_FILE) + set(RunCMake_TEST_FILE "${test}") + endif() if(APPLE) list(APPEND RunCMake_TEST_OPTIONS -DCMAKE_POLICY_DEFAULT_CMP0025=NEW) endif() @@ -52,7 +57,7 @@ function(run_cmake test) COMMAND ${CMAKE_COMMAND} "${RunCMake_TEST_SOURCE_DIR}" -G "${RunCMake_GENERATOR}" -T "${RunCMake_GENERATOR_TOOLSET}" - -DRunCMake_TEST=${test} + -DRunCMake_TEST=${RunCMake_TEST_FILE} --no-warn-unused-cli ${RunCMake_TEST_OPTIONS} WORKING_DIRECTORY "${RunCMake_TEST_BINARY_DIR}" diff --git a/Tests/RunCMake/TargetPolicies/PolicyList-stderr.txt b/Tests/RunCMake/TargetPolicies/PolicyList-stderr.txt index f30c9a9..f4b744b 100644 --- a/Tests/RunCMake/TargetPolicies/PolicyList-stderr.txt +++ b/Tests/RunCMake/TargetPolicies/PolicyList-stderr.txt @@ -16,6 +16,7 @@ \* CMP0041 \* CMP0042 \* CMP0046 + \* CMP0052 Call Stack \(most recent call first\): CMakeLists.txt:3 \(include\) diff --git a/Tests/RunCMake/set/PARENT_SCOPE-result.txt b/Tests/RunCMake/TargetSources/CMP0026-LOCATION-result.txt index 573541a..573541a 100644 --- a/Tests/RunCMake/set/PARENT_SCOPE-result.txt +++ b/Tests/RunCMake/TargetSources/CMP0026-LOCATION-result.txt diff --git a/Tests/RunCMake/TargetSources/CMP0026-LOCATION-stderr.txt b/Tests/RunCMake/TargetSources/CMP0026-LOCATION-stderr.txt new file mode 100644 index 0000000..10f3293 --- /dev/null +++ b/Tests/RunCMake/TargetSources/CMP0026-LOCATION-stderr.txt @@ -0,0 +1 @@ +^$ diff --git a/Tests/RunCMake/TargetSources/CMP0026-LOCATION.cmake b/Tests/RunCMake/TargetSources/CMP0026-LOCATION.cmake new file mode 100644 index 0000000..464df36 --- /dev/null +++ b/Tests/RunCMake/TargetSources/CMP0026-LOCATION.cmake @@ -0,0 +1,13 @@ + +cmake_policy(SET CMP0026 OLD) + +add_library(objlib OBJECT + empty_1.cpp +) + +add_executable(my_exe + empty_2.cpp + $<TARGET_OBJECTS:objlib> +) + +get_target_property( loc my_exe LOCATION) diff --git a/Tests/RunCMake/TargetSources/CMakeLists.txt b/Tests/RunCMake/TargetSources/CMakeLists.txt index 12cd3c7..f452db1 100644 --- a/Tests/RunCMake/TargetSources/CMakeLists.txt +++ b/Tests/RunCMake/TargetSources/CMakeLists.txt @@ -1,3 +1,3 @@ cmake_minimum_required(VERSION 2.8.4) -project(${RunCMake_TEST} NONE) +project(${RunCMake_TEST} CXX) include(${RunCMake_TEST}.cmake) diff --git a/Tests/RunCMake/TargetSources/RunCMakeTest.cmake b/Tests/RunCMake/TargetSources/RunCMakeTest.cmake index b9095f9..01e505c 100644 --- a/Tests/RunCMake/TargetSources/RunCMakeTest.cmake +++ b/Tests/RunCMake/TargetSources/RunCMakeTest.cmake @@ -7,3 +7,5 @@ if(RunCMake_GENERATOR MATCHES Xcode else() run_cmake(OriginDebug) endif() + +run_cmake(CMP0026-LOCATION) diff --git a/Tests/RunCMake/include_directories/BinInInstallPrefix-CMP0052-NEW-result.txt b/Tests/RunCMake/include_directories/BinInInstallPrefix-CMP0052-NEW-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/include_directories/BinInInstallPrefix-CMP0052-NEW-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/include_directories/BinInInstallPrefix-CMP0052-NEW-stderr.txt b/Tests/RunCMake/include_directories/BinInInstallPrefix-CMP0052-NEW-stderr.txt new file mode 100644 index 0000000..f0adc9f --- /dev/null +++ b/Tests/RunCMake/include_directories/BinInInstallPrefix-CMP0052-NEW-stderr.txt @@ -0,0 +1,6 @@ +CMake Error in CMakeLists.txt: + Target "testTarget" INTERFACE_INCLUDE_DIRECTORIES property contains path: + + ".*Tests/RunCMake/include_directories/prefix/BinInInstallPrefix-CMP0052-NEW-build/foo" + + which is prefixed in the build directory. diff --git a/Tests/RunCMake/include_directories/BinInInstallPrefix-CMP0052-OLD-result.txt b/Tests/RunCMake/include_directories/BinInInstallPrefix-CMP0052-OLD-result.txt new file mode 100644 index 0000000..573541a --- /dev/null +++ b/Tests/RunCMake/include_directories/BinInInstallPrefix-CMP0052-OLD-result.txt @@ -0,0 +1 @@ +0 diff --git a/Tests/RunCMake/include_directories/BinInInstallPrefix-CMP0052-OLD-stderr.txt b/Tests/RunCMake/include_directories/BinInInstallPrefix-CMP0052-OLD-stderr.txt new file mode 100644 index 0000000..10f3293 --- /dev/null +++ b/Tests/RunCMake/include_directories/BinInInstallPrefix-CMP0052-OLD-stderr.txt @@ -0,0 +1 @@ +^$ diff --git a/Tests/RunCMake/include_directories/BinInInstallPrefix-CMP0052-WARN-result.txt b/Tests/RunCMake/include_directories/BinInInstallPrefix-CMP0052-WARN-result.txt new file mode 100644 index 0000000..573541a --- /dev/null +++ b/Tests/RunCMake/include_directories/BinInInstallPrefix-CMP0052-WARN-result.txt @@ -0,0 +1 @@ +0 diff --git a/Tests/RunCMake/include_directories/BinInInstallPrefix-CMP0052-WARN-stderr.txt b/Tests/RunCMake/include_directories/BinInInstallPrefix-CMP0052-WARN-stderr.txt new file mode 100644 index 0000000..f6d408c --- /dev/null +++ b/Tests/RunCMake/include_directories/BinInInstallPrefix-CMP0052-WARN-stderr.txt @@ -0,0 +1,15 @@ +CMake Warning \(dev\) in CMakeLists.txt: + Policy CMP0052 is not set: Reject source and build dirs in installed + INTERFACE_INCLUDE_DIRECTORIES. Run "cmake --help-policy CMP0052" for + policy details. Use the cmake_policy command to set the policy and + suppress this warning. + + Directory: + + ".*Tests/RunCMake/include_directories/prefix/BinInInstallPrefix-CMP0052-WARN-build/foo" + + in INTERFACE_INCLUDE_DIRECTORIES of target "testTarget" is a subdirectory + of the install directory: + + ".*Tests/RunCMake/include_directories/prefix" +This warning is for project developers. Use -Wno-dev to suppress it. diff --git a/Tests/RunCMake/include_directories/CMakeLists.txt b/Tests/RunCMake/include_directories/CMakeLists.txt index f452db1..3482e6b 100644 --- a/Tests/RunCMake/include_directories/CMakeLists.txt +++ b/Tests/RunCMake/include_directories/CMakeLists.txt @@ -1,3 +1,3 @@ -cmake_minimum_required(VERSION 2.8.4) +cmake_minimum_required(VERSION 3.0) project(${RunCMake_TEST} CXX) include(${RunCMake_TEST}.cmake) diff --git a/Tests/RunCMake/include_directories/InstallInBinDir-result.txt b/Tests/RunCMake/include_directories/InstallInBinDir-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/include_directories/InstallInBinDir-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/include_directories/InstallInBinDir-stderr.txt b/Tests/RunCMake/include_directories/InstallInBinDir-stderr.txt new file mode 100644 index 0000000..254fae1 --- /dev/null +++ b/Tests/RunCMake/include_directories/InstallInBinDir-stderr.txt @@ -0,0 +1,6 @@ +CMake Error in CMakeLists.txt: + Target "testTarget" INTERFACE_INCLUDE_DIRECTORIES property contains path: + + ".*Tests/RunCMake/include_directories/InstallInBinDir-build/foo" + + which is prefixed in the build directory. diff --git a/Tests/RunCMake/include_directories/InstallInSrcDir-result.txt b/Tests/RunCMake/include_directories/InstallInSrcDir-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/include_directories/InstallInSrcDir-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/include_directories/InstallInSrcDir-stderr.txt b/Tests/RunCMake/include_directories/InstallInSrcDir-stderr.txt new file mode 100644 index 0000000..7be3044 --- /dev/null +++ b/Tests/RunCMake/include_directories/InstallInSrcDir-stderr.txt @@ -0,0 +1,6 @@ +CMake Error in CMakeLists.txt: + Target "testTarget" INTERFACE_INCLUDE_DIRECTORIES property contains path: + + ".*Tests/RunCMake/include_directories/copy/foo" + + which is prefixed in the source directory. diff --git a/Tests/RunCMake/include_directories/InstallPrefixInInterface-result.txt b/Tests/RunCMake/include_directories/InstallPrefixInInterface-result.txt new file mode 100644 index 0000000..573541a --- /dev/null +++ b/Tests/RunCMake/include_directories/InstallPrefixInInterface-result.txt @@ -0,0 +1 @@ +0 diff --git a/Tests/RunCMake/include_directories/InstallPrefixInInterface-stderr.txt b/Tests/RunCMake/include_directories/InstallPrefixInInterface-stderr.txt new file mode 100644 index 0000000..10f3293 --- /dev/null +++ b/Tests/RunCMake/include_directories/InstallPrefixInInterface-stderr.txt @@ -0,0 +1 @@ +^$ diff --git a/Tests/RunCMake/include_directories/InstallPrefixInInterface.cmake b/Tests/RunCMake/include_directories/InstallPrefixInInterface.cmake new file mode 100644 index 0000000..0f08e58 --- /dev/null +++ b/Tests/RunCMake/include_directories/InstallPrefixInInterface.cmake @@ -0,0 +1,11 @@ + +project(InstallPrefixInInterface) + +add_library(testTarget "${CMAKE_CURRENT_SOURCE_DIR}/empty.cpp") +target_include_directories(testTarget INTERFACE "${CMAKE_INSTALL_PREFIX}/foo") + +install(TARGETS testTarget EXPORT testTargets + DESTINATION lib +) + +install(EXPORT testTargets DESTINATION lib/cmake) diff --git a/Tests/RunCMake/include_directories/InstallToPrefixInSrcDirInSource-result.txt b/Tests/RunCMake/include_directories/InstallToPrefixInSrcDirInSource-result.txt new file mode 100644 index 0000000..573541a --- /dev/null +++ b/Tests/RunCMake/include_directories/InstallToPrefixInSrcDirInSource-result.txt @@ -0,0 +1 @@ +0 diff --git a/Tests/RunCMake/include_directories/InstallToPrefixInSrcDirInSource-stderr.txt b/Tests/RunCMake/include_directories/InstallToPrefixInSrcDirInSource-stderr.txt new file mode 100644 index 0000000..10f3293 --- /dev/null +++ b/Tests/RunCMake/include_directories/InstallToPrefixInSrcDirInSource-stderr.txt @@ -0,0 +1 @@ +^$ diff --git a/Tests/RunCMake/include_directories/InstallToPrefixInSrcDirOutOfSource-result.txt b/Tests/RunCMake/include_directories/InstallToPrefixInSrcDirOutOfSource-result.txt new file mode 100644 index 0000000..573541a --- /dev/null +++ b/Tests/RunCMake/include_directories/InstallToPrefixInSrcDirOutOfSource-result.txt @@ -0,0 +1 @@ +0 diff --git a/Tests/RunCMake/include_directories/InstallToPrefixInSrcDirOutOfSource-stderr.txt b/Tests/RunCMake/include_directories/InstallToPrefixInSrcDirOutOfSource-stderr.txt new file mode 100644 index 0000000..10f3293 --- /dev/null +++ b/Tests/RunCMake/include_directories/InstallToPrefixInSrcDirOutOfSource-stderr.txt @@ -0,0 +1 @@ +^$ diff --git a/Tests/RunCMake/include_directories/RunCMakeTest.cmake b/Tests/RunCMake/include_directories/RunCMakeTest.cmake index c00b924..434beb9 100644 --- a/Tests/RunCMake/include_directories/RunCMakeTest.cmake +++ b/Tests/RunCMake/include_directories/RunCMakeTest.cmake @@ -12,3 +12,128 @@ run_cmake(CMP0021) run_cmake(install_config) run_cmake(incomplete-genex) run_cmake(export-NOWARN) + +configure_file( + "${RunCMake_SOURCE_DIR}/CMakeLists.txt" + "${RunCMake_BINARY_DIR}/copy/CMakeLists.txt" + COPYONLY +) +configure_file( + "${RunCMake_SOURCE_DIR}/empty.cpp" + "${RunCMake_BINARY_DIR}/copy/empty.cpp" + COPYONLY +) +configure_file( + "${RunCMake_SOURCE_DIR}/SourceDirectoryInInterface.cmake" + "${RunCMake_BINARY_DIR}/copy/SourceDirectoryInInterface.cmake" + COPYONLY +) +set(RunCMake_TEST_OPTIONS "-DCMAKE_INSTALL_PREFIX=${RunCMake_BINARY_DIR}/copy/SourceDirectoryInInterface/prefix") +set(RunCMake_TEST_FILE "${RunCMake_BINARY_DIR}/copy/SourceDirectoryInInterface") +set(RunCMake_TEST_SOURCE_DIR "${RunCMake_BINARY_DIR}/copy") +run_cmake(InstallInSrcDir) +unset(RunCMake_TEST_SOURCE_DIR) +unset(RunCMake_TEST_FILE) + +set(RunCMake_TEST_OPTIONS "-DCMAKE_INSTALL_PREFIX=${RunCMake_BINARY_DIR}/InstallInBinDir-build/prefix") +set(RunCMake_TEST_BINARY_DIR "${RunCMake_BINARY_DIR}/InstallInBinDir-build") +set(RunCMake_TEST_FILE "${RunCMake_SOURCE_DIR}/BinaryDirectoryInInterface") +run_cmake(InstallInBinDir) +unset(RunCMake_TEST_BINARY_DIR) +unset(RunCMake_TEST_FILE) + +configure_file( + "${RunCMake_SOURCE_DIR}/CMakeLists.txt" + "${RunCMake_BINARY_DIR}/prefix/src/CMakeLists.txt" + COPYONLY +) +configure_file( + "${RunCMake_SOURCE_DIR}/empty.cpp" + "${RunCMake_BINARY_DIR}/prefix/src/empty.cpp" + COPYONLY +) +configure_file( + "${RunCMake_SOURCE_DIR}/SourceDirectoryInInterface.cmake" + "${RunCMake_BINARY_DIR}/prefix/src/SourceDirectoryInInterface.cmake" + COPYONLY +) + +foreach(policyStatus "" NEW OLD) + if (NOT "${policyStatus}" STREQUAL "") + set(policyOption -DCMAKE_POLICY_DEFAULT_CMP0052=${policyStatus}) + else() + unset(policyOption) + set(policyStatus WARN) + endif() + set(RunCMake_TEST_OPTIONS "-DCMAKE_INSTALL_PREFIX=${RunCMake_BINARY_DIR}/prefix" ${policyOption}) + # Set the RunCMake_TEST_SOURCE_DIR here to the copy too. This is needed to run + # the test suite in-source properly. Otherwise the install directory would be + # a subdirectory or the source directory, which is allowed and tested separately + # below. + set(RunCMake_TEST_SOURCE_DIR "${RunCMake_BINARY_DIR}/prefix/src") + set(RunCMake_TEST_BINARY_DIR "${RunCMake_BINARY_DIR}/prefix/BinInInstallPrefix-CMP0052-${policyStatus}-build") + set(RunCMake_TEST_FILE "${RunCMake_SOURCE_DIR}/BinaryDirectoryInInterface") + run_cmake(BinInInstallPrefix-CMP0052-${policyStatus}) + unset(RunCMake_TEST_BINARY_DIR) + unset(RunCMake_TEST_FILE) + + set(RunCMake_TEST_FILE "${RunCMake_BINARY_DIR}/prefix/src/SourceDirectoryInInterface") + run_cmake(SrcInInstallPrefix-CMP0052-${policyStatus}) + unset(RunCMake_TEST_SOURCE_DIR) + unset(RunCMake_TEST_FILE) +endforeach() + +set(RunCMake_TEST_OPTIONS "-DCMAKE_INSTALL_PREFIX=${RunCMake_BINARY_DIR}/InstallPrefixInInterface-build/prefix") +run_cmake(InstallPrefixInInterface) + +configure_file( + "${RunCMake_SOURCE_DIR}/CMakeLists.txt" + "${RunCMake_BINARY_DIR}/installToSrc/CMakeLists.txt" + COPYONLY +) +configure_file( + "${RunCMake_SOURCE_DIR}/empty.cpp" + "${RunCMake_BINARY_DIR}/installToSrc/empty.cpp" + COPYONLY +) +configure_file( + "${RunCMake_SOURCE_DIR}/InstallPrefixInInterface.cmake" + "${RunCMake_BINARY_DIR}/installToSrc/InstallPrefixInInterface.cmake" + COPYONLY +) +set(RunCMake_TEST_OPTIONS "-DCMAKE_INSTALL_PREFIX=${RunCMake_BINARY_DIR}/installToSrc/InstallPrefixInInterface/prefix") +set(RunCMake_TEST_FILE "${RunCMake_BINARY_DIR}/installToSrc/InstallPrefixInInterface") +set(RunCMake_TEST_SOURCE_DIR "${RunCMake_BINARY_DIR}/installToSrc") +run_cmake(InstallToPrefixInSrcDirOutOfSource) +unset(RunCMake_TEST_SOURCE_DIR) +unset(RunCMake_TEST_FILE) + + +file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}/installToSrcInSrc") +set(RunCMake_TEST_NO_CLEAN ON) + +configure_file( + "${RunCMake_SOURCE_DIR}/CMakeLists.txt" + "${RunCMake_BINARY_DIR}/installToSrcInSrc/CMakeLists.txt" + COPYONLY +) +configure_file( + "${RunCMake_SOURCE_DIR}/empty.cpp" + "${RunCMake_BINARY_DIR}/installToSrcInSrc/empty.cpp" + COPYONLY +) +configure_file( + "${RunCMake_SOURCE_DIR}/InstallPrefixInInterface.cmake" + "${RunCMake_BINARY_DIR}/installToSrcInSrc/InstallPrefixInInterface.cmake" + COPYONLY +) + +set(RunCMake_TEST_OPTIONS "-DCMAKE_INSTALL_PREFIX=${RunCMake_BINARY_DIR}/installToSrcInSrc/InstallPrefixInInterface/prefix") +set(RunCMake_TEST_FILE "${RunCMake_BINARY_DIR}/installToSrcInSrc/InstallPrefixInInterface") +set(RunCMake_TEST_SOURCE_DIR "${RunCMake_BINARY_DIR}/installToSrcInSrc") +set(RunCMake_TEST_BINARY_DIR "${RunCMake_BINARY_DIR}/installToSrcInSrc") +run_cmake(InstallToPrefixInSrcDirInSource) +unset(RunCMake_TEST_SOURCE_DIR) +unset(RunCMake_TEST_BINARY_DIR) +unset(RunCMake_TEST_FILE) +unset(RunCMake_TEST_NO_CLEAN) diff --git a/Tests/RunCMake/include_directories/SrcInInstallPrefix-CMP0052-NEW-result.txt b/Tests/RunCMake/include_directories/SrcInInstallPrefix-CMP0052-NEW-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/include_directories/SrcInInstallPrefix-CMP0052-NEW-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/include_directories/SrcInInstallPrefix-CMP0052-NEW-stderr.txt b/Tests/RunCMake/include_directories/SrcInInstallPrefix-CMP0052-NEW-stderr.txt new file mode 100644 index 0000000..afa43e0 --- /dev/null +++ b/Tests/RunCMake/include_directories/SrcInInstallPrefix-CMP0052-NEW-stderr.txt @@ -0,0 +1,6 @@ +CMake Error in CMakeLists.txt: + Target "testTarget" INTERFACE_INCLUDE_DIRECTORIES property contains path: + + ".*Tests/RunCMake/include_directories/prefix/src/foo" + + which is prefixed in the source directory. diff --git a/Tests/RunCMake/include_directories/SrcInInstallPrefix-CMP0052-OLD-result.txt b/Tests/RunCMake/include_directories/SrcInInstallPrefix-CMP0052-OLD-result.txt new file mode 100644 index 0000000..573541a --- /dev/null +++ b/Tests/RunCMake/include_directories/SrcInInstallPrefix-CMP0052-OLD-result.txt @@ -0,0 +1 @@ +0 diff --git a/Tests/RunCMake/include_directories/SrcInInstallPrefix-CMP0052-OLD-stderr.txt b/Tests/RunCMake/include_directories/SrcInInstallPrefix-CMP0052-OLD-stderr.txt new file mode 100644 index 0000000..10f3293 --- /dev/null +++ b/Tests/RunCMake/include_directories/SrcInInstallPrefix-CMP0052-OLD-stderr.txt @@ -0,0 +1 @@ +^$ diff --git a/Tests/RunCMake/include_directories/SrcInInstallPrefix-CMP0052-WARN-result.txt b/Tests/RunCMake/include_directories/SrcInInstallPrefix-CMP0052-WARN-result.txt new file mode 100644 index 0000000..573541a --- /dev/null +++ b/Tests/RunCMake/include_directories/SrcInInstallPrefix-CMP0052-WARN-result.txt @@ -0,0 +1 @@ +0 diff --git a/Tests/RunCMake/include_directories/SrcInInstallPrefix-CMP0052-WARN-stderr.txt b/Tests/RunCMake/include_directories/SrcInInstallPrefix-CMP0052-WARN-stderr.txt new file mode 100644 index 0000000..78710c0 --- /dev/null +++ b/Tests/RunCMake/include_directories/SrcInInstallPrefix-CMP0052-WARN-stderr.txt @@ -0,0 +1,15 @@ +CMake Warning \(dev\) in CMakeLists.txt: + Policy CMP0052 is not set: Reject source and build dirs in installed + INTERFACE_INCLUDE_DIRECTORIES. Run "cmake --help-policy CMP0052" for + policy details. Use the cmake_policy command to set the policy and + suppress this warning. + + Directory: + + ".*Tests/RunCMake/include_directories/prefix/src/foo" + + in INTERFACE_INCLUDE_DIRECTORIES of target "testTarget" is a subdirectory + of the install directory: + + ".*Tests/RunCMake/include_directories/prefix" +This warning is for project developers. Use -Wno-dev to suppress it. diff --git a/Tests/RunCMake/set/ParentScope-result.txt b/Tests/RunCMake/set/ParentScope-result.txt new file mode 100644 index 0000000..573541a --- /dev/null +++ b/Tests/RunCMake/set/ParentScope-result.txt @@ -0,0 +1 @@ +0 diff --git a/Tests/RunCMake/set/PARENT_SCOPE.cmake b/Tests/RunCMake/set/ParentScope.cmake index 9bd6bca..9bd6bca 100644 --- a/Tests/RunCMake/set/PARENT_SCOPE.cmake +++ b/Tests/RunCMake/set/ParentScope.cmake diff --git a/Tests/RunCMake/set/RunCMakeTest.cmake b/Tests/RunCMake/set/RunCMakeTest.cmake index 5d036e3..1b51ea2 100644 --- a/Tests/RunCMake/set/RunCMakeTest.cmake +++ b/Tests/RunCMake/set/RunCMakeTest.cmake @@ -1,3 +1,3 @@ include(RunCMake) -run_cmake(PARENT_SCOPE) +run_cmake(ParentScope) diff --git a/Tests/SubDirSpaces/CMakeLists.txt b/Tests/SubDirSpaces/CMakeLists.txt index 69f1d68..40c265e 100644 --- a/Tests/SubDirSpaces/CMakeLists.txt +++ b/Tests/SubDirSpaces/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required (VERSION 2.6) project(SUBDIR) # Some systems do not seem to support rpath with spaces. -if("${CMAKE_SYSTEM}" MATCHES "IRIX|QNX") +if(CMAKE_SYSTEM_NAME MATCHES "IRIX|QNX") set(CMAKE_SKIP_BUILD_RPATH 1) endif() diff --git a/Utilities/Sphinx/CMakeLists.txt b/Utilities/Sphinx/CMakeLists.txt index 4ae4bec..132ce60 100644 --- a/Utilities/Sphinx/CMakeLists.txt +++ b/Utilities/Sphinx/CMakeLists.txt @@ -79,6 +79,11 @@ if(SPHINX_QTHELP) # https://codereview.qt-project.org/#change,82250 in Qt 4. COMMAND ${CMAKE_COMMAND} "-DCSS_DIR=${CMAKE_CURRENT_BINARY_DIR}/qthelp/_static" -P "${CMAKE_CURRENT_SOURCE_DIR}/apply_qthelp_css_workaround.cmake" + # Workaround sphinx configurability: + # https://bitbucket.org/birkenfeld/sphinx/issue/1448/make-qthelp-more-configurable + COMMAND ${CMAKE_COMMAND} "-DQTHELP_DIR=${CMAKE_CURRENT_BINARY_DIR}/qthelp/" + "-DCMake_VERSION=${CMake_VERSION_MAJOR}${CMake_VERSION_MINOR}${CMake_VERSION_PATCH}" + -P "${CMAKE_CURRENT_SOURCE_DIR}/fixup_qthelp_names.cmake" COMMAND qcollectiongenerator ${CMAKE_CURRENT_BINARY_DIR}/qthelp/CMake.qhcp ) endif() @@ -144,7 +149,7 @@ if(SPHINX_HTML) ) endif() if(SPHINX_QTHELP) - install(FILES ${CMAKE_CURRENT_BINARY_DIR}/qthelp/CMake.qch + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/qthelp/CMake-${CMake_VERSION_MAJOR}${CMake_VERSION_MINOR}${CMake_VERSION_PATCH}.qch DESTINATION ${CMAKE_DOC_DIR} ) endif() diff --git a/Utilities/Sphinx/conf.py.in b/Utilities/Sphinx/conf.py.in index ef622fd..f7e4b8b 100644 --- a/Utilities/Sphinx/conf.py.in +++ b/Utilities/Sphinx/conf.py.in @@ -61,3 +61,7 @@ html_theme = 'default' html_title = 'CMake %s Documentation' % release html_short_title = '%s Documentation' % release html_favicon = 'cmake-favicon.ico' +# Not supported yet by sphinx: +# https://bitbucket.org/birkenfeld/sphinx/issue/1448/make-qthelp-more-configurable +# qthelp_namespace = "org.cmake" +# qthelp_qch_name = "CMake-300.qch" diff --git a/Utilities/Sphinx/fixup_qthelp_names.cmake b/Utilities/Sphinx/fixup_qthelp_names.cmake new file mode 100644 index 0000000..e35ef25 --- /dev/null +++ b/Utilities/Sphinx/fixup_qthelp_names.cmake @@ -0,0 +1,32 @@ + +file(READ "${QTHELP_DIR}/CMake.qhcp" QHCP_CONTENT) + +string(REPLACE + "<homePage>qthelp://org.sphinx.cmake" "<homePage>qthelp://org.cmake" + QHCP_CONTENT "${QHCP_CONTENT}" +) +string(REPLACE + "<startPage>qthelp://org.sphinx.cmake" "<startPage>qthelp://org.cmake" + QHCP_CONTENT "${QHCP_CONTENT}" +) + +string(REPLACE + "<output>CMake.qch" "<output>CMake-${CMake_VERSION}.qch" + QHCP_CONTENT "${QHCP_CONTENT}" +) +string(REPLACE + "<file>CMake.qch" "<file>CMake-${CMake_VERSION}.qch" + QHCP_CONTENT "${QHCP_CONTENT}" +) + +file(WRITE "${QTHELP_DIR}/CMake.qhcp" "${QHCP_CONTENT}") + + +file(READ "${QTHELP_DIR}/CMake.qhp" QHP_CONTENT) + +string(REPLACE + "<namespace>org.sphinx.cmake" "<namespace>org.cmake" + QHP_CONTENT "${QHP_CONTENT}" +) + +file(WRITE "${QTHELP_DIR}/CMake.qhp" "${QHP_CONTENT}") diff --git a/Utilities/cmlibarchive/.gitattributes b/Utilities/cmlibarchive/.gitattributes index be7062b..a87f192 100644 --- a/Utilities/cmlibarchive/.gitattributes +++ b/Utilities/cmlibarchive/.gitattributes @@ -1,2 +1 @@ -*.h whitespace=indent-with-non-tab,-blank-at-eol -*.c whitespace=indent-with-non-tab,-blank-at-eol +* whitespace=-indent-with-non-tab,-tab-in-indent,-blank-at-eol,-blank-at-eof diff --git a/Utilities/cmlibarchive/CMakeLists.txt b/Utilities/cmlibarchive/CMakeLists.txt index 132bfeb..afb7cea 100644 --- a/Utilities/cmlibarchive/CMakeLists.txt +++ b/Utilities/cmlibarchive/CMakeLists.txt @@ -32,7 +32,7 @@ SET(LIBARCHIVE_VERSION_NUMBER "${_version_number}") SET(LIBARCHIVE_VERSION_STRING "${VERSION}") # INTERFACE_VERSION increments with every release -# libarchive 2.7 == interface version 9 = 2 + 7 +# libarchive 2.7 == interface version 9 = 2 + 7 # libarchive 2.8 == interface version 10 = 2 + 8 # libarchive 2.9 == interface version 11 = 2 + 9 # libarchive 3.0 == interface version 12 @@ -69,6 +69,13 @@ include(CTest) OPTION(ENABLE_NETTLE "Enable use of Nettle" ON) OPTION(ENABLE_OPENSSL "Enable use of OpenSSL" ON) +OPTION(ENABLE_LZMA "Enable the use of the system found LZMA library if found" ON) +OPTION(ENABLE_ZLIB "Enable the use of the system found ZLIB library if found" ON) +OPTION(ENABLE_BZip2 "Enable the use of the system found BZip2 library if found" ON) +OPTION(ENABLE_EXPAT "Enable the use of the system found EXPAT library if found" ON) +OPTION(ENABLE_PCREPOSIX "Enable the use of the system found PCREPOSIX library if found" ON) +OPTION(ENABLE_LibGCC "Enable the use of the system found LibGCC library if found" ON) + OPTION(ENABLE_XATTR "Enable extended attribute support" ON) OPTION(ENABLE_ACL "Enable ACL support" ON) OPTION(ENABLE_ICONV "Enable iconv support" ON) @@ -190,7 +197,7 @@ IF(DEFINED __GNUWIN32PATH AND EXISTS "${__GNUWIN32PATH}") #--- zconf.h.orig 2005-07-21 00:40:26.000000000 #+++ zconf.h 2009-01-19 11:39:10.093750000 #@@ -286,7 +286,7 @@ - # + # # #if 1 /* HAVE_UNISTD_H -- this line is updated by ./configure */ # # include <sys/types.h> /* for off_t */ #-# include <unistd.h> /* for SEEK_* and off_t */ @@ -204,7 +211,11 @@ SET(ADDITIONAL_LIBS "") # # Find ZLIB # -FIND_PACKAGE(ZLIB) +IF(ENABLE_ZLIB) + FIND_PACKAGE(ZLIB) +ELSE() + SET(ZLIB_FOUND FALSE) # Override cached value +ENDIF() IF(ZLIB_FOUND) SET(HAVE_LIBZ 1) SET(HAVE_ZLIB_H 1) @@ -239,7 +250,11 @@ ENDIF(ZLIB_FOUND) # # Find BZip2 # -FIND_PACKAGE(BZip2) +IF(ENABLE_BZip2) + FIND_PACKAGE(BZip2) +ELSE() + SET(BZIP2_FOUND FALSE) # Override cached value +ENDIF() IF(BZIP2_FOUND) SET(HAVE_LIBBZ2 1) SET(HAVE_BZLIB_H 1) @@ -263,7 +278,13 @@ IF(0) # CMake does not need LZMA or LZO2 support in libarchive # # Find LZMA # -FIND_PACKAGE(LZMA) +IF(ENABLE_LZMA) + FIND_PACKAGE(LZMA) +ELSE() + SET(LZMA_FOUND FALSE) # Override cached value + SET(LZMADEC_FOUND FALSE) # Override cached value +ENDIF() + IF(LZMA_FOUND) SET(HAVE_LIBLZMA 1) SET(HAVE_LZMA_H 1) @@ -283,6 +304,8 @@ ELSEIF(LZMADEC_FOUND) SET(HAVE_LZMADEC_H 1) INCLUDE_DIRECTORIES(${LZMADEC_INCLUDE_DIR}) LIST(APPEND ADDITIONAL_LIBS ${LZMADEC_LIBRARIES}) +ELSE(LZMA_FOUND) +# LZMA not found and will not be used. ENDIF(LZMA_FOUND) # # Find LZO2 @@ -327,7 +350,11 @@ ENDMACRO (LA_CHECK_INCLUDE_FILE) LA_CHECK_INCLUDE_FILE("sys/types.h" HAVE_SYS_TYPES_H) # Alphabetize the rest unless there's a compelling reason -LA_CHECK_INCLUDE_FILE("acl/libacl.h" HAVE_ACL_LIBACL_H) +IF(ENABLE_ACL) + LA_CHECK_INCLUDE_FILE("acl/libacl.h" HAVE_ACL_LIBACL_H) +ELSE(ENABLE_ACL) + SET(HAVE_ACL_LIBACL_H FALSE) +ENDIF(ENABLE_ACL) LA_CHECK_INCLUDE_FILE("ctype.h" HAVE_CTYPE_H) LA_CHECK_INCLUDE_FILE("copyfile.h" HAVE_COPYFILE_H) LA_CHECK_INCLUDE_FILE("direct.h" HAVE_DIRECT_H) @@ -510,16 +537,10 @@ main(int argc, char **argv) FILE(WRITE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/check_crypto_md.c" "${SOURCE}") MESSAGE(STATUS "Checking support for ARCHIVE_CRYPTO_${ALGORITHM}_${IMPLEMENTATION}") - IF(CMAKE_REQUIRED_LINKER_FLAGS) - SET(CHECK_CRYPTO_ADD_LINKER_FLAGS - "-DCMAKE_EXE_LINKER_FLAGS:STRING=${CMAKE_REQUIRED_LINKER_FLAGS} -DCMAKE_SHARED_LINKER_FLAGS:STRING=${CMAKE_REQUIRED_LINKER_FLAGS} -DCMAKE_MODULE_LINKER_FLAGS:STRING=${CMAKE_REQUIRED_LINKER_FLAGS}") - ELSE(CMAKE_REQUIRED_LINKER_FLAGS) - SET(CHECK_CRYPTO_ADD_LINKER_FLAGS) - ENDIF(CMAKE_REQUIRED_LINKER_FLAGS) TRY_COMPILE(ARCHIVE_CRYPTO_${ALGORITHM}_${IMPLEMENTATION} ${CMAKE_BINARY_DIR} ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/check_crypto_md.c - CMAKE_FLAGS ${CHECK_CRYPTO_ADD_LINKER_FLAGS} + CMAKE_FLAGS "${TRY_CRYPTO_REQUIRED_LIBS}" "${TRY_CRYPTO_REQUIRED_INCLUDES}" OUTPUT_VARIABLE OUTPUT) @@ -604,16 +625,10 @@ main(int argc, char **argv) FILE(WRITE "${SOURCE_FILE}" "${SOURCE}") MESSAGE(STATUS "Checking support for ARCHIVE_CRYPTO_${CRYPTO}_WIN") - IF(CMAKE_REQUIRED_LINKER_FLAGS) - SET(CHECK_CRYPTO_WIN_ADD_LINKER_FLAGS - "-DCMAKE_EXE_LINKER_FLAGS:STRING=${CMAKE_REQUIRED_LINKER_FLAGS} -DCMAKE_SHARED_LINKER_FLAGS:STRING=${CMAKE_REQUIRED_LINKER_FLAGS} -DCMAKE_MODULE_LINKER_FLAGS:STRING=${CMAKE_REQUIRED_LINKER_FLAGS}") - ELSE(CMAKE_REQUIRED_LINKER_FLAGS) - SET(CHECK_CRYPTO_WIN_ADD_LINKER_FLAGS) - ENDIF(CMAKE_REQUIRED_LINKER_FLAGS) TRY_COMPILE(ARCHIVE_CRYPTO_${CRYPTO}_WIN ${CMAKE_BINARY_DIR} ${SOURCE_FILE} - CMAKE_FLAGS "-DINCLUDE_DIRECTORIES:STRING=${CMAKE_BINARY_DIR};${CMAKE_CURRENT_SOURCE_DIR}/libarchive" ${CHECK_CRYPTO_WIN_ADD_LINKER_FLAGS} + CMAKE_FLAGS "-DINCLUDE_DIRECTORIES:STRING=${CMAKE_BINARY_DIR};${CMAKE_CURRENT_SOURCE_DIR}/libarchive" OUTPUT_VARIABLE OUTPUT) IF (ARCHIVE_CRYPTO_${CRYPTO}_WIN) @@ -1030,13 +1045,13 @@ CHECK_TYPE_SIZE("unsigned long long" SIZE_OF_UNSIGNED_LONG_LONG) CHECK_TYPE_SIZE("__int64" __INT64) CHECK_TYPE_SIZE("unsigned __int64" UNSIGNED___INT64) -CHECK_TYPE_SIZE(int16_t INT16_T) +CHECK_TYPE_SIZE(int16_t INT16_T) CHECK_TYPE_SIZE(int32_t INT32_T) CHECK_TYPE_SIZE(int64_t INT64_T) CHECK_TYPE_SIZE(intmax_t INTMAX_T) -CHECK_TYPE_SIZE(uint8_t UINT8_T) -CHECK_TYPE_SIZE(uint16_t UINT16_T) -CHECK_TYPE_SIZE(uint32_t UINT32_T) +CHECK_TYPE_SIZE(uint8_t UINT8_T) +CHECK_TYPE_SIZE(uint16_t UINT16_T) +CHECK_TYPE_SIZE(uint32_t UINT32_T) CHECK_TYPE_SIZE(uint64_t UINT64_T) CHECK_TYPE_SIZE(uintmax_t UINTMAX_T) diff --git a/Utilities/cmlibarchive/README-CMake.txt b/Utilities/cmlibarchive/README-CMake.txt index ab105f0..7cbee4c 100644 --- a/Utilities/cmlibarchive/README-CMake.txt +++ b/Utilities/cmlibarchive/README-CMake.txt @@ -11,7 +11,7 @@ branch, but it is merged into our history. Update libarchive from upstream as follows. Create a local branch to explicitly reference the upstream snapshot branch head: - git branch libarchive-upstream 35df7c8b + git branch libarchive-upstream 64713ae3 Use a temporary directory to checkout the branch: @@ -24,7 +24,7 @@ Use a temporary directory to checkout the branch: Now place the (reduced) libarchive content in this directory. See instructions shown by - git log 35df7c8b + git log 64713ae3 for help extracting the content from the upstream svn repo. Then run the following commands to commit the new version. Substitute the @@ -34,8 +34,8 @@ appropriate date and version number: GIT_AUTHOR_NAME='LibArchive Upstream' \ GIT_AUTHOR_EMAIL='libarchive-discuss@googlegroups.com' \ - GIT_AUTHOR_DATE='2013-02-09 12:17:57 -0500' \ - git commit -m 'libarchive 3.1.2 (reduced)' && + GIT_AUTHOR_DATE='Mon Mar 17 20:43:07 2014 -0700' \ + git commit -m 'libarchive 3.1.2-218-g00f4bd83 (reduced)' && git commit --amend Edit the commit message to describe the procedure used to obtain the diff --git a/Utilities/cmlibarchive/build/cmake/CreatePkgConfigFile.cmake b/Utilities/cmlibarchive/build/cmake/CreatePkgConfigFile.cmake new file mode 100644 index 0000000..f96bbef --- /dev/null +++ b/Utilities/cmlibarchive/build/cmake/CreatePkgConfigFile.cmake @@ -0,0 +1,31 @@ +# - Generate a libarchive.pc like autotools for pkg-config +# + +# Set the required variables (we use the same input file as autotools) +SET(prefix ${CMAKE_INSTALL_PREFIX}) +SET(exec_prefix \${prefix}) +SET(libdir \${exec_prefix}/lib) +SET(includedir \${prefix}/include) +# Now, this is not particularly pretty, nor is it terribly accurate... +# Loop over all our additional libs +FOREACH(mylib ${ADDITIONAL_LIBS}) + # Extract the filename from the absolute path + GET_FILENAME_COMPONENT(mylib_name ${mylib} NAME_WE) + # Strip the lib prefix + STRING(REGEX REPLACE "^lib" "" mylib_name ${mylib_name}) + # Append it to our LIBS string + SET(LIBS "${LIBS} -l${mylib_name}") +ENDFOREACH() +# libxml2 is easier, since it's already using pkg-config +FOREACH(mylib ${PC_LIBXML_STATIC_LDFLAGS}) + SET(LIBS "${LIBS} ${mylib}") +ENDFOREACH() +# FIXME: The order of the libraries doesn't take dependencies into account, +# thus there's a good chance it'll make some binutils versions unhappy... +# This only affects Libs.private (looked up for static builds) though. +CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/build/pkgconfig/libarchive.pc.in + ${CMAKE_CURRENT_SOURCE_DIR}/build/pkgconfig/libarchive.pc + @ONLY) +# And install it, of course ;). +INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/build/pkgconfig/libarchive.pc + DESTINATION "lib/pkgconfig") diff --git a/Utilities/cmlibarchive/build/cmake/LibarchiveCodeCoverage.cmake b/Utilities/cmlibarchive/build/cmake/LibarchiveCodeCoverage.cmake new file mode 100644 index 0000000..297b886 --- /dev/null +++ b/Utilities/cmlibarchive/build/cmake/LibarchiveCodeCoverage.cmake @@ -0,0 +1,68 @@ +################################################################# +# Adds a build target called "coverage" for code coverage. +# +# This compiles the code using special GCC flags, run the tests, +# and then generates a nice HTML output. This new "coverage" make +# target will only be available if you build using GCC in Debug +# mode. If any of the required programs (lcov and genhtml) were +# not found, a FATAL_ERROR message is printed. +# +# If not already done, this code will set ENABLE_TEST to ON. +# +# To build the code coverage and open it in your browser do this: +# +# mkdir debug +# cd debug +# cmake -DCMAKE_BUILD_TYPE=Debug -DENABLE_COVERAGE=ON .. +# make -j4 +# make coverage +# xdg-open coverage/index.html +################################################################# + +# Find programs we need +FIND_PROGRAM(LCOV_EXECUTABLE lcov DOC "Full path to lcov executable") +FIND_PROGRAM(GENHTML_EXECUTABLE genhtml DOC "Full path to genhtml executable") +MARK_AS_ADVANCED(LCOV_EXECUTABLE GENHTML_EXECUTABLE) + +# Check, compiler, build types and programs are available +IF(NOT CMAKE_COMPILER_IS_GNUCC) +MESSAGE(FATAL_ERROR "Coverage can only be built on GCC") +ELSEIF(NOT CMAKE_BUILD_TYPE STREQUAL "Debug") +MESSAGE(FATAL_ERROR "Coverage can only be built in Debug mode") +ELSEIF(NOT LCOV_EXECUTABLE) +MESSAGE(FATAL_ERROR "lcov executable not found") +ELSEIF(NOT GENHTML_EXECUTABLE) +MESSAGE(FATAL_ERROR "genhtml executable not found") +ENDIF(NOT CMAKE_COMPILER_IS_GNUCC) + +# Enable testing if not already done +SET(ENABLE_TEST ON) + +################################################################# +# Set special compiler and linker flags for test coverage +################################################################# +# 0. Enable debug: -g +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g") +# 1. Disable optimizations: -O0 +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O0") +# 2. Enable all kind of warnings: +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -W") +# 3. Enable special coverage flag (HINT: --coverage is a synonym for -fprofile-arcs -ftest-coverage) +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} --coverage") +SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} --coverage") +SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --coverage") +################################################################# + +ADD_CUSTOM_TARGET(coverage +COMMAND ${CMAKE_COMMAND} -E echo "Beginning test coverage. Output is written to coverage.log." +COMMAND ${CMAKE_COMMAND} -E echo "COVERAGE-STEP-1/5: Reset all execution counts to zero" +COMMAND ${LCOV_EXECUTABLE} --directory . --zerocounters > coverage.log 2>&1 +COMMAND ${CMAKE_COMMAND} -E echo "COVERAGE-STEP-2/5: Run testrunner" +COMMAND ${CMAKE_CTEST_COMMAND} >> coverage.log 2>&1 +COMMAND ${CMAKE_COMMAND} -E echo "COVERAGE-STEP-3/5: Collect coverage data" +COMMAND ${LCOV_EXECUTABLE} --capture --directory . --output-file "./coverage.info" >> coverage.log 2>&1 +COMMAND ${CMAKE_COMMAND} -E echo "COVERAGE-STEP-4/5: Generate HTML from coverage data" +COMMAND ${GENHTML_EXECUTABLE} "coverage.info" --title="libarchive-${LIBARCHIVE_VERSION_STRING}" --show-details --legend --output-directory "./coverage" >> coverage.log 2>&1 +COMMAND ${CMAKE_COMMAND} -E echo "COVERAGE-STEP-5/5: Open test coverage HTML output in browser: xdg-open ./coverage/index.html" +COMMENT "Runs testrunner and generates coverage output (formats: .info and .html)") + diff --git a/Utilities/cmlibarchive/build/cmake/config.h.in b/Utilities/cmlibarchive/build/cmake/config.h.in index 750ae66..f2d2068 100644 --- a/Utilities/cmlibarchive/build/cmake/config.h.in +++ b/Utilities/cmlibarchive/build/cmake/config.h.in @@ -1112,8 +1112,13 @@ typedef uint64_t uintmax_t; #cmakedefine _LARGE_FILES ${_LARGE_FILES} /* Define for Windows to use Windows 2000+ APIs. */ +#ifndef _WIN32_WINNT #cmakedefine _WIN32_WINNT ${_WIN32_WINNT} +#endif // _WIN32_WINNT + +#ifndef WINVER #cmakedefine WINVER ${WINVER} +#endif // WINVER /* Define to empty if `const' does not conform to ANSI C. */ #cmakedefine const ${const} diff --git a/Utilities/cmlibarchive/libarchive/CMakeLists.txt b/Utilities/cmlibarchive/libarchive/CMakeLists.txt index 42781bc..8a68424 100644 --- a/Utilities/cmlibarchive/libarchive/CMakeLists.txt +++ b/Utilities/cmlibarchive/libarchive/CMakeLists.txt @@ -35,6 +35,8 @@ SET(libarchive_SOURCES archive_match.c archive_options.c archive_options_private.h + archive_pack_dev.h + archive_pack_dev.c archive_pathmatch.c archive_pathmatch.h archive_platform.h @@ -125,6 +127,7 @@ SET(libarchive_SOURCES archive_write_set_format_iso9660.c archive_write_set_format_mtree.c archive_write_set_format_pax.c + archive_write_set_format_raw.c archive_write_set_format_shar.c archive_write_set_format_ustar.c archive_write_set_format_v7tar.c diff --git a/Utilities/cmlibarchive/libarchive/archive.h b/Utilities/cmlibarchive/libarchive/archive.h index 83d2c16..9cf762d 100644 --- a/Utilities/cmlibarchive/libarchive/archive.h +++ b/Utilities/cmlibarchive/libarchive/archive.h @@ -137,6 +137,11 @@ __LA_DECL int archive_version_number(void); #define ARCHIVE_VERSION_STRING "libarchive 3.1.2" __LA_DECL const char * archive_version_string(void); +/* + * Detailed textual name/version of the library and its dependencies. + */ +__LA_DECL const char * archive_version_details(void); + /* Declare our basic types. */ struct archive; struct archive_entry; @@ -289,6 +294,30 @@ typedef int archive_switch_callback(struct archive *, void *_client_data1, #define ARCHIVE_FORMAT_RAR 0xD0000 #define ARCHIVE_FORMAT_7ZIP 0xE0000 +/* + * Codes returned by archive_read_format_capabilities(). + * + * This list can be extended with values between 0 and 0xffff. + * The original purpose of this list was to let different archive + * format readers expose their general capabilities in terms of + * encryption. + */ +#define ARCHIVE_READ_FORMAT_CAPS_NONE (0) /* no special capabilities */ +#define ARCHIVE_READ_FORMAT_CAPS_ENCRYPT_DATA (1<<0) /* reader can detect encrypted data */ +#define ARCHIVE_READ_FORMAT_CAPS_ENCRYPT_METADATA (1<<1) /* reader can detect encryptable metadata (pathname, mtime, etc.) */ + +/* + * Codes returned by archive_read_has_encrypted_entries(). + * + * In case the archive does not support encryption detection at all + * ARCHIVE_READ_FORMAT_ENCRYPTION_UNSUPPORTED is returned. If the reader + * for some other reason (e.g. not enough bytes read) cannot say if + * there are encrypted entries, ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW + * is returned. + */ +#define ARCHIVE_READ_FORMAT_ENCRYPTION_UNSUPPORTED -2 +#define ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW -1 + /*- * Basic outline for reading an archive: * 1) Ask archive_read_new for an archive reader object. @@ -374,7 +403,15 @@ __LA_DECL int archive_read_support_format_rar(struct archive *); __LA_DECL int archive_read_support_format_raw(struct archive *); __LA_DECL int archive_read_support_format_tar(struct archive *); __LA_DECL int archive_read_support_format_xar(struct archive *); +/* archive_read_support_format_zip() enables both streamable and seekable + * zip readers. */ __LA_DECL int archive_read_support_format_zip(struct archive *); +/* Reads Zip archives as stream from beginning to end. Doesn't + * correctly handle SFX ZIP files or ZIP archives that have been modified + * in-place. */ +__LA_DECL int archive_read_support_format_zip_streamable(struct archive *); +/* Reads starting from central directory; requires seekable input. */ +__LA_DECL int archive_read_support_format_zip_seekable(struct archive *); /* Functions to manually set the format and filters to be used. This is * useful to bypass the bidding process when the format and filters to use @@ -470,6 +507,32 @@ __LA_DECL int archive_read_next_header2(struct archive *, */ __LA_DECL __LA_INT64_T archive_read_header_position(struct archive *); +/* + * Returns 1 if the archive contains at least one encrypted entry. + * If the archive format not support encryption at all + * ARCHIVE_READ_FORMAT_ENCRYPTION_UNSUPPORTED is returned. + * If for any other reason (e.g. not enough data read so far) + * we cannot say whether there are encrypted entries, then + * ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW is returned. + * In general, this function will return values below zero when the + * reader is uncertain or totally uncapable of encryption support. + * When this function returns 0 you can be sure that the reader + * supports encryption detection but no encrypted entries have + * been found yet. + * + * NOTE: If the metadata/header of an archive is also encrypted, you + * cannot rely on the number of encrypted entries. That is why this + * function does not return the number of encrypted entries but# + * just shows that there are some. + */ +__LA_DECL int archive_read_has_encrypted_entries(struct archive *); + +/* + * Returns a bitmask of capabilities that are supported by the archive format reader. + * If the reader has no special capabilities, ARCHIVE_READ_FORMAT_CAPS_NONE is returned. + */ +__LA_DECL int archive_read_format_capabilities(struct archive *); + /* Read data from the body of an entry. Similar to read(2). */ __LA_DECL __LA_SSIZE_T archive_read_data(struct archive *, void *, size_t); @@ -674,6 +737,7 @@ __LA_DECL int archive_write_set_format_mtree_classic(struct archive *); /* TODO: int archive_write_set_format_old_tar(struct archive *); */ __LA_DECL int archive_write_set_format_pax(struct archive *); __LA_DECL int archive_write_set_format_pax_restricted(struct archive *); +__LA_DECL int archive_write_set_format_raw(struct archive *); __LA_DECL int archive_write_set_format_shar(struct archive *); __LA_DECL int archive_write_set_format_shar_dump(struct archive *); __LA_DECL int archive_write_set_format_ustar(struct archive *); @@ -883,6 +947,10 @@ __LA_DECL int archive_read_disk_set_metadata_filter_callback(struct archive *, int (*_metadata_filter_func)(struct archive *, void *, struct archive_entry *), void *_client_data); +/* Simplified cleanup interface; + * This calls archive_read_free() or archive_write_free() as needed. */ +__LA_DECL int archive_free(struct archive *); + /* * Accessor functions to read/set various information in * the struct archive object: @@ -1029,6 +1097,10 @@ __LA_DECL int archive_match_include_gname(struct archive *, const char *); __LA_DECL int archive_match_include_gname_w(struct archive *, const wchar_t *); +/* Utility functions */ +/* Convenience function to sort a NULL terminated list of strings */ +__LA_DECL int archive_utility_string_sort(char **); + #ifdef __cplusplus } #endif diff --git a/Utilities/cmlibarchive/libarchive/archive_entry.c b/Utilities/cmlibarchive/libarchive/archive_entry.c index 386e51d..293c701 100644 --- a/Utilities/cmlibarchive/libarchive/archive_entry.c +++ b/Utilities/cmlibarchive/libarchive/archive_entry.c @@ -201,6 +201,9 @@ archive_entry_clone(struct archive_entry *entry) entry2->ae_set = entry->ae_set; archive_mstring_copy(&entry2->ae_uname, &entry->ae_uname); + /* Copy encryption status */ + entry2->encryption = entry->encryption; + /* Copy ACL data over. */ archive_acl_copy(&entry2->acl, &entry->acl); @@ -695,6 +698,24 @@ _archive_entry_uname_l(struct archive_entry *entry, return (archive_mstring_get_mbs_l(&entry->ae_uname, p, len, sc)); } +int +archive_entry_is_data_encrypted(struct archive_entry *entry) +{ + return ((entry->encryption & AE_ENCRYPTION_DATA) == AE_ENCRYPTION_DATA); +} + +int +archive_entry_is_metadata_encrypted(struct archive_entry *entry) +{ + return ((entry->encryption & AE_ENCRYPTION_METADATA) == AE_ENCRYPTION_METADATA); +} + +int +archive_entry_is_encrypted(struct archive_entry *entry) +{ + return (entry->encryption & (AE_ENCRYPTION_DATA|AE_ENCRYPTION_METADATA)); +} + /* * Functions to set archive_entry properties. */ @@ -1216,6 +1237,26 @@ archive_entry_update_uname_utf8(struct archive_entry *entry, const char *name) return (0); } +void +archive_entry_set_is_data_encrypted(struct archive_entry *entry, char is_encrypted) +{ + if (is_encrypted) { + entry->encryption |= AE_ENCRYPTION_DATA; + } else { + entry->encryption &= ~AE_ENCRYPTION_DATA; + } +} + +void +archive_entry_set_is_metadata_encrypted(struct archive_entry *entry, char is_encrypted) +{ + if (is_encrypted) { + entry->encryption |= AE_ENCRYPTION_METADATA; + } else { + entry->encryption &= ~AE_ENCRYPTION_METADATA; + } +} + int _archive_entry_copy_uname_l(struct archive_entry *entry, const char *name, size_t len, struct archive_string_conv *sc) diff --git a/Utilities/cmlibarchive/libarchive/archive_entry.h b/Utilities/cmlibarchive/libarchive/archive_entry.h index ae6a76e..efc4d73 100644 --- a/Utilities/cmlibarchive/libarchive/archive_entry.h +++ b/Utilities/cmlibarchive/libarchive/archive_entry.h @@ -43,10 +43,6 @@ #include <stddef.h> /* for wchar_t */ #include <time.h> -#if defined(_WIN32) && !defined(__CYGWIN__) -#include <windows.h> -#endif - /* Get a suitable 64-bit integer type. */ #if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__WATCOMC__) # define __LA_INT64_T __int64 @@ -235,6 +231,9 @@ __LA_DECL const wchar_t *archive_entry_symlink_w(struct archive_entry *); __LA_DECL __LA_INT64_T archive_entry_uid(struct archive_entry *); __LA_DECL const char *archive_entry_uname(struct archive_entry *); __LA_DECL const wchar_t *archive_entry_uname_w(struct archive_entry *); +__LA_DECL int archive_entry_is_data_encrypted(struct archive_entry *); +__LA_DECL int archive_entry_is_metadata_encrypted(struct archive_entry *); +__LA_DECL int archive_entry_is_encrypted(struct archive_entry *); /* * Set fields in an archive_entry. @@ -248,7 +247,7 @@ __LA_DECL const wchar_t *archive_entry_uname_w(struct archive_entry *); __LA_DECL void archive_entry_set_atime(struct archive_entry *, time_t, long); __LA_DECL void archive_entry_unset_atime(struct archive_entry *); #if defined(_WIN32) && !defined(__CYGWIN__) -__LA_DECL void archive_entry_copy_bhfi(struct archive_entry *, BY_HANDLE_FILE_INFORMATION *); +__LA_DECL void archive_entry_copy_bhfi(struct archive_entry *, struct _BY_HANDLE_FILE_INFORMATION *); #endif __LA_DECL void archive_entry_set_birthtime(struct archive_entry *, time_t, long); __LA_DECL void archive_entry_unset_birthtime(struct archive_entry *); @@ -306,6 +305,8 @@ __LA_DECL void archive_entry_set_uname(struct archive_entry *, const char *); __LA_DECL void archive_entry_copy_uname(struct archive_entry *, const char *); __LA_DECL void archive_entry_copy_uname_w(struct archive_entry *, const wchar_t *); __LA_DECL int archive_entry_update_uname_utf8(struct archive_entry *, const char *); +__LA_DECL void archive_entry_set_is_data_encrypted(struct archive_entry *, char is_encrypted); +__LA_DECL void archive_entry_set_is_metadata_encrypted(struct archive_entry *, char is_encrypted); /* * Routines to bulk copy fields to/from a platform-native "struct * stat." Libarchive used to just store a struct stat inside of each diff --git a/Utilities/cmlibarchive/libarchive/archive_entry_private.h b/Utilities/cmlibarchive/libarchive/archive_entry_private.h index e3547c3..c69233e 100644 --- a/Utilities/cmlibarchive/libarchive/archive_entry_private.h +++ b/Utilities/cmlibarchive/libarchive/archive_entry_private.h @@ -154,6 +154,11 @@ struct archive_entry { /* Not used within libarchive; useful for some clients. */ struct archive_mstring ae_sourcepath; /* Path this entry is sourced from. */ +#define AE_ENCRYPTION_NONE 0 +#define AE_ENCRYPTION_DATA 1 +#define AE_ENCRYPTION_METADATA 2 + char encryption; + void *mac_metadata; size_t mac_metadata_size; diff --git a/Utilities/cmlibarchive/libarchive/archive_entry_sparse.c b/Utilities/cmlibarchive/libarchive/archive_entry_sparse.c index 10c5447..fed74f5 100644 --- a/Utilities/cmlibarchive/libarchive/archive_entry_sparse.c +++ b/Utilities/cmlibarchive/libarchive/archive_entry_sparse.c @@ -58,7 +58,7 @@ archive_entry_sparse_add_entry(struct archive_entry *entry, if (offset < 0 || length < 0) /* Invalid value */ return; - if (offset + length < 0 || + if (offset > INT64_MAX - length || offset + length > archive_entry_size(entry)) /* A value of "length" parameter is too large. */ return; diff --git a/Utilities/cmlibarchive/libarchive/archive_getdate.c b/Utilities/cmlibarchive/libarchive/archive_getdate.c index f8b5a28..aaa9d6f 100644 --- a/Utilities/cmlibarchive/libarchive/archive_getdate.c +++ b/Utilities/cmlibarchive/libarchive/archive_getdate.c @@ -369,8 +369,8 @@ relunitphrase(struct gdstate *gds) && gds->tokenp[1].token == tSEC_UNIT) { /* "1 day" */ gds->HaveRel++; - gds->RelSeconds += gds->tokenp[1].value * gds->tokenp[2].value; - gds->tokenp += 3; + gds->RelSeconds += gds->tokenp[0].value * gds->tokenp[1].value; + gds->tokenp += 2; return 1; } if (gds->tokenp[0].token == '-' @@ -403,7 +403,7 @@ relunitphrase(struct gdstate *gds) /* "now", "tomorrow" */ gds->HaveRel++; gds->RelSeconds += gds->tokenp[0].value; - ++gds->tokenp; + gds->tokenp += 1; return 1; } if (gds->tokenp[0].token == tMONTH_UNIT) { @@ -1022,10 +1022,11 @@ int main(int argc, char **argv) { time_t d; + time_t now = time(NULL); while (*++argv != NULL) { (void)printf("Input: %s\n", *argv); - d = get_date(*argv); + d = get_date(now, *argv); if (d == -1) (void)printf("Bad format - couldn't convert.\n"); else diff --git a/Utilities/cmlibarchive/libarchive/archive_match.c b/Utilities/cmlibarchive/libarchive/archive_match.c index 6b6be9c..6fb8644 100644 --- a/Utilities/cmlibarchive/libarchive/archive_match.c +++ b/Utilities/cmlibarchive/libarchive/archive_match.c @@ -1152,7 +1152,7 @@ set_timefilter_pathname_mbs(struct archive_match *a, int timetype, { /* NOTE: stat() on Windows cannot handle nano seconds. */ HANDLE h; - WIN32_FIND_DATA d; + WIN32_FIND_DATAA d; if (path == NULL || *path == '\0') { archive_set_error(&(a->archive), EINVAL, "pathname is empty"); diff --git a/Utilities/cmlibarchive/libarchive/archive_pack_dev.c b/Utilities/cmlibarchive/libarchive/archive_pack_dev.c new file mode 100644 index 0000000..6b7b472 --- /dev/null +++ b/Utilities/cmlibarchive/libarchive/archive_pack_dev.c @@ -0,0 +1,329 @@ +/* $NetBSD: pack_dev.c,v 1.12 2013/06/14 16:28:20 tsutsui Exp $ */ + +/*- + * Copyright (c) 1998, 2001 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Charles M. Hannum. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* Originally from NetBSD's mknod(8) source. */ + +#include "archive_platform.h" + +#if HAVE_SYS_CDEFS_H +#include <sys/cdefs.h> +#endif +#if !defined(lint) +__RCSID("$NetBSD$"); +#endif /* not lint */ + +#ifdef HAVE_LIMITS_H +#include <limits.h> +#endif + +#include <stdio.h> +#ifdef HAVE_STDLIB_H +#include <stdlib.h> +#endif +#ifdef HAVE_STRING_H +#include <string.h> +#endif +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#ifdef HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif + +#include "archive_pack_dev.h" + +static pack_t pack_netbsd; +static pack_t pack_freebsd; +static pack_t pack_8_8; +static pack_t pack_12_20; +static pack_t pack_14_18; +static pack_t pack_8_24; +static pack_t pack_bsdos; +static int compare_format(const void *, const void *); + +static const char iMajorError[] = "invalid major number"; +static const char iMinorError[] = "invalid minor number"; +static const char tooManyFields[] = "too many fields for format"; + +/* This is blatantly stolen from libarchive/archive_entry.c, + * in an attempt to get this to play nice on MinGW... */ +#if !defined(HAVE_MAJOR) && !defined(major) +/* Replacement for major/minor/makedev. */ +#define major(x) ((int)(0x00ff & ((x) >> 8))) +#define minor(x) ((int)(0xffff00ff & (x))) +#define makedev(maj,min) ((0xff00 & ((maj)<<8)) | (0xffff00ff & (min))) +#endif + +/* Play games to come up with a suitable makedev() definition. */ +#ifdef __QNXNTO__ +/* QNX. <sigh> */ +#include <sys/netmgr.h> +#define apd_makedev(maj, min) makedev(ND_LOCAL_NODE, (maj), (min)) +#elif defined makedev +/* There's a "makedev" macro. */ +#define apd_makedev(maj, min) makedev((maj), (min)) +#elif defined mkdev || ((defined _WIN32 || defined __WIN32__) && !defined(__CYGWIN__)) +/* Windows. <sigh> */ +#define apd_makedev(maj, min) mkdev((maj), (min)) +#else +/* There's a "makedev" function. */ +#define apd_makedev(maj, min) makedev((maj), (min)) +#endif + +/* exported */ +dev_t +pack_native(int n, unsigned long numbers[], const char **error) +{ + dev_t dev = 0; + + if (n == 2) { + dev = apd_makedev(numbers[0], numbers[1]); + if ((unsigned long)major(dev) != numbers[0]) + *error = iMajorError; + else if ((unsigned long)minor(dev) != numbers[1]) + *error = iMinorError; + } else + *error = tooManyFields; + return (dev); +} + + +static dev_t +pack_netbsd(int n, unsigned long numbers[], const char **error) +{ + dev_t dev = 0; + + if (n == 2) { + dev = makedev_netbsd(numbers[0], numbers[1]); + if ((unsigned long)major_netbsd(dev) != numbers[0]) + *error = iMajorError; + else if ((unsigned long)minor_netbsd(dev) != numbers[1]) + *error = iMinorError; + } else + *error = tooManyFields; + return (dev); +} + + +#define major_freebsd(x) ((int32_t)(((x) & 0x0000ff00) >> 8)) +#define minor_freebsd(x) ((int32_t)(((x) & 0xffff00ff) >> 0)) +#define makedev_freebsd(x,y) ((dev_t)((((x) << 8) & 0x0000ff00) | \ + (((y) << 0) & 0xffff00ff))) + +static dev_t +pack_freebsd(int n, unsigned long numbers[], const char **error) +{ + dev_t dev = 0; + + if (n == 2) { + dev = makedev_freebsd(numbers[0], numbers[1]); + if ((unsigned long)major_freebsd(dev) != numbers[0]) + *error = iMajorError; + if ((unsigned long)minor_freebsd(dev) != numbers[1]) + *error = iMinorError; + } else + *error = tooManyFields; + return (dev); +} + + +#define major_8_8(x) ((int32_t)(((x) & 0x0000ff00) >> 8)) +#define minor_8_8(x) ((int32_t)(((x) & 0x000000ff) >> 0)) +#define makedev_8_8(x,y) ((dev_t)((((x) << 8) & 0x0000ff00) | \ + (((y) << 0) & 0x000000ff))) + +static dev_t +pack_8_8(int n, unsigned long numbers[], const char **error) +{ + dev_t dev = 0; + + if (n == 2) { + dev = makedev_8_8(numbers[0], numbers[1]); + if ((unsigned long)major_8_8(dev) != numbers[0]) + *error = iMajorError; + if ((unsigned long)minor_8_8(dev) != numbers[1]) + *error = iMinorError; + } else + *error = tooManyFields; + return (dev); +} + + +#define major_12_20(x) ((int32_t)(((x) & 0xfff00000) >> 20)) +#define minor_12_20(x) ((int32_t)(((x) & 0x000fffff) >> 0)) +#define makedev_12_20(x,y) ((dev_t)((((x) << 20) & 0xfff00000) | \ + (((y) << 0) & 0x000fffff))) + +static dev_t +pack_12_20(int n, unsigned long numbers[], const char **error) +{ + dev_t dev = 0; + + if (n == 2) { + dev = makedev_12_20(numbers[0], numbers[1]); + if ((unsigned long)major_12_20(dev) != numbers[0]) + *error = iMajorError; + if ((unsigned long)minor_12_20(dev) != numbers[1]) + *error = iMinorError; + } else + *error = tooManyFields; + return (dev); +} + + +#define major_14_18(x) ((int32_t)(((x) & 0xfffc0000) >> 18)) +#define minor_14_18(x) ((int32_t)(((x) & 0x0003ffff) >> 0)) +#define makedev_14_18(x,y) ((dev_t)((((x) << 18) & 0xfffc0000) | \ + (((y) << 0) & 0x0003ffff))) + +static dev_t +pack_14_18(int n, unsigned long numbers[], const char **error) +{ + dev_t dev = 0; + + if (n == 2) { + dev = makedev_14_18(numbers[0], numbers[1]); + if ((unsigned long)major_14_18(dev) != numbers[0]) + *error = iMajorError; + if ((unsigned long)minor_14_18(dev) != numbers[1]) + *error = iMinorError; + } else + *error = tooManyFields; + return (dev); +} + + +#define major_8_24(x) ((int32_t)(((x) & 0xff000000) >> 24)) +#define minor_8_24(x) ((int32_t)(((x) & 0x00ffffff) >> 0)) +#define makedev_8_24(x,y) ((dev_t)((((x) << 24) & 0xff000000) | \ + (((y) << 0) & 0x00ffffff))) + +static dev_t +pack_8_24(int n, unsigned long numbers[], const char **error) +{ + dev_t dev = 0; + + if (n == 2) { + dev = makedev_8_24(numbers[0], numbers[1]); + if ((unsigned long)major_8_24(dev) != numbers[0]) + *error = iMajorError; + if ((unsigned long)minor_8_24(dev) != numbers[1]) + *error = iMinorError; + } else + *error = tooManyFields; + return (dev); +} + + +#define major_12_12_8(x) ((int32_t)(((x) & 0xfff00000) >> 20)) +#define unit_12_12_8(x) ((int32_t)(((x) & 0x000fff00) >> 8)) +#define subunit_12_12_8(x) ((int32_t)(((x) & 0x000000ff) >> 0)) +#define makedev_12_12_8(x,y,z) ((dev_t)((((x) << 20) & 0xfff00000) | \ + (((y) << 8) & 0x000fff00) | \ + (((z) << 0) & 0x000000ff))) + +static dev_t +pack_bsdos(int n, unsigned long numbers[], const char **error) +{ + dev_t dev = 0; + + if (n == 2) { + dev = makedev_12_20(numbers[0], numbers[1]); + if ((unsigned long)major_12_20(dev) != numbers[0]) + *error = iMajorError; + if ((unsigned long)minor_12_20(dev) != numbers[1]) + *error = iMinorError; + } else if (n == 3) { + dev = makedev_12_12_8(numbers[0], numbers[1], numbers[2]); + if ((unsigned long)major_12_12_8(dev) != numbers[0]) + *error = iMajorError; + if ((unsigned long)unit_12_12_8(dev) != numbers[1]) + *error = "invalid unit number"; + if ((unsigned long)subunit_12_12_8(dev) != numbers[2]) + *error = "invalid subunit number"; + } else + *error = tooManyFields; + return (dev); +} + + + /* list of formats and pack functions */ + /* this list must be sorted lexically */ +static struct format { + const char *name; + pack_t *pack; +} formats[] = { + {"386bsd", pack_8_8}, + {"4bsd", pack_8_8}, + {"bsdos", pack_bsdos}, + {"freebsd", pack_freebsd}, + {"hpux", pack_8_24}, + {"isc", pack_8_8}, + {"linux", pack_8_8}, + {"native", pack_native}, + {"netbsd", pack_netbsd}, + {"osf1", pack_12_20}, + {"sco", pack_8_8}, + {"solaris", pack_14_18}, + {"sunos", pack_8_8}, + {"svr3", pack_8_8}, + {"svr4", pack_14_18}, + {"ultrix", pack_8_8}, +}; + +static int +compare_format(const void *key, const void *element) +{ + const char *name; + const struct format *format; + + name = key; + format = element; + + return (strcmp(name, format->name)); +} + + +pack_t * +pack_find(const char *name) +{ + struct format *format; + + format = bsearch(name, formats, + sizeof(formats)/sizeof(formats[0]), + sizeof(formats[0]), compare_format); + if (format == 0) + return (NULL); + return (format->pack); +} diff --git a/Utilities/cmlibarchive/libarchive/archive_pack_dev.h b/Utilities/cmlibarchive/libarchive/archive_pack_dev.h new file mode 100644 index 0000000..749fd3d --- /dev/null +++ b/Utilities/cmlibarchive/libarchive/archive_pack_dev.h @@ -0,0 +1,49 @@ +/* $NetBSD: pack_dev.h,v 1.8 2013/06/14 16:28:20 tsutsui Exp $ */ + +/*- + * Copyright (c) 1998, 2001 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Charles M. Hannum. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* Originally from NetBSD's mknod(8) source. */ + +#ifndef _PACK_DEV_H +#define _PACK_DEV_H + +typedef dev_t pack_t(int, unsigned long [], const char **); + +pack_t *pack_find(const char *); +pack_t pack_native; + +#define major_netbsd(x) ((int32_t)((((x) & 0x000fff00) >> 8))) +#define minor_netbsd(x) ((int32_t)((((x) & 0xfff00000) >> 12) | \ + (((x) & 0x000000ff) >> 0))) +#define makedev_netbsd(x,y) ((dev_t)((((x) << 8) & 0x000fff00) | \ + (((y) << 12) & 0xfff00000) | \ + (((y) << 0) & 0x000000ff))) + +#endif /* _PACK_DEV_H */ diff --git a/Utilities/cmlibarchive/libarchive/archive_platform.h b/Utilities/cmlibarchive/libarchive/archive_platform.h index cdd9c7c..cbe08ec 100644 --- a/Utilities/cmlibarchive/libarchive/archive_platform.h +++ b/Utilities/cmlibarchive/libarchive/archive_platform.h @@ -66,15 +66,18 @@ * headers as required. */ -/* Get a real definition for __FBSDID if we can */ +/* Get a real definition for __FBSDID or __RCSID if we can */ #if HAVE_SYS_CDEFS_H #include <sys/cdefs.h> #endif -/* If not, define it so as to avoid dangling semicolons. */ +/* If not, define them so as to avoid dangling semicolons. */ #ifndef __FBSDID #define __FBSDID(a) struct _undefined_hack #endif +#ifndef __RCSID +#define __RCSID(a) struct _undefined_hack +#endif /* Old glibc mbsnrtowcs fails assertions in our use case. */ #if defined(__GLIBC__) && __GLIBC__ == 2 && __GLIBC_MINOR__ <= 1 diff --git a/Utilities/cmlibarchive/libarchive/archive_read.c b/Utilities/cmlibarchive/libarchive/archive_read.c index 796d37d..a65b94d 100644 --- a/Utilities/cmlibarchive/libarchive/archive_read.c +++ b/Utilities/cmlibarchive/libarchive/archive_read.c @@ -747,6 +747,59 @@ archive_read_header_position(struct archive *_a) } /* + * Returns 1 if the archive contains at least one encrypted entry. + * If the archive format not support encryption at all + * ARCHIVE_READ_FORMAT_ENCRYPTION_UNSUPPORTED is returned. + * If for any other reason (e.g. not enough data read so far) + * we cannot say whether there are encrypted entries, then + * ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW is returned. + * In general, this function will return values below zero when the + * reader is uncertain or totally uncapable of encryption support. + * When this function returns 0 you can be sure that the reader + * supports encryption detection but no encrypted entries have + * been found yet. + * + * NOTE: If the metadata/header of an archive is also encrypted, you + * cannot rely on the number of encrypted entries. That is why this + * function does not return the number of encrypted entries but# + * just shows that there are some. + */ +int +archive_read_has_encrypted_entries(struct archive *_a) +{ + struct archive_read *a = (struct archive_read *)_a; + int format_supports_encryption = archive_read_format_capabilities(_a) + & (ARCHIVE_READ_FORMAT_CAPS_ENCRYPT_DATA | ARCHIVE_READ_FORMAT_CAPS_ENCRYPT_METADATA); + + if (!_a || !format_supports_encryption) { + /* Format in general doesn't support encryption */ + return ARCHIVE_READ_FORMAT_ENCRYPTION_UNSUPPORTED; + } + + /* A reader potentially has read enough data now. */ + if (a->format && a->format->has_encrypted_entries) { + return (a->format->has_encrypted_entries)(a); + } + + /* For any other reason we cannot say how many entries are there. */ + return ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW; +} + +/* + * Returns a bitmask of capabilities that are supported by the archive format reader. + * If the reader has no special capabilities, ARCHIVE_READ_FORMAT_CAPS_NONE is returned. + */ +int +archive_read_format_capabilities(struct archive *_a) +{ + struct archive_read *a = (struct archive_read *)_a; + if (a && a->format && a->format->format_capabilties) { + return (a->format->format_capabilties)(a); + } + return ARCHIVE_READ_FORMAT_CAPS_NONE; +} + +/* * Read data from an archive entry, using a read(2)-style interface. * This is a convenience routine that just calls * archive_read_data_block and copies the results into the client @@ -1094,7 +1147,9 @@ __archive_read_register_format(struct archive_read *a, int (*read_data)(struct archive_read *, const void **, size_t *, int64_t *), int (*read_data_skip)(struct archive_read *), int64_t (*seek_data)(struct archive_read *, int64_t, int), - int (*cleanup)(struct archive_read *)) + int (*cleanup)(struct archive_read *), + int (*format_capabilities)(struct archive_read *), + int (*has_encrypted_entries)(struct archive_read *)) { int i, number_slots; @@ -1117,6 +1172,8 @@ __archive_read_register_format(struct archive_read *a, a->formats[i].cleanup = cleanup; a->formats[i].data = format_data; a->formats[i].name = name; + a->formats[i].format_capabilties = format_capabilities; + a->formats[i].has_encrypted_entries = has_encrypted_entries; return (ARCHIVE_OK); } } @@ -1557,10 +1614,9 @@ __archive_read_filter_seek(struct archive_read_filter *filter, int64_t offset, client->dataset[++cursor].begin_position = r; } offset -= client->dataset[cursor].begin_position; - if (offset < 0) - offset = 0; - else if (offset > client->dataset[cursor].total_size - 1) - offset = client->dataset[cursor].total_size - 1; + if (offset < 0 + || offset > client->dataset[cursor].total_size) + return ARCHIVE_FATAL; if ((r = client_seek_proxy(filter, offset, SEEK_SET)) < 0) return r; break; diff --git a/Utilities/cmlibarchive/libarchive/archive_read_disk_entry_from_file.c b/Utilities/cmlibarchive/libarchive/archive_read_disk_entry_from_file.c index e984aaa..e81cbec 100644 --- a/Utilities/cmlibarchive/libarchive/archive_read_disk_entry_from_file.c +++ b/Utilities/cmlibarchive/libarchive/archive_read_disk_entry_from_file.c @@ -399,7 +399,7 @@ setup_mac_metadata(struct archive_read_disk *a, #endif -#if defined(HAVE_POSIX_ACL) && defined(ACL_TYPE_NFS4) +#ifdef HAVE_POSIX_ACL static int translate_acl(struct archive_read_disk *a, struct archive_entry *entry, acl_t acl, int archive_entry_acl_type); @@ -419,6 +419,7 @@ setup_acls(struct archive_read_disk *a, archive_entry_acl_clear(entry); +#ifdef ACL_TYPE_NFS4 /* Try NFS4 ACL first. */ if (*fd >= 0) acl = acl_get_fd(*fd); @@ -447,6 +448,7 @@ setup_acls(struct archive_read_disk *a, acl_free(acl); return (ARCHIVE_OK); } +#endif /* Retrieve access ACL from file. */ if (*fd >= 0) @@ -492,6 +494,7 @@ static struct { {ARCHIVE_ENTRY_ACL_EXECUTE, ACL_EXECUTE}, {ARCHIVE_ENTRY_ACL_WRITE, ACL_WRITE}, {ARCHIVE_ENTRY_ACL_READ, ACL_READ}, +#ifdef ACL_TYPE_NFS4 {ARCHIVE_ENTRY_ACL_READ_DATA, ACL_READ_DATA}, {ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, ACL_LIST_DIRECTORY}, {ARCHIVE_ENTRY_ACL_WRITE_DATA, ACL_WRITE_DATA}, @@ -508,8 +511,10 @@ static struct { {ARCHIVE_ENTRY_ACL_WRITE_ACL, ACL_WRITE_ACL}, {ARCHIVE_ENTRY_ACL_WRITE_OWNER, ACL_WRITE_OWNER}, {ARCHIVE_ENTRY_ACL_SYNCHRONIZE, ACL_SYNCHRONIZE} +#endif }; +#ifdef ACL_TYPE_NFS4 static struct { int archive_inherit; int platform_inherit; @@ -519,21 +524,25 @@ static struct { {ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, ACL_ENTRY_NO_PROPAGATE_INHERIT}, {ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, ACL_ENTRY_INHERIT_ONLY} }; - +#endif static int translate_acl(struct archive_read_disk *a, struct archive_entry *entry, acl_t acl, int default_entry_acl_type) { acl_tag_t acl_tag; +#ifdef ACL_TYPE_NFS4 acl_entry_type_t acl_type; acl_flagset_t acl_flagset; + int brand, r; +#endif acl_entry_t acl_entry; acl_permset_t acl_permset; - int brand, i, r, entry_acl_type; + int i, entry_acl_type; int s, ae_id, ae_tag, ae_perm; const char *ae_name; +#ifdef ACL_TYPE_NFS4 // FreeBSD "brands" ACLs as POSIX.1e or NFSv4 // Make sure the "brand" on this ACL is consistent // with the default_entry_acl_type bits provided. @@ -560,6 +569,7 @@ translate_acl(struct archive_read_disk *a, return ARCHIVE_FAILED; break; } +#endif s = acl_get_entry(acl, ACL_FIRST_ENTRY, &acl_entry); @@ -592,9 +602,11 @@ translate_acl(struct archive_read_disk *a, case ACL_OTHER: ae_tag = ARCHIVE_ENTRY_ACL_OTHER; break; +#ifdef ACL_TYPE_NFS4 case ACL_EVERYONE: ae_tag = ARCHIVE_ENTRY_ACL_EVERYONE; break; +#endif default: /* Skip types that libarchive can't support. */ s = acl_get_entry(acl, ACL_NEXT_ENTRY, &acl_entry); @@ -605,6 +617,7 @@ translate_acl(struct archive_read_disk *a, // XXX acl_get_entry_type_np on FreeBSD returns EINVAL for // non-NFSv4 ACLs entry_acl_type = default_entry_acl_type; +#ifdef ACL_TYPE_NFS4 r = acl_get_entry_type_np(acl_entry, &acl_type); if (r == 0) { switch (acl_type) { @@ -634,9 +647,10 @@ translate_acl(struct archive_read_disk *a, ae_perm |= acl_inherit_map[i].archive_inherit; } +#endif acl_get_permset(acl_entry, &acl_permset); - for (i = 0; i < (int)(sizeof(acl_perm_map) / sizeof(acl_perm_map[0])); ++i) { + for (i = 0; i < (int)(sizeof(acl_perm_map) / sizeof(acl_perm_map[0])); ++i) { /* * acl_get_perm() is spelled differently on different * platforms; see above. diff --git a/Utilities/cmlibarchive/libarchive/archive_read_disk_posix.c b/Utilities/cmlibarchive/libarchive/archive_read_disk_posix.c index a13dbbf..94eb5e7 100644 --- a/Utilities/cmlibarchive/libarchive/archive_read_disk_posix.c +++ b/Utilities/cmlibarchive/libarchive/archive_read_disk_posix.c @@ -1973,7 +1973,7 @@ tree_dup(int fd) static volatile int can_dupfd_cloexec = 1; if (can_dupfd_cloexec) { - new_fd = fcntl(fd, F_DUPFD_CLOEXEC); + new_fd = fcntl(fd, F_DUPFD_CLOEXEC, 0); if (new_fd != -1) return (new_fd); /* Linux 2.6.18 - 2.6.23 declare F_DUPFD_CLOEXEC, diff --git a/Utilities/cmlibarchive/libarchive/archive_read_disk_windows.c b/Utilities/cmlibarchive/libarchive/archive_read_disk_windows.c index 9c5420d..5c0f366 100644 --- a/Utilities/cmlibarchive/libarchive/archive_read_disk_windows.c +++ b/Utilities/cmlibarchive/libarchive/archive_read_disk_windows.c @@ -929,7 +929,7 @@ next_entry(struct archive_read_disk *a, struct tree *t, else flags |= FILE_FLAG_SEQUENTIAL_SCAN; t->entry_fh = CreateFileW(tree_current_access_path(t), - GENERIC_READ, 0, NULL, OPEN_EXISTING, flags, NULL); + GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, flags, NULL); if (t->entry_fh == INVALID_HANDLE_VALUE) { archive_set_error(&a->archive, errno, "Couldn't open %ls", tree_current_path(a->tree)); @@ -1886,7 +1886,7 @@ tree_current_file_information(struct tree *t, BY_HANDLE_FILE_INFORMATION *st, if (sim_lstat && tree_current_is_physical_link(t)) flag |= FILE_FLAG_OPEN_REPARSE_POINT; - h = CreateFileW(tree_current_access_path(t), 0, 0, NULL, + h = CreateFileW(tree_current_access_path(t), 0, FILE_SHARE_READ, NULL, OPEN_EXISTING, flag, NULL); if (h == INVALID_HANDLE_VALUE) { la_dosmaperr(GetLastError()); @@ -2115,7 +2115,7 @@ archive_read_disk_entry_from_file(struct archive *_a, } else desiredAccess = GENERIC_READ; - h = CreateFileW(path, desiredAccess, 0, NULL, + h = CreateFileW(path, desiredAccess, FILE_SHARE_READ, NULL, OPEN_EXISTING, flag, NULL); if (h == INVALID_HANDLE_VALUE) { la_dosmaperr(GetLastError()); @@ -2162,7 +2162,7 @@ archive_read_disk_entry_from_file(struct archive *_a, if (fd >= 0) { h = (HANDLE)_get_osfhandle(fd); } else { - h = CreateFileW(path, GENERIC_READ, 0, NULL, + h = CreateFileW(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); if (h == INVALID_HANDLE_VALUE) { la_dosmaperr(GetLastError()); diff --git a/Utilities/cmlibarchive/libarchive/archive_read_private.h b/Utilities/cmlibarchive/libarchive/archive_read_private.h index 8a6c859..6636a59 100644 --- a/Utilities/cmlibarchive/libarchive/archive_read_private.h +++ b/Utilities/cmlibarchive/libarchive/archive_read_private.h @@ -207,6 +207,8 @@ struct archive_read { int (*read_data_skip)(struct archive_read *); int64_t (*seek_data)(struct archive_read *, int64_t, int); int (*cleanup)(struct archive_read *); + int (*format_capabilties)(struct archive_read *); + int (*has_encrypted_entries)(struct archive_read *); } formats[16]; struct archive_format_descriptor *format; /* Active format. */ @@ -218,15 +220,17 @@ struct archive_read { }; int __archive_read_register_format(struct archive_read *a, - void *format_data, - const char *name, - int (*bid)(struct archive_read *, int), - int (*options)(struct archive_read *, const char *, const char *), - int (*read_header)(struct archive_read *, struct archive_entry *), - int (*read_data)(struct archive_read *, const void **, size_t *, int64_t *), - int (*read_data_skip)(struct archive_read *), - int64_t (*seek_data)(struct archive_read *, int64_t, int), - int (*cleanup)(struct archive_read *)); + void *format_data, + const char *name, + int (*bid)(struct archive_read *, int), + int (*options)(struct archive_read *, const char *, const char *), + int (*read_header)(struct archive_read *, struct archive_entry *), + int (*read_data)(struct archive_read *, const void **, size_t *, int64_t *), + int (*read_data_skip)(struct archive_read *), + int64_t (*seek_data)(struct archive_read *, int64_t, int), + int (*cleanup)(struct archive_read *), + int (*format_capabilities)(struct archive_read *), + int (*has_encrypted_entries)(struct archive_read *)); int __archive_read_get_bidder(struct archive_read *a, struct archive_read_filter_bidder **bidder); diff --git a/Utilities/cmlibarchive/libarchive/archive_read_set_options.3 b/Utilities/cmlibarchive/libarchive/archive_read_set_options.3 index 6fe9f90..1a251ce 100644 --- a/Utilities/cmlibarchive/libarchive/archive_read_set_options.3 +++ b/Utilities/cmlibarchive/libarchive/archive_read_set_options.3 @@ -193,6 +193,28 @@ Defaults to enabled, use .Cm !rockridge to disable. .El +.It Format tar +.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 filenames. +.It Cm mac-ext +Support Mac OS metadata extension that records data in special +files beginning with a period and underscore. +Defaults to enabled on Mac OS, disabled on other platforms. +Use +.Cm !mac-ext +to disable. +.It Cm read_concatenated_archives +Ignore zeroed blocks in the archive, which occurs when multiple tar archives +have been concatenated together. Without this option, only the contents of +the first concatenated archive would be read. +.El .El .\" .Sh ERRORS diff --git a/Utilities/cmlibarchive/libarchive/archive_read_set_options.c b/Utilities/cmlibarchive/libarchive/archive_read_set_options.c index 793f8f7..46678b1 100644 --- a/Utilities/cmlibarchive/libarchive/archive_read_set_options.c +++ b/Utilities/cmlibarchive/libarchive/archive_read_set_options.c @@ -78,7 +78,7 @@ archive_set_format_option(struct archive *_a, const char *m, const char *o, struct archive_read *a = (struct archive_read *)_a; struct archive_format_descriptor *format; size_t i; - int r, rv = ARCHIVE_WARN; + int r, rv = ARCHIVE_WARN, matched_modules = 0; for (i = 0; i < sizeof(a->formats)/sizeof(a->formats[0]); i++) { format = &a->formats[i]; @@ -86,8 +86,11 @@ archive_set_format_option(struct archive *_a, const char *m, const char *o, format->name == NULL) /* This format does not support option. */ continue; - if (m != NULL && strcmp(format->name, m) != 0) - continue; + if (m != NULL) { + if (strcmp(format->name, m) != 0) + continue; + ++matched_modules; + } a->format = format; r = format->options(a, o, v); @@ -96,16 +99,13 @@ archive_set_format_option(struct archive *_a, const char *m, const char *o, if (r == ARCHIVE_FATAL) return (ARCHIVE_FATAL); - if (m != NULL) - return (r); - if (r == ARCHIVE_OK) rv = ARCHIVE_OK; } /* If the format name didn't match, return a special code for * _archive_set_option[s]. */ - if (rv == ARCHIVE_WARN && m != NULL) - rv = ARCHIVE_WARN - 1; + if (m != NULL && matched_modules == 0) + return ARCHIVE_WARN - 1; return (rv); } @@ -116,7 +116,7 @@ archive_set_filter_option(struct archive *_a, const char *m, const char *o, struct archive_read *a = (struct archive_read *)_a; struct archive_read_filter *filter; struct archive_read_filter_bidder *bidder; - int r, rv = ARCHIVE_WARN; + int r, rv = ARCHIVE_WARN, matched_modules = 0; for (filter = a->filter; filter != NULL; filter = filter->upstream) { bidder = filter->bidder; @@ -125,24 +125,24 @@ archive_set_filter_option(struct archive *_a, const char *m, const char *o, if (bidder->options == NULL) /* This bidder does not support option */ continue; - if (m != NULL && strcmp(filter->name, m) != 0) - continue; + if (m != NULL) { + if (strcmp(filter->name, m) != 0) + continue; + ++matched_modules; + } r = bidder->options(bidder, o, v); if (r == ARCHIVE_FATAL) return (ARCHIVE_FATAL); - if (m != NULL) - return (r); - if (r == ARCHIVE_OK) rv = ARCHIVE_OK; } /* If the filter name didn't match, return a special code for * _archive_set_option[s]. */ - if (rv == ARCHIVE_WARN && m != NULL) - rv = ARCHIVE_WARN - 1; + if (m != NULL && matched_modules == 0) + return ARCHIVE_WARN - 1; return (rv); } diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_filter_lzop.c b/Utilities/cmlibarchive/libarchive/archive_read_support_filter_lzop.c index 7958fa5..9ef2054 100644 --- a/Utilities/cmlibarchive/libarchive/archive_read_support_filter_lzop.c +++ b/Utilities/cmlibarchive/libarchive/archive_read_support_filter_lzop.c @@ -242,10 +242,11 @@ consume_header(struct archive_read_filter *self) if (version >= 0x940) { unsigned level = *p++; - if (method == 1 && level == 0) level = 3; - if (method == 2 && level == 0) level = 1; - if (method == 3 && level == 0) level = 9; - if (level < 1 && level > 9) { + unsigned default_level[] = {0, 3, 1, 9}; + if (level == 0) + /* Method is 1..3 here due to check above. */ + level = default_level[method]; + else if (level > 9) { archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC, "Invalid level"); return (ARCHIVE_FAILED); diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_filter_xz.c b/Utilities/cmlibarchive/libarchive/archive_read_support_filter_xz.c index 15824b1..7bda263 100644 --- a/Utilities/cmlibarchive/libarchive/archive_read_support_filter_xz.c +++ b/Utilities/cmlibarchive/libarchive/archive_read_support_filter_xz.c @@ -601,7 +601,7 @@ lzip_init(struct archive_read_filter *self) return (ARCHIVE_FATAL); } ret = lzma_raw_decoder(&(state->stream), filters); -#if LZMA_VERSION < 50000030 +#if LZMA_VERSION < 50010000 free(filters[0].options); #endif if (ret != LZMA_OK) { diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_format_7zip.c b/Utilities/cmlibarchive/libarchive/archive_read_support_format_7zip.c index 54ea245..8cd241b 100644 --- a/Utilities/cmlibarchive/libarchive/archive_read_support_format_7zip.c +++ b/Utilities/cmlibarchive/libarchive/archive_read_support_format_7zip.c @@ -69,7 +69,11 @@ __FBSDID("$FreeBSD$"); #define _7Z_BZ2 0x040202 #define _7Z_PPMD 0x030401 #define _7Z_DELTA 0x03 -#define _7Z_CRYPTO 0x06F10701 +#define _7Z_CRYPTO_MAIN_ZIP 0x06F10101 /* Main Zip crypto algo */ +#define _7Z_CRYPTO_RAR_29 0x06F10303 /* Rar29 AES-128 + (modified SHA-1) */ +#define _7Z_CRYPTO_AES_256_SHA_256 0x06F10701 /* AES-256 + SHA-256 */ + + #define _7Z_X86 0x03030103 #define _7Z_X86_BCJ2 0x0303011B #define _7Z_POWERPC 0x03030205 @@ -322,8 +326,13 @@ struct _7zip { struct archive_string_conv *sconv; char format_name[64]; + + /* Custom value that is non-zero if this archive contains encrypted entries. */ + int has_encrypted_entries; }; +static int archive_read_format_7zip_has_encrypted_entries(struct archive_read *); +static int archive_read_support_format_7zip_capabilities(struct archive_read *a); static int archive_read_format_7zip_bid(struct archive_read *, int); static int archive_read_format_7zip_cleanup(struct archive_read *); static int archive_read_format_7zip_read_data(struct archive_read *, @@ -401,6 +410,13 @@ archive_read_support_format_7zip(struct archive *_a) return (ARCHIVE_FATAL); } + /* + * Until enough data has been read, we cannot tell about + * any encrypted entries yet. + */ + zip->has_encrypted_entries = ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW; + + r = __archive_read_register_format(a, zip, "7zip", @@ -410,7 +426,9 @@ archive_read_support_format_7zip(struct archive *_a) archive_read_format_7zip_read_data, archive_read_format_7zip_read_data_skip, NULL, - archive_read_format_7zip_cleanup); + archive_read_format_7zip_cleanup, + archive_read_support_format_7zip_capabilities, + archive_read_format_7zip_has_encrypted_entries); if (r != ARCHIVE_OK) free(zip); @@ -418,6 +436,27 @@ archive_read_support_format_7zip(struct archive *_a) } static int +archive_read_support_format_7zip_capabilities(struct archive_read * a) +{ + (void)a; /* UNUSED */ + return (ARCHIVE_READ_FORMAT_CAPS_ENCRYPT_DATA | + ARCHIVE_READ_FORMAT_CAPS_ENCRYPT_METADATA); +} + + +static int +archive_read_format_7zip_has_encrypted_entries(struct archive_read *_a) +{ + if (_a && _a->format) { + struct _7zip * zip = (struct _7zip *)_a->format->data; + if (zip) { + return zip->has_encrypted_entries; + } + } + return ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW; +} + +static int archive_read_format_7zip_bid(struct archive_read *a, int best_bid) { const char *p; @@ -476,7 +515,7 @@ check_7zip_header_in_sfx(const char *p) switch ((unsigned char)p[5]) { case 0x1C: if (memcmp(p, _7ZIP_SIGNATURE, 6) != 0) - return (6); + return (6); /* * Test the CRC because its extraction code has 7-Zip * Magic Code, so we should do this in order not to @@ -484,15 +523,15 @@ check_7zip_header_in_sfx(const char *p) */ if (crc32(0, (const unsigned char *)p + 12, 20) != archive_le32dec(p + 8)) - return (6); + return (6); /* Hit the header! */ return (0); - case 0x37: return (5); - case 0x7A: return (4); - case 0xBC: return (3); - case 0xAF: return (2); - case 0x27: return (1); - default: return (6); + case 0x37: return (5); + case 0x7A: return (4); + case 0xBC: return (3); + case 0xAF: return (2); + case 0x27: return (1); + default: return (6); } } @@ -568,6 +607,19 @@ archive_read_format_7zip_read_header(struct archive_read *a, struct _7zip *zip = (struct _7zip *)a->format->data; struct _7zip_entry *zip_entry; int r, ret = ARCHIVE_OK; + struct _7z_folder *folder = 0; + uint64_t fidx = 0; + + /* + * It should be sufficient to call archive_read_next_header() for + * a reader to determine if an entry is encrypted or not. If the + * encryption of an entry is only detectable when calling + * archive_read_data(), so be it. We'll do the same check there + * as well. + */ + if (zip->has_encrypted_entries == ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW) { + zip->has_encrypted_entries = 0; + } a->archive.archive_format = ARCHIVE_FORMAT_7ZIP; if (a->archive.archive_format_name == NULL) @@ -604,6 +656,32 @@ archive_read_format_7zip_read_header(struct archive_read *a, return (ARCHIVE_FATAL); } + /* Figure out if the entry is encrypted by looking at the folder + that is associated to the current 7zip entry. If the folder + has a coder with a _7Z_CRYPTO codec then the folder is encrypted. + Hence the entry must also be encrypted. */ + if (zip_entry && zip_entry->folderIndex < zip->si.ci.numFolders) { + folder = &(zip->si.ci.folders[zip_entry->folderIndex]); + for (fidx=0; folder && fidx<folder->numCoders; fidx++) { + switch(folder->coders[fidx].codec) { + case _7Z_CRYPTO_MAIN_ZIP: + case _7Z_CRYPTO_RAR_29: + case _7Z_CRYPTO_AES_256_SHA_256: { + archive_entry_set_is_data_encrypted(entry, 1); + zip->has_encrypted_entries = 1; + break; + } + } + } + } + + /* Now that we've checked for encryption, if there were still no + * encrypted entries found we can say for sure that there are none. + */ + if (zip->has_encrypted_entries == ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW) { + zip->has_encrypted_entries = 0; + } + if (archive_entry_copy_pathname_l(entry, (const char *)zip_entry->utf16name, zip_entry->name_len, zip->sconv) != 0) { @@ -707,6 +785,10 @@ archive_read_format_7zip_read_data(struct archive_read *a, zip = (struct _7zip *)(a->format->data); + if (zip->has_encrypted_entries == ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW) { + zip->has_encrypted_entries = 0; + } + if (zip->pack_stream_bytes_unconsumed) read_consume(a); @@ -969,7 +1051,7 @@ init_decompression(struct archive_read *a, struct _7zip *zip, { lzma_options_delta delta_opt; lzma_filter filters[LZMA_FILTERS_MAX]; -#if LZMA_VERSION < 50000030 +#if LZMA_VERSION < 50010000 lzma_filter *ff; #endif int fi = 0; @@ -994,7 +1076,7 @@ init_decompression(struct archive_read *a, struct _7zip *zip, * for BCJ+LZMA. If we were able to tell the uncompressed * size to liblzma when using lzma_raw_decoder() liblzma * could correctly deal with BCJ+LZMA. But unfortunately - * there is no way to do that. + * there is no way to do that. * Discussion about this can be found at XZ Utils forum. */ if (coder2 != NULL) { @@ -1056,7 +1138,7 @@ init_decompression(struct archive_read *a, struct _7zip *zip, else filters[fi].id = LZMA_FILTER_LZMA1; filters[fi].options = NULL; -#if LZMA_VERSION < 50000030 +#if LZMA_VERSION < 50010000 ff = &filters[fi]; #endif r = lzma_properties_decode(&filters[fi], NULL, @@ -1070,7 +1152,7 @@ init_decompression(struct archive_read *a, struct _7zip *zip, filters[fi].id = LZMA_VLI_UNKNOWN; filters[fi].options = NULL; r = lzma_raw_decoder(&(zip->lzstream), filters); -#if LZMA_VERSION < 50000030 +#if LZMA_VERSION < 50010000 free(ff->options); #endif if (r != LZMA_OK) { @@ -1203,6 +1285,17 @@ init_decompression(struct archive_read *a, struct _7zip *zip, archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Unexpected codec ID: %lX", zip->codec); return (ARCHIVE_FAILED); + case _7Z_CRYPTO_MAIN_ZIP: + case _7Z_CRYPTO_RAR_29: + case _7Z_CRYPTO_AES_256_SHA_256: + if (a->entry) { + archive_entry_set_is_metadata_encrypted(a->entry, 1); + archive_entry_set_is_data_encrypted(a->entry, 1); + zip->has_encrypted_entries = 1; + } + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "Crypto codec not supported yet (ID: 0x%lX)", zip->codec); + return (ARCHIVE_FAILED); default: archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Unknown codec ID: %lX", zip->codec); @@ -1426,7 +1519,7 @@ decompress(struct archive_read *a, struct _7zip *zip, do { int sym; - + sym = __archive_ppmd7_functions.Ppmd7_DecodeSymbol( &(zip->ppmd7_context), &(zip->range_dec.p)); if (sym < 0) { @@ -2755,6 +2848,7 @@ slurp_central_directory(struct archive_read *a, struct _7zip *zip, zip->header_crc32 = 0; zip->header_is_encoded = 0; zip->header_is_being_read = 1; + zip->has_encrypted_entries = 0; check_header_crc = 1; if ((p = header_bytes(a, 1)) == NULL) { @@ -3170,7 +3264,7 @@ read_stream(struct archive_read *a, const void **buff, size_t size, return (r); /* - * Skip the bytes we alrady has skipped in skip_stream(). + * Skip the bytes we alrady has skipped in skip_stream(). */ while (skip_bytes) { ssize_t skipped; @@ -3235,16 +3329,36 @@ setup_decode_folder(struct archive_read *a, struct _7z_folder *folder, * Check coder types. */ for (i = 0; i < folder->numCoders; i++) { - if (folder->coders[i].codec == _7Z_CRYPTO) { - archive_set_error(&(a->archive), - ARCHIVE_ERRNO_MISC, - "The %s is encrypted, " - "but currently not supported", cname); - return (ARCHIVE_FATAL); + switch(folder->coders[i].codec) { + case _7Z_CRYPTO_MAIN_ZIP: + case _7Z_CRYPTO_RAR_29: + case _7Z_CRYPTO_AES_256_SHA_256: { + /* For entry that is associated with this folder, mark + it as encrypted (data+metadata). */ + zip->has_encrypted_entries = 1; + if (a->entry) { + archive_entry_set_is_data_encrypted(a->entry, 1); + archive_entry_set_is_metadata_encrypted(a->entry, 1); + } + archive_set_error(&(a->archive), + ARCHIVE_ERRNO_MISC, + "The %s is encrypted, " + "but currently not supported", cname); + return (ARCHIVE_FATAL); + } + case _7Z_X86_BCJ2: { + found_bcj2++; + break; + } } - if (folder->coders[i].codec == _7Z_X86_BCJ2) - found_bcj2++; } + /* Now that we've checked for encryption, if there were still no + * encrypted entries found we can say for sure that there are none. + */ + if (zip->has_encrypted_entries == ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW) { + zip->has_encrypted_entries = 0; + } + if ((folder->numCoders > 2 && !found_bcj2) || found_bcj2 > 1) { archive_set_error(&(a->archive), ARCHIVE_ERRNO_MISC, diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_format_ar.c b/Utilities/cmlibarchive/libarchive/archive_read_support_format_ar.c index 40be18c..82756c9 100644 --- a/Utilities/cmlibarchive/libarchive/archive_read_support_format_ar.c +++ b/Utilities/cmlibarchive/libarchive/archive_read_support_format_ar.c @@ -122,7 +122,9 @@ archive_read_support_format_ar(struct archive *_a) archive_read_format_ar_read_data, archive_read_format_ar_skip, NULL, - archive_read_format_ar_cleanup); + archive_read_format_ar_cleanup, + NULL, + NULL); if (r != ARCHIVE_OK) { free(ar); diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_format_cab.c b/Utilities/cmlibarchive/libarchive/archive_read_support_format_cab.c index 4dd38db..6356963 100644 --- a/Utilities/cmlibarchive/libarchive/archive_read_support_format_cab.c +++ b/Utilities/cmlibarchive/libarchive/archive_read_support_format_cab.c @@ -383,7 +383,9 @@ archive_read_support_format_cab(struct archive *_a) archive_read_format_cab_read_data, archive_read_format_cab_read_data_skip, NULL, - archive_read_format_cab_cleanup); + archive_read_format_cab_cleanup, + NULL, + NULL); if (r != ARCHIVE_OK) free(cab); diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_format_cpio.c b/Utilities/cmlibarchive/libarchive/archive_read_support_format_cpio.c index 819f4a4..0b69689 100644 --- a/Utilities/cmlibarchive/libarchive/archive_read_support_format_cpio.c +++ b/Utilities/cmlibarchive/libarchive/archive_read_support_format_cpio.c @@ -243,7 +243,9 @@ archive_read_support_format_cpio(struct archive *_a) archive_read_format_cpio_read_data, archive_read_format_cpio_skip, NULL, - archive_read_format_cpio_cleanup); + archive_read_format_cpio_cleanup, + NULL, + NULL); if (r != ARCHIVE_OK) free(cpio); diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_format_empty.c b/Utilities/cmlibarchive/libarchive/archive_read_support_format_empty.c index 3660738..c641eb9 100644 --- a/Utilities/cmlibarchive/libarchive/archive_read_support_format_empty.c +++ b/Utilities/cmlibarchive/libarchive/archive_read_support_format_empty.c @@ -54,6 +54,8 @@ archive_read_support_format_empty(struct archive *_a) archive_read_format_empty_read_data, NULL, NULL, + NULL, + NULL, NULL); return (r); diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_format_iso9660.c b/Utilities/cmlibarchive/libarchive/archive_read_support_format_iso9660.c index 8147461..2219e61 100644 --- a/Utilities/cmlibarchive/libarchive/archive_read_support_format_iso9660.c +++ b/Utilities/cmlibarchive/libarchive/archive_read_support_format_iso9660.c @@ -478,7 +478,9 @@ archive_read_support_format_iso9660(struct archive *_a) archive_read_format_iso9660_read_data, archive_read_format_iso9660_read_data_skip, NULL, - archive_read_format_iso9660_cleanup); + archive_read_format_iso9660_cleanup, + NULL, + NULL); if (r != ARCHIVE_OK) { free(iso9660); diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_format_lha.c b/Utilities/cmlibarchive/libarchive/archive_read_support_format_lha.c index f702949..b88731a 100644 --- a/Utilities/cmlibarchive/libarchive/archive_read_support_format_lha.c +++ b/Utilities/cmlibarchive/libarchive/archive_read_support_format_lha.c @@ -320,7 +320,9 @@ archive_read_support_format_lha(struct archive *_a) archive_read_format_lha_read_data, archive_read_format_lha_read_data_skip, NULL, - archive_read_format_lha_cleanup); + archive_read_format_lha_cleanup, + NULL, + NULL); if (r != ARCHIVE_OK) free(lha); diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_format_mtree.c b/Utilities/cmlibarchive/libarchive/archive_read_support_format_mtree.c index c4e7021..d82d4c1 100644 --- a/Utilities/cmlibarchive/libarchive/archive_read_support_format_mtree.c +++ b/Utilities/cmlibarchive/libarchive/archive_read_support_format_mtree.c @@ -51,6 +51,7 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_read_support_format_mtree.c 2011 #include "archive_private.h" #include "archive_read_private.h" #include "archive_string.h" +#include "archive_pack_dev.h" #ifndef O_BINARY #define O_BINARY 0 @@ -103,6 +104,7 @@ struct mtree { struct archive_entry_linkresolver *resolver; int64_t cur_size; + char checkfs; }; static int bid_keycmp(const char *, const char *, ssize_t); @@ -173,6 +175,29 @@ get_time_t_min(void) #endif } +static int +archive_read_format_mtree_options(struct archive_read *a, + const char *key, const char *val) +{ + struct mtree *mtree; + + mtree = (struct mtree *)(a->format->data); + if (strcmp(key, "checkfs") == 0) { + /* Allows to read information missing from the mtree from the file system */ + if (val == NULL || val[0] == 0) { + mtree->checkfs = 0; + } else { + mtree->checkfs = 1; + } + return (ARCHIVE_OK); + } + + /* Note: The "warn" return is just to inform the options + * supervisor that we didn't handle it. It will generate + * a suitable error if no one used this option. */ + return (ARCHIVE_WARN); +} + static void free_options(struct mtree_option *head) { @@ -205,7 +230,7 @@ archive_read_support_format_mtree(struct archive *_a) mtree->fd = -1; r = __archive_read_register_format(a, mtree, "mtree", - mtree_bid, NULL, read_header, read_data, skip, NULL, cleanup); + mtree_bid, archive_read_format_mtree_options, read_header, read_data, skip, NULL, cleanup, NULL, NULL); if (r != ARCHIVE_OK) free(mtree); @@ -367,7 +392,7 @@ bid_keyword(const char *p, ssize_t len) "gid", "gname", NULL }; static const char *keys_il[] = { - "ignore", "link", NULL + "ignore", "inode", "link", NULL }; static const char *keys_m[] = { "md5", "md5digest", "mode", NULL @@ -376,7 +401,7 @@ bid_keyword(const char *p, ssize_t len) "nlink", "nochange", "optional", NULL }; static const char *keys_r[] = { - "rmd160", "rmd160digest", NULL + "resdevice", "rmd160", "rmd160digest", NULL }; static const char *keys_s[] = { "sha1", "sha1digest", @@ -1103,162 +1128,164 @@ parse_file(struct archive_read *a, struct archive_entry *entry, mtree->current_dir.length = n; } - /* - * Try to open and stat the file to get the real size - * and other file info. It would be nice to avoid - * this here so that getting a listing of an mtree - * wouldn't require opening every referenced contents - * file. But then we wouldn't know the actual - * contents size, so I don't see a really viable way - * around this. (Also, we may want to someday pull - * other unspecified info from the contents file on - * disk.) - */ - mtree->fd = -1; - if (archive_strlen(&mtree->contents_name) > 0) - path = mtree->contents_name.s; - else - path = archive_entry_pathname(entry); - - if (archive_entry_filetype(entry) == AE_IFREG || - archive_entry_filetype(entry) == AE_IFDIR) { - mtree->fd = open(path, O_RDONLY | O_BINARY | O_CLOEXEC); - __archive_ensure_cloexec_flag(mtree->fd); - if (mtree->fd == -1 && - (errno != ENOENT || - archive_strlen(&mtree->contents_name) > 0)) { - archive_set_error(&a->archive, errno, - "Can't open %s", path); - r = ARCHIVE_WARN; + if (mtree->checkfs) { + /* + * Try to open and stat the file to get the real size + * and other file info. It would be nice to avoid + * this here so that getting a listing of an mtree + * wouldn't require opening every referenced contents + * file. But then we wouldn't know the actual + * contents size, so I don't see a really viable way + * around this. (Also, we may want to someday pull + * other unspecified info from the contents file on + * disk.) + */ + mtree->fd = -1; + if (archive_strlen(&mtree->contents_name) > 0) + path = mtree->contents_name.s; + else + path = archive_entry_pathname(entry); + + if (archive_entry_filetype(entry) == AE_IFREG || + archive_entry_filetype(entry) == AE_IFDIR) { + mtree->fd = open(path, O_RDONLY | O_BINARY | O_CLOEXEC); + __archive_ensure_cloexec_flag(mtree->fd); + if (mtree->fd == -1 && + (errno != ENOENT || + archive_strlen(&mtree->contents_name) > 0)) { + archive_set_error(&a->archive, errno, + "Can't open %s", path); + r = ARCHIVE_WARN; + } } - } - st = &st_storage; - if (mtree->fd >= 0) { - if (fstat(mtree->fd, st) == -1) { - archive_set_error(&a->archive, errno, - "Could not fstat %s", path); - r = ARCHIVE_WARN; - /* If we can't stat it, don't keep it open. */ - close(mtree->fd); - mtree->fd = -1; + st = &st_storage; + if (mtree->fd >= 0) { + if (fstat(mtree->fd, st) == -1) { + archive_set_error(&a->archive, errno, + "Could not fstat %s", path); + r = ARCHIVE_WARN; + /* If we can't stat it, don't keep it open. */ + close(mtree->fd); + mtree->fd = -1; + st = NULL; + } + } else if (lstat(path, st) == -1) { st = NULL; } - } else if (lstat(path, st) == -1) { - st = NULL; - } - /* - * Check for a mismatch between the type in the specification and - * the type of the contents object on disk. - */ - if (st != NULL) { - if ( - ((st->st_mode & S_IFMT) == S_IFREG && - archive_entry_filetype(entry) == AE_IFREG) + /* + * Check for a mismatch between the type in the specification and + * the type of the contents object on disk. + */ + if (st != NULL) { + if ( + ((st->st_mode & S_IFMT) == S_IFREG && + archive_entry_filetype(entry) == AE_IFREG) #ifdef S_IFLNK - || ((st->st_mode & S_IFMT) == S_IFLNK && - archive_entry_filetype(entry) == AE_IFLNK) + || ((st->st_mode & S_IFMT) == S_IFLNK && + archive_entry_filetype(entry) == AE_IFLNK) #endif #ifdef S_IFSOCK - || ((st->st_mode & S_IFSOCK) == S_IFSOCK && - archive_entry_filetype(entry) == AE_IFSOCK) + || ((st->st_mode & S_IFSOCK) == S_IFSOCK && + archive_entry_filetype(entry) == AE_IFSOCK) #endif #ifdef S_IFCHR - || ((st->st_mode & S_IFMT) == S_IFCHR && - archive_entry_filetype(entry) == AE_IFCHR) + || ((st->st_mode & S_IFMT) == S_IFCHR && + archive_entry_filetype(entry) == AE_IFCHR) #endif #ifdef S_IFBLK - || ((st->st_mode & S_IFMT) == S_IFBLK && - archive_entry_filetype(entry) == AE_IFBLK) + || ((st->st_mode & S_IFMT) == S_IFBLK && + archive_entry_filetype(entry) == AE_IFBLK) #endif - || ((st->st_mode & S_IFMT) == S_IFDIR && - archive_entry_filetype(entry) == AE_IFDIR) + || ((st->st_mode & S_IFMT) == S_IFDIR && + archive_entry_filetype(entry) == AE_IFDIR) #ifdef S_IFIFO - || ((st->st_mode & S_IFMT) == S_IFIFO && - archive_entry_filetype(entry) == AE_IFIFO) + || ((st->st_mode & S_IFMT) == S_IFIFO && + archive_entry_filetype(entry) == AE_IFIFO) #endif - ) { - /* Types match. */ - } else { - /* Types don't match; bail out gracefully. */ - if (mtree->fd >= 0) - close(mtree->fd); - mtree->fd = -1; - if (parsed_kws & MTREE_HAS_OPTIONAL) { - /* It's not an error for an optional entry - to not match disk. */ - *use_next = 1; - } else if (r == ARCHIVE_OK) { - archive_set_error(&a->archive, - ARCHIVE_ERRNO_MISC, - "mtree specification has different type for %s", - archive_entry_pathname(entry)); - r = ARCHIVE_WARN; - } - return r; + ) { + /* Types match. */ + } else { + /* Types don't match; bail out gracefully. */ + if (mtree->fd >= 0) + close(mtree->fd); + mtree->fd = -1; + if (parsed_kws & MTREE_HAS_OPTIONAL) { + /* It's not an error for an optional entry + to not match disk. */ + *use_next = 1; + } else if (r == ARCHIVE_OK) { + archive_set_error(&a->archive, + ARCHIVE_ERRNO_MISC, + "mtree specification has different type for %s", + archive_entry_pathname(entry)); + r = ARCHIVE_WARN; + } + return r; + } } - } - /* - * If there is a contents file on disk, pick some of the metadata - * from that file. For most of these, we only set it from the contents - * if it wasn't already parsed from the specification. - */ - if (st != NULL) { - if (((parsed_kws & MTREE_HAS_DEVICE) == 0 || - (parsed_kws & MTREE_HAS_NOCHANGE) != 0) && - (archive_entry_filetype(entry) == AE_IFCHR || - archive_entry_filetype(entry) == AE_IFBLK)) - archive_entry_set_rdev(entry, st->st_rdev); - if ((parsed_kws & (MTREE_HAS_GID | MTREE_HAS_GNAME)) == 0 || - (parsed_kws & MTREE_HAS_NOCHANGE) != 0) - archive_entry_set_gid(entry, st->st_gid); - if ((parsed_kws & (MTREE_HAS_UID | MTREE_HAS_UNAME)) == 0 || - (parsed_kws & MTREE_HAS_NOCHANGE) != 0) - archive_entry_set_uid(entry, st->st_uid); - if ((parsed_kws & MTREE_HAS_MTIME) == 0 || - (parsed_kws & MTREE_HAS_NOCHANGE) != 0) { + /* + * If there is a contents file on disk, pick some of the metadata + * from that file. For most of these, we only set it from the contents + * if it wasn't already parsed from the specification. + */ + if (st != NULL) { + if (((parsed_kws & MTREE_HAS_DEVICE) == 0 || + (parsed_kws & MTREE_HAS_NOCHANGE) != 0) && + (archive_entry_filetype(entry) == AE_IFCHR || + archive_entry_filetype(entry) == AE_IFBLK)) + archive_entry_set_rdev(entry, st->st_rdev); + if ((parsed_kws & (MTREE_HAS_GID | MTREE_HAS_GNAME)) == 0 || + (parsed_kws & MTREE_HAS_NOCHANGE) != 0) + archive_entry_set_gid(entry, st->st_gid); + if ((parsed_kws & (MTREE_HAS_UID | MTREE_HAS_UNAME)) == 0 || + (parsed_kws & MTREE_HAS_NOCHANGE) != 0) + archive_entry_set_uid(entry, st->st_uid); + if ((parsed_kws & MTREE_HAS_MTIME) == 0 || + (parsed_kws & MTREE_HAS_NOCHANGE) != 0) { #if HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC - archive_entry_set_mtime(entry, st->st_mtime, - st->st_mtimespec.tv_nsec); + archive_entry_set_mtime(entry, st->st_mtime, + st->st_mtimespec.tv_nsec); #elif HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC - archive_entry_set_mtime(entry, st->st_mtime, - st->st_mtim.tv_nsec); + archive_entry_set_mtime(entry, st->st_mtime, + st->st_mtim.tv_nsec); #elif HAVE_STRUCT_STAT_ST_MTIME_N - archive_entry_set_mtime(entry, st->st_mtime, - st->st_mtime_n); + archive_entry_set_mtime(entry, st->st_mtime, + st->st_mtime_n); #elif HAVE_STRUCT_STAT_ST_UMTIME - archive_entry_set_mtime(entry, st->st_mtime, - st->st_umtime*1000); + archive_entry_set_mtime(entry, st->st_mtime, + st->st_umtime*1000); #elif HAVE_STRUCT_STAT_ST_MTIME_USEC - archive_entry_set_mtime(entry, st->st_mtime, - st->st_mtime_usec*1000); + archive_entry_set_mtime(entry, st->st_mtime, + st->st_mtime_usec*1000); #else - archive_entry_set_mtime(entry, st->st_mtime, 0); + archive_entry_set_mtime(entry, st->st_mtime, 0); #endif + } + if ((parsed_kws & MTREE_HAS_NLINK) == 0 || + (parsed_kws & MTREE_HAS_NOCHANGE) != 0) + archive_entry_set_nlink(entry, st->st_nlink); + if ((parsed_kws & MTREE_HAS_PERM) == 0 || + (parsed_kws & MTREE_HAS_NOCHANGE) != 0) + archive_entry_set_perm(entry, st->st_mode); + if ((parsed_kws & MTREE_HAS_SIZE) == 0 || + (parsed_kws & MTREE_HAS_NOCHANGE) != 0) + archive_entry_set_size(entry, st->st_size); + archive_entry_set_ino(entry, st->st_ino); + archive_entry_set_dev(entry, st->st_dev); + + archive_entry_linkify(mtree->resolver, &entry, &sparse_entry); + } else if (parsed_kws & MTREE_HAS_OPTIONAL) { + /* + * Couldn't open the entry, stat it or the on-disk type + * didn't match. If this entry is optional, just ignore it + * and read the next header entry. + */ + *use_next = 1; + return ARCHIVE_OK; } - if ((parsed_kws & MTREE_HAS_NLINK) == 0 || - (parsed_kws & MTREE_HAS_NOCHANGE) != 0) - archive_entry_set_nlink(entry, st->st_nlink); - if ((parsed_kws & MTREE_HAS_PERM) == 0 || - (parsed_kws & MTREE_HAS_NOCHANGE) != 0) - archive_entry_set_perm(entry, st->st_mode); - if ((parsed_kws & MTREE_HAS_SIZE) == 0 || - (parsed_kws & MTREE_HAS_NOCHANGE) != 0) - archive_entry_set_size(entry, st->st_size); - archive_entry_set_ino(entry, st->st_ino); - archive_entry_set_dev(entry, st->st_dev); - - archive_entry_linkify(mtree->resolver, &entry, &sparse_entry); - } else if (parsed_kws & MTREE_HAS_OPTIONAL) { - /* - * Couldn't open the entry, stat it or the on-disk type - * didn't match. If this entry is optional, just ignore it - * and read the next header entry. - */ - *use_next = 1; - return ARCHIVE_OK; } mtree->cur_size = archive_entry_size(entry); @@ -1292,33 +1319,82 @@ parse_line(struct archive_read *a, struct archive_entry *entry, /* * Device entries have one of the following forms: - * raw dev_t - * format,major,minor[,subdevice] - * - * Just use major and minor, no translation etc is done - * between formats. + * - raw dev_t + * - format,major,minor[,subdevice] + * When parsing succeeded, `pdev' will contain the appropriate dev_t value. */ -static int -parse_device(struct archive *a, struct archive_entry *entry, char *val) + +/* strsep() is not in C90, but strcspn() is. */ +/* Taken from http://unixpapa.com/incnote/string.html */ +static char * +la_strsep(char **sp, char *sep) { - char *comma1, *comma2; + char *p, *s; + if (sp == NULL || *sp == NULL || **sp == '\0') + return(NULL); + s = *sp; + p = s + strcspn(s, sep); + if (*p != '\0') + *p++ = '\0'; + *sp = p; + return(s); +} - comma1 = strchr(val, ','); - if (comma1 == NULL) { - archive_entry_set_dev(entry, (dev_t)mtree_atol10(&val)); - return (ARCHIVE_OK); - } - ++comma1; - comma2 = strchr(comma1, ','); - if (comma2 == NULL) { - archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT, - "Malformed device attribute"); - return (ARCHIVE_WARN); +static int +parse_device(dev_t *pdev, struct archive *a, char *val) +{ +#define MAX_PACK_ARGS 3 + unsigned long numbers[MAX_PACK_ARGS]; + char *p, *dev; + int argc; + pack_t *pack; + dev_t result; + const char *error = NULL; + + memset(pdev, 0, sizeof(*pdev)); + if ((dev = strchr(val, ',')) != NULL) { + /* + * Device's major/minor are given in a specified format. + * Decode and pack it accordingly. + */ + *dev++ = '\0'; + if ((pack = pack_find(val)) == NULL) { + archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT, + "Unknown format `%s'", val); + return ARCHIVE_WARN; + } + argc = 0; + while ((p = la_strsep(&dev, ",")) != NULL) { + if (*p == '\0') { + archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT, + "Missing number"); + return ARCHIVE_WARN; + } + numbers[argc++] = mtree_atol(&p); + if (argc > MAX_PACK_ARGS) { + archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT, + "Too many arguments"); + return ARCHIVE_WARN; + } + } + if (argc < 2) { + archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT, + "Not enough arguments"); + return ARCHIVE_WARN; + } + result = (*pack)(argc, numbers, &error); + if (error != NULL) { + archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT, + "%s", error); + return ARCHIVE_WARN; + } + } else { + /* file system raw value. */ + result = (dev_t)mtree_atol(&val); } - ++comma2; - archive_entry_set_rdevmajor(entry, (dev_t)mtree_atol(&comma1)); - archive_entry_set_rdevminor(entry, (dev_t)mtree_atol(&comma2)); - return (ARCHIVE_OK); + *pdev = result; + return ARCHIVE_OK; +#undef MAX_PACK_ARGS } /* @@ -1374,8 +1450,16 @@ parse_keyword(struct archive_read *a, struct mtree *mtree, break; case 'd': if (strcmp(key, "device") == 0) { + /* stat(2) st_rdev field, e.g. the major/minor IDs + * of a char/block special file */ + int r; + dev_t dev; + *parsed_kws |= MTREE_HAS_DEVICE; - return parse_device(&a->archive, entry, val); + r = parse_device(&dev, &a->archive, val); + if (r == ARCHIVE_OK) + archive_entry_set_rdev(entry, dev); + return r; } case 'f': if (strcmp(key, "flags") == 0) { @@ -1394,6 +1478,11 @@ parse_keyword(struct archive_read *a, struct mtree *mtree, archive_entry_copy_gname(entry, val); break; } + case 'i': + if (strcmp(key, "inode") == 0) { + archive_entry_set_ino(entry, mtree_atol10(&val)); + break; + } case 'l': if (strcmp(key, "link") == 0) { archive_entry_copy_symlink(entry, val); @@ -1423,6 +1512,17 @@ parse_keyword(struct archive_read *a, struct mtree *mtree, break; } case 'r': + if (strcmp(key, "resdevice") == 0) { + /* stat(2) st_dev field, e.g. the device ID where the + * inode resides */ + int r; + dev_t dev; + + r = parse_device(&dev, &a->archive, val); + if (r == ARCHIVE_OK) + archive_entry_set_dev(entry, dev); + return r; + } if (strcmp(key, "rmd160") == 0 || strcmp(key, "rmd160digest") == 0) break; diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_format_rar.c b/Utilities/cmlibarchive/libarchive/archive_read_support_format_rar.c index dc1563d..4c56834 100644 --- a/Utilities/cmlibarchive/libarchive/archive_read_support_format_rar.c +++ b/Utilities/cmlibarchive/libarchive/archive_read_support_format_rar.c @@ -304,8 +304,15 @@ struct rar ssize_t avail_in; const unsigned char *next_in; } br; + + /* + * Custom field to denote that this archive contains encrypted entries + */ + int has_encrypted_entries; }; +static int archive_read_support_format_rar_capabilities(struct archive_read *); +static int archive_read_format_rar_has_encrypted_entries(struct archive_read *); static int archive_read_format_rar_bid(struct archive_read *, int); static int archive_read_format_rar_options(struct archive_read *, const char *, const char *); @@ -646,6 +653,12 @@ archive_read_support_format_rar(struct archive *_a) } memset(rar, 0, sizeof(*rar)); + /* + * Until enough data has been read, we cannot tell about + * any encrypted entries yet. + */ + rar->has_encrypted_entries = ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW; + r = __archive_read_register_format(a, rar, "rar", @@ -655,7 +668,9 @@ archive_read_support_format_rar(struct archive *_a) archive_read_format_rar_read_data, archive_read_format_rar_read_data_skip, archive_read_format_rar_seek_data, - archive_read_format_rar_cleanup); + archive_read_format_rar_cleanup, + archive_read_support_format_rar_capabilities, + archive_read_format_rar_has_encrypted_entries); if (r != ARCHIVE_OK) free(rar); @@ -663,6 +678,27 @@ archive_read_support_format_rar(struct archive *_a) } static int +archive_read_support_format_rar_capabilities(struct archive_read * a) +{ + (void)a; /* UNUSED */ + return (ARCHIVE_READ_FORMAT_CAPS_ENCRYPT_DATA + | ARCHIVE_READ_FORMAT_CAPS_ENCRYPT_METADATA); +} + +static int +archive_read_format_rar_has_encrypted_entries(struct archive_read *_a) +{ + if (_a && _a->format) { + struct rar * rar = (struct rar *)_a->format->data; + if (rar) { + return rar->has_encrypted_entries; + } + } + return ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW; +} + + +static int archive_read_format_rar_bid(struct archive_read *a, int best_bid) { const char *p; @@ -755,7 +791,7 @@ archive_read_format_rar_options(struct archive_read *a, { struct rar *rar; int ret = ARCHIVE_FAILED; - + rar = (struct rar *)(a->format->data); if (strcmp(key, "hdrcharset") == 0) { if (val == NULL || val[0] == 0) @@ -797,6 +833,17 @@ archive_read_format_rar_read_header(struct archive_read *a, rar = (struct rar *)(a->format->data); + /* + * It should be sufficient to call archive_read_next_header() for + * a reader to determine if an entry is encrypted or not. If the + * encryption of an entry is only detectable when calling + * archive_read_data(), so be it. We'll do the same check there + * as well. + */ + if (rar->has_encrypted_entries == ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW) { + rar->has_encrypted_entries = 0; + } + /* RAR files can be generated without EOF headers, so return ARCHIVE_EOF if * this fails. */ @@ -857,9 +904,14 @@ archive_read_format_rar_read_header(struct archive_read *a, sizeof(rar->reserved2)); } + /* Main header is password encrytped, so we cannot read any + file names or any other info about files from the header. */ if (rar->main_flags & MHD_PASSWORD) { - archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, + archive_entry_set_is_metadata_encrypted(entry, 1); + archive_entry_set_is_data_encrypted(entry, 1); + rar->has_encrypted_entries = 1; + archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, "RAR encryption support unavailable."); return (ARCHIVE_FATAL); } @@ -938,6 +990,10 @@ archive_read_format_rar_read_data(struct archive_read *a, const void **buff, struct rar *rar = (struct rar *)(a->format->data); int ret; + if (rar->has_encrypted_entries == ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW) { + rar->has_encrypted_entries = 0; + } + if (rar->bytes_unconsumed > 0) { /* Consume as much as the decompressor actually used. */ __archive_read_consume(a, rar->bytes_unconsumed); @@ -957,7 +1013,7 @@ archive_read_format_rar_read_data(struct archive_read *a, const void **buff, { case COMPRESS_METHOD_STORE: ret = read_data_stored(a, buff, size, offset); - break; + break; case COMPRESS_METHOD_FASTEST: case COMPRESS_METHOD_FAST: @@ -967,13 +1023,13 @@ archive_read_format_rar_read_data(struct archive_read *a, const void **buff, ret = read_data_compressed(a, buff, size, offset); if (ret != ARCHIVE_OK && ret != ARCHIVE_WARN) __archive_ppmd7_functions.Ppmd7_Free(&rar->ppmd7_context, &g_szalloc); - break; + break; default: archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, "Unsupported compression method for RAR file."); ret = ARCHIVE_FATAL; - break; + break; } return (ret); } @@ -1290,9 +1346,14 @@ read_header(struct archive_read *a, struct archive_entry *entry, if (rar->file_flags & FHD_PASSWORD) { + archive_entry_set_is_data_encrypted(entry, 1); + rar->has_encrypted_entries = 1; archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, "RAR encryption support unavailable."); - return (ARCHIVE_FATAL); + /* Since it is only the data part itself that is encrypted we can at least + extract information about the currently processed entry and don't need + to return ARCHIVE_FATAL here. */ + /*return (ARCHIVE_FATAL);*/ } if (rar->file_flags & FHD_LARGE) @@ -1377,7 +1438,7 @@ read_header(struct archive_read *a, struct archive_entry *entry, flagbyte = *(p + offset++); flagbits = 8; } - + flagbits -= 2; switch((flagbyte >> flagbits) & 3) { @@ -2611,7 +2672,7 @@ expand(struct archive_read *a, int64_t end) if ((symbol = read_next_symbol(a, &rar->maincode)) < 0) return (ARCHIVE_FATAL); rar->output_last_match = 0; - + if (symbol < 256) { lzss_emit_literal(rar, symbol); diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_format_raw.c b/Utilities/cmlibarchive/libarchive/archive_read_support_format_raw.c index 8434978..efa2c6a 100644 --- a/Utilities/cmlibarchive/libarchive/archive_read_support_format_raw.c +++ b/Utilities/cmlibarchive/libarchive/archive_read_support_format_raw.c @@ -78,7 +78,9 @@ archive_read_support_format_raw(struct archive *_a) archive_read_format_raw_read_data, archive_read_format_raw_read_data_skip, NULL, - archive_read_format_raw_cleanup); + archive_read_format_raw_cleanup, + NULL, + NULL); if (r != ARCHIVE_OK) free(info); return (r); diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_format_tar.c b/Utilities/cmlibarchive/libarchive/archive_read_support_format_tar.c index c7c808f..734424d 100644 --- a/Utilities/cmlibarchive/libarchive/archive_read_support_format_tar.c +++ b/Utilities/cmlibarchive/libarchive/archive_read_support_format_tar.c @@ -151,6 +151,8 @@ struct tar { struct archive_string_conv *sconv_default; int init_default_conversion; int compat_2x; + int process_mac_extensions; + int read_concatenated_archives; }; static int archive_block_is_null(const char *p); @@ -241,6 +243,10 @@ archive_read_support_format_tar(struct archive *_a) ARCHIVE_STATE_NEW, "archive_read_support_format_tar"); tar = (struct tar *)calloc(1, sizeof(*tar)); +#ifdef HAVE_COPYFILE_H + /* Set this by default on Mac OS. */ + tar->process_mac_extensions = 1; +#endif if (tar == NULL) { archive_set_error(&a->archive, ENOMEM, "Can't allocate tar data"); @@ -254,7 +260,9 @@ archive_read_support_format_tar(struct archive *_a) archive_read_format_tar_read_data, archive_read_format_tar_skip, NULL, - archive_read_format_tar_cleanup); + archive_read_format_tar_cleanup, + NULL, + NULL); if (r != ARCHIVE_OK) free(tar); @@ -368,7 +376,7 @@ archive_read_format_tar_options(struct archive_read *a, tar = (struct tar *)(a->format->data); if (strcmp(key, "compat-2x") == 0) { /* Handle UTF-8 filnames as libarchive 2.x */ - tar->compat_2x = (val != NULL)?1:0; + tar->compat_2x = (val != NULL && val[0] != 0); tar->init_default_conversion = tar->compat_2x; return (ARCHIVE_OK); } else if (strcmp(key, "hdrcharset") == 0) { @@ -385,6 +393,12 @@ archive_read_format_tar_options(struct archive_read *a, ret = ARCHIVE_FATAL; } return (ret); + } else if (strcmp(key, "mac-ext") == 0) { + tar->process_mac_extensions = (val != NULL && val[0] != 0); + return (ARCHIVE_OK); + } else if (strcmp(key, "read_concatenated_archives") == 0) { + tar->read_concatenated_archives = (val != NULL && val[0] != 0); + return (ARCHIVE_OK); } /* Note: The "warn" return is just to inform the options @@ -397,7 +411,7 @@ archive_read_format_tar_options(struct archive_read *a, * how much unconsumed data we have floating around, and to consume * anything outstanding since we're going to do read_aheads */ -static void +static void tar_flush_unconsumed(struct archive_read *a, size_t *unconsumed) { if (*unconsumed) { @@ -590,7 +604,7 @@ archive_read_format_tar_skip(struct archive_read *a) tar = (struct tar *)(a->format->data); bytes_skipped = __archive_read_consume(a, - tar->entry_bytes_remaining + tar->entry_padding + + tar->entry_bytes_remaining + tar->entry_padding + tar->entry_bytes_unconsumed); if (bytes_skipped < 0) return (ARCHIVE_FATAL); @@ -619,36 +633,50 @@ tar_read_header(struct archive_read *a, struct tar *tar, const struct archive_entry_header_ustar *header; const struct archive_entry_header_gnutar *gnuheader; - tar_flush_unconsumed(a, unconsumed); + /* Loop until we find a workable header record. */ + for (;;) { + tar_flush_unconsumed(a, unconsumed); - /* Read 512-byte header record */ - h = __archive_read_ahead(a, 512, &bytes); - if (bytes < 0) - return ((int)bytes); - if (bytes == 0) { /* EOF at a block boundary. */ - /* Some writers do omit the block of nulls. <sigh> */ - return (ARCHIVE_EOF); - } - if (bytes < 512) { /* Short block at EOF; this is bad. */ - archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, - "Truncated tar archive"); - return (ARCHIVE_FATAL); - } - *unconsumed = 512; + /* Read 512-byte header record */ + h = __archive_read_ahead(a, 512, &bytes); + if (bytes < 0) + return ((int)bytes); + if (bytes == 0) { /* EOF at a block boundary. */ + /* Some writers do omit the block of nulls. <sigh> */ + return (ARCHIVE_EOF); + } + if (bytes < 512) { /* Short block at EOF; this is bad. */ + archive_set_error(&a->archive, + ARCHIVE_ERRNO_FILE_FORMAT, + "Truncated tar archive"); + return (ARCHIVE_FATAL); + } + *unconsumed = 512; - /* Check for end-of-archive mark. */ - if (h[0] == 0 && archive_block_is_null(h)) { - /* Try to consume a second all-null record, as well. */ - tar_flush_unconsumed(a, unconsumed); - h = __archive_read_ahead(a, 512, NULL); - if (h != NULL) - __archive_read_consume(a, 512); - archive_clear_error(&a->archive); + /* Header is workable if it's not an end-of-archive mark. */ + if (h[0] != 0 || !archive_block_is_null(h)) + break; + + /* Ensure format is set for archives with only null blocks. */ if (a->archive.archive_format_name == NULL) { a->archive.archive_format = ARCHIVE_FORMAT_TAR; a->archive.archive_format_name = "tar"; } - return (ARCHIVE_EOF); + + if (!tar->read_concatenated_archives) { + /* Try to consume a second all-null record, as well. */ + tar_flush_unconsumed(a, unconsumed); + h = __archive_read_ahead(a, 512, NULL); + if (h != NULL && h[0] == 0 && archive_block_is_null(h)) + __archive_read_consume(a, 512); + archive_clear_error(&a->archive); + return (ARCHIVE_EOF); + } + + /* + * We're reading concatenated archives, ignore this block and + * loop to get the next. + */ } /* @@ -683,6 +711,8 @@ tar_read_header(struct archive_read *a, struct tar *tar, a->archive.archive_format = ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE; a->archive.archive_format_name = "POSIX pax interchange format"; err = header_pax_global(a, tar, entry, h, unconsumed); + if (err == ARCHIVE_EOF) + return (err); break; case 'K': /* Long link name (GNU tar, others) */ err = header_longlink(a, tar, entry, h, unconsumed); @@ -735,9 +765,9 @@ tar_read_header(struct archive_read *a, struct tar *tar, * extensions for both the AppleDouble extension entry and the * regular entry. */ - /* TODO: Should this be disabled on non-Mac platforms? */ if ((err == ARCHIVE_WARN || err == ARCHIVE_OK) && - tar->header_recursion_depth == 0) { + tar->header_recursion_depth == 0 && + tar->process_mac_extensions) { int err2 = read_mac_metadata_blob(a, tar, entry, h, unconsumed); if (err2 < err) err = err2; @@ -780,12 +810,20 @@ checksum(struct archive_read *a, const void *h) { const unsigned char *bytes; const struct archive_entry_header_ustar *header; - int check, i, sum; + int check, sum; + size_t i; (void)a; /* UNUSED */ bytes = (const unsigned char *)h; header = (const struct archive_entry_header_ustar *)h; + /* Checksum field must hold an octal number */ + for (i = 0; i < sizeof(header->checksum); ++i) { + char c = header->checksum[i]; + if (c != ' ' && c != '\0' && (c < '0' || c > '7')) + return 0; + } + /* * Test the checksum. Note that POSIX specifies _unsigned_ * bytes for this calculation. @@ -1277,7 +1315,7 @@ read_mac_metadata_blob(struct archive_read *a, struct tar *tar, if (wp[0] == '/' && wp[1] != L'\0') wname = wp + 1; } - /* + /* * If last path element starts with "._", then * this is a Mac extension. */ @@ -1292,7 +1330,7 @@ read_mac_metadata_blob(struct archive_read *a, struct tar *tar, if (p[0] == '/' && p[1] != '\0') name = p + 1; } - /* + /* * If last path element starts with "._", then * this is a Mac extension. */ diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_format_xar.c b/Utilities/cmlibarchive/libarchive/archive_read_support_format_xar.c index 2530e34..af89ded 100644 --- a/Utilities/cmlibarchive/libarchive/archive_read_support_format_xar.c +++ b/Utilities/cmlibarchive/libarchive/archive_read_support_format_xar.c @@ -468,7 +468,9 @@ archive_read_support_format_xar(struct archive *_a) xar_read_data, xar_read_data_skip, NULL, - xar_cleanup); + xar_cleanup, + NULL, + NULL); if (r != ARCHIVE_OK) free(xar); return (r); @@ -967,10 +969,14 @@ move_reading_point(struct archive_read *a, uint64_t offset) return ((int)step); xar->offset += step; } else { - archive_set_error(&(a->archive), - ARCHIVE_ERRNO_MISC, - "Cannot seek."); - return (ARCHIVE_FAILED); + int64_t pos = __archive_read_seek(a, offset, SEEK_SET); + if (pos == ARCHIVE_FAILED) { + archive_set_error(&(a->archive), + ARCHIVE_ERRNO_MISC, + "Cannot seek."); + return (ARCHIVE_FAILED); + } + xar->offset = pos; } } return (ARCHIVE_OK); diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_format_zip.c b/Utilities/cmlibarchive/libarchive/archive_read_support_format_zip.c index 2fdc08b..3f4014b 100644 --- a/Utilities/cmlibarchive/libarchive/archive_read_support_format_zip.c +++ b/Utilities/cmlibarchive/libarchive/archive_read_support_format_zip.c @@ -1,6 +1,7 @@ /*- - * Copyright (c) 2004 Tim Kientzle + * Copyright (c) 2004-2013 Tim Kientzle * Copyright (c) 2011-2012 Michihiro NAKAJIMA + * Copyright (c) 2013 Konrad Kleine * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -27,6 +28,20 @@ #include "archive_platform.h" __FBSDID("$FreeBSD: head/lib/libarchive/archive_read_support_format_zip.c 201102 2009-12-28 03:11:36Z kientzle $"); +/* + * The definitive documentation of the Zip file format is: + * http://www.pkware.com/documents/casestudies/APPNOTE.TXT + * + * The Info-Zip project has pioneered various extensions to better + * support Zip on Unix, including the 0x5455 "UT", 0x5855 "UX", 0x7855 + * "Ux", and 0x7875 "ux" extensions for time and ownership + * information. + * + * History of this code: The streaming Zip reader was first added to + * libarchive in January 2005. Support for seekable input sources was + * added in Nov 2011. + */ + #ifdef HAVE_ERRNO_H #include <errno.h> #endif @@ -51,42 +66,55 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_read_support_format_zip.c 201102 struct zip_entry { struct archive_rb_node node; + struct zip_entry *next; int64_t local_header_offset; int64_t compressed_size; int64_t uncompressed_size; int64_t gid; int64_t uid; - struct archive_entry *entry; struct archive_string rsrcname; time_t mtime; time_t atime; time_t ctime; uint32_t crc32; uint16_t mode; - uint16_t flags; - char compression; - char system; + uint16_t zip_flags; /* From GP Flags Field */ + unsigned char compression; + unsigned char system; /* From "version written by" */ + unsigned char flags; /* Our extra markers. */ }; +/* Bits used in zip_flags. */ +#define ZIP_ENCRYPTED (1 << 0) +#define ZIP_LENGTH_AT_END (1 << 3) +#define ZIP_STRONG_ENCRYPTED (1 << 6) +#define ZIP_UTF8_NAME (1 << 11) +/* See "7.2 Single Password Symmetric Encryption Method" + in http://www.pkware.com/documents/casestudies/APPNOTE.TXT */ +#define ZIP_CENTRAL_DIRECTORY_ENCRYPTED (1 << 13) + +/* Bits used in flags. */ +#define LA_USED_ZIP64 (1 << 0) +#define LA_FROM_CENTRAL_DIRECTORY (1 << 1) + struct zip { /* Structural information about the archive. */ - int64_t end_of_central_directory_offset; + char format_name[64]; int64_t central_directory_offset; - size_t central_directory_size; - size_t central_directory_entries; - char have_central_directory; - int64_t offset; + size_t central_directory_entries_total; + size_t central_directory_entries_on_this_disk; + int has_encrypted_entries; /* List of entries (seekable Zip only) */ - size_t entries_remaining; struct zip_entry *zip_entries; - struct zip_entry *entry; struct archive_rb_tree tree; struct archive_rb_tree tree_rsrc; + /* Bytes read but not yet consumed via __archive_read_consume() */ size_t unconsumed; - /* entry_bytes_remaining is the number of bytes we expect. */ + /* Information about entry we're currently reading. */ + struct zip_entry *entry; int64_t entry_bytes_remaining; /* These count the number of bytes actually read for the entry. */ @@ -95,852 +123,363 @@ struct zip { /* Running CRC32 of the decompressed data */ unsigned long entry_crc32; + unsigned long (*crc32func)(unsigned long, const void *, size_t); + char ignore_crc32; /* Flags to mark progress of decompression. */ char decompress_init; char end_of_entry; - ssize_t filename_length; - ssize_t extra_length; - +#ifdef HAVE_ZLIB_H unsigned char *uncompressed_buffer; size_t uncompressed_buffer_size; -#ifdef HAVE_ZLIB_H z_stream stream; char stream_valid; #endif - struct archive_string extra; struct archive_string_conv *sconv; struct archive_string_conv *sconv_default; struct archive_string_conv *sconv_utf8; int init_default_conversion; - char format_name[64]; + int process_mac_extensions; }; -#define ZIP_LENGTH_AT_END 8 -#define ZIP_ENCRYPTED (1<<0) -#define ZIP_STRONG_ENCRYPTED (1<<6) -#define ZIP_UTF8_NAME (1<<11) - -static int archive_read_format_zip_streamable_bid(struct archive_read *, - int); -static int archive_read_format_zip_seekable_bid(struct archive_read *, - int); -static int archive_read_format_zip_options(struct archive_read *, - const char *, const char *); -static int archive_read_format_zip_cleanup(struct archive_read *); -static int archive_read_format_zip_read_data(struct archive_read *, - const void **, size_t *, int64_t *); -static int archive_read_format_zip_read_data_skip(struct archive_read *a); -static int archive_read_format_zip_seekable_read_header( - struct archive_read *, struct archive_entry *); -static int archive_read_format_zip_streamable_read_header( - struct archive_read *, struct archive_entry *); -static ssize_t zip_get_local_file_header_size(struct archive_read *, size_t); -#ifdef HAVE_ZLIB_H -static int zip_deflate_init(struct archive_read *, struct zip *); -static int zip_read_data_deflate(struct archive_read *a, const void **buff, - size_t *size, int64_t *offset); -#endif -static int zip_read_data_none(struct archive_read *a, const void **buff, - size_t *size, int64_t *offset); -static int zip_read_local_file_header(struct archive_read *a, - struct archive_entry *entry, struct zip *); -static time_t zip_time(const char *); -static const char *compression_name(int compression); -static void process_extra(const char *, size_t, struct zip_entry *); - -int archive_read_support_format_zip_streamable(struct archive *); -int archive_read_support_format_zip_seekable(struct archive *); - -int -archive_read_support_format_zip_streamable(struct archive *_a) -{ - struct archive_read *a = (struct archive_read *)_a; - struct zip *zip; - int r; - - archive_check_magic(_a, ARCHIVE_READ_MAGIC, - ARCHIVE_STATE_NEW, "archive_read_support_format_zip"); - - zip = (struct zip *)malloc(sizeof(*zip)); - if (zip == NULL) { - archive_set_error(&a->archive, ENOMEM, - "Can't allocate zip data"); - return (ARCHIVE_FATAL); - } - memset(zip, 0, sizeof(*zip)); - - r = __archive_read_register_format(a, - zip, - "zip", - archive_read_format_zip_streamable_bid, - archive_read_format_zip_options, - archive_read_format_zip_streamable_read_header, - archive_read_format_zip_read_data, - archive_read_format_zip_read_data_skip, - NULL, - archive_read_format_zip_cleanup); +/* Many systems define min or MIN, but not all. */ +#define zipmin(a,b) ((a) < (b) ? (a) : (b)) - if (r != ARCHIVE_OK) - free(zip); - return (ARCHIVE_OK); -} - -int -archive_read_support_format_zip_seekable(struct archive *_a) -{ - struct archive_read *a = (struct archive_read *)_a; - struct zip *zip; - int r; - - archive_check_magic(_a, ARCHIVE_READ_MAGIC, - ARCHIVE_STATE_NEW, "archive_read_support_format_zip_seekable"); - - zip = (struct zip *)malloc(sizeof(*zip)); - if (zip == NULL) { - archive_set_error(&a->archive, ENOMEM, - "Can't allocate zip data"); - return (ARCHIVE_FATAL); - } - memset(zip, 0, sizeof(*zip)); - - r = __archive_read_register_format(a, - zip, - "zip", - archive_read_format_zip_seekable_bid, - archive_read_format_zip_options, - archive_read_format_zip_seekable_read_header, - archive_read_format_zip_read_data, - archive_read_format_zip_read_data_skip, - NULL, - archive_read_format_zip_cleanup); - - if (r != ARCHIVE_OK) - free(zip); - return (ARCHIVE_OK); -} - -int -archive_read_support_format_zip(struct archive *a) -{ - int r; - r = archive_read_support_format_zip_streamable(a); - if (r != ARCHIVE_OK) - return r; - return (archive_read_support_format_zip_seekable(a)); -} +/* ------------------------------------------------------------------------ */ /* - * TODO: This is a performance sink because it forces the read core to - * drop buffered data from the start of file, which will then have to - * be re-read again if this bidder loses. + * Common code for streaming or seeking modes. * - * We workaround this a little by passing in the best bid so far so - * that later bidders can do nothing if they know they'll never - * outbid. But we can certainly do better... + * Includes code to read local file headers, decompress data + * from entry bodies, and common API. */ -static int -archive_read_format_zip_seekable_bid(struct archive_read *a, int best_bid) -{ - struct zip *zip = (struct zip *)a->format->data; - int64_t filesize; - const char *p; - - /* If someone has already bid more than 32, then avoid - trashing the look-ahead buffers with a seek. */ - if (best_bid > 32) - return (-1); - - filesize = __archive_read_seek(a, -22, SEEK_END); - /* If we can't seek, then we can't bid. */ - if (filesize <= 0) - return 0; - - /* TODO: More robust search for end of central directory record. */ - if ((p = __archive_read_ahead(a, 22, NULL)) == NULL) - return 0; - /* First four bytes are signature for end of central directory - record. Four zero bytes ensure this isn't a multi-volume - Zip file (which we don't yet support). */ - if (memcmp(p, "PK\005\006\000\000\000\000", 8) != 0) { - int64_t i, tail; - int found; - - /* - * If there is a comment in end of central directory - * record, 22 bytes are too short. we have to read more - * to properly detect the record. Hopefully, a length - * of the comment is not longer than 16362 bytes(16K-22). - */ - if (filesize + 22 > 1024 * 16) { - tail = 1024 * 16; - filesize = __archive_read_seek(a, tail * -1, SEEK_END); - } else { - tail = filesize + 22; - filesize = __archive_read_seek(a, 0, SEEK_SET); - } - if (filesize < 0) - return 0; - if ((p = __archive_read_ahead(a, (size_t)tail, NULL)) == NULL) - return 0; - for (found = 0, i = 0;!found && i < tail - 22;) { - switch (p[i]) { - case 'P': - if (memcmp(p+i, - "PK\005\006\000\000\000\000", 8) == 0) { - p += i; - filesize += tail - - (22 + archive_le16dec(p+20)); - found = 1; - } else - i += 8; - break; - case 'K': i += 7; break; - case 005: i += 6; break; - case 006: i += 5; break; - default: i += 1; break; - } - } - if (!found) - return 0; - } - - /* Since we've already done the hard work of finding the - end of central directory record, let's save the important - information. */ - zip->central_directory_entries = archive_le16dec(p + 10); - zip->central_directory_size = archive_le32dec(p + 12); - zip->central_directory_offset = archive_le32dec(p + 16); - zip->end_of_central_directory_offset = filesize; - /* Just one volume, so central dir must all be on this volume. */ - if (zip->central_directory_entries != archive_le16dec(p + 8)) - return 0; - /* Central directory can't extend beyond end of this file. */ - if (zip->central_directory_offset + - (int64_t)zip->central_directory_size > filesize) - return 0; - - /* This is just a tiny bit higher than the maximum returned by - the streaming Zip bidder. This ensures that the more accurate - seeking Zip parser wins whenever seek is available. */ - return 32; -} - -static int -cmp_node(const struct archive_rb_node *n1, const struct archive_rb_node *n2) +static unsigned long +real_crc32(unsigned long crc, const void *buff, size_t len) { - const struct zip_entry *e1 = (const struct zip_entry *)n1; - const struct zip_entry *e2 = (const struct zip_entry *)n2; - - return ((int)(e2->local_header_offset - e1->local_header_offset)); -} - -static int -cmp_key(const struct archive_rb_node *n, const void *key) -{ - /* This function won't be called */ - (void)n; /* UNUSED */ - (void)key; /* UNUSED */ - return 1; + return crc32(crc, buff, len); } -static int -rsrc_cmp_node(const struct archive_rb_node *n1, - const struct archive_rb_node *n2) +static unsigned long +fake_crc32(unsigned long crc, const void *buff, size_t len) { - const struct zip_entry *e1 = (const struct zip_entry *)n1; - const struct zip_entry *e2 = (const struct zip_entry *)n2; - - return (strcmp(e2->rsrcname.s, e1->rsrcname.s)); + (void)crc; /* UNUSED */ + (void)buff; /* UNUSED */ + (void)len; /* UNUSED */ + return 0; } -static int -rsrc_cmp_key(const struct archive_rb_node *n, const void *key) -{ - const struct zip_entry *e = (const struct zip_entry *)n; - return (strcmp((const char *)key, e->rsrcname.s)); -} +static struct { + int id; + const char * name; +} compression_methods[] = { + {0, "uncompressed"}, /* The file is stored (no compression) */ + {1, "shrinking"}, /* The file is Shrunk */ + {2, "reduced-1"}, /* The file is Reduced with compression factor 1 */ + {3, "reduced-2"}, /* The file is Reduced with compression factor 2 */ + {4, "reduced-3"}, /* The file is Reduced with compression factor 3 */ + {5, "reduced-4"}, /* The file is Reduced with compression factor 4 */ + {6, "imploded"}, /* The file is Imploded */ + {7, "reserved"}, /* Reserved for Tokenizing compression algorithm */ + {8, "deflation"}, /* The file is Deflated */ + {9, "deflation-64-bit"}, /* Enhanced Deflating using Deflate64(tm) */ + {10, "ibm-terse"}, /* PKWARE Data Compression Library Imploding (old IBM TERSE) */ + {11, "reserved"}, /* Reserved by PKWARE */ + {12, "bzip"}, /* File is compressed using BZIP2 algorithm */ + {13, "reserved"}, /* Reserved by PKWARE */ + {14, "lzma"}, /* LZMA (EFS) */ + {15, "reserved"}, /* Reserved by PKWARE */ + {16, "reserved"}, /* Reserved by PKWARE */ + {17, "reserved"}, /* Reserved by PKWARE */ + {18, "ibm-terse-new"}, /* File is compressed using IBM TERSE (new) */ + {19, "ibm-lz777"}, /* IBM LZ77 z Architecture (PFS) */ + {97, "wav-pack"}, /* WavPack compressed data */ + {98, "ppmd-1"} /* PPMd version I, Rev 1 */ +}; static const char * -rsrc_basename(const char *name, size_t name_length) +compression_name(const int compression) { - const char *s, *r; - - r = s = name; - for (;;) { - s = memchr(s, '/', name_length - (s - name)); - if (s == NULL) - break; - r = ++s; - } - return (r); -} - -static void -expose_parent_dirs(struct zip *zip, const char *name, size_t name_length) -{ - struct archive_string str; - struct zip_entry *dir; - char *s; - - archive_string_init(&str); - archive_strncpy(&str, name, name_length); - for (;;) { - s = strrchr(str.s, '/'); - if (s == NULL) - break; - *s = '\0'; - /* Transfer the parent directory from zip->tree_rsrc RB - * tree to zip->tree RB tree to expose. */ - dir = (struct zip_entry *) - __archive_rb_tree_find_node(&zip->tree_rsrc, str.s); - if (dir == NULL) - break; - __archive_rb_tree_remove_node(&zip->tree_rsrc, &dir->node); - archive_string_free(&dir->rsrcname); - __archive_rb_tree_insert_node(&zip->tree, &dir->node); - } - archive_string_free(&str); -} - -static int -slurp_central_directory(struct archive_read *a, struct zip *zip) -{ - unsigned i; - int64_t correction; - static const struct archive_rb_tree_ops rb_ops = { - &cmp_node, &cmp_key - }; - static const struct archive_rb_tree_ops rb_rsrc_ops = { - &rsrc_cmp_node, &rsrc_cmp_key - }; - - /* - * Consider the archive file we are reading may be SFX. - * So we have to calculate a SFX header size to revise - * ZIP header offsets. - */ - correction = zip->end_of_central_directory_offset - - (zip->central_directory_offset + zip->central_directory_size); - /* The central directory offset is relative value, and so - * we revise this offset for SFX. */ - zip->central_directory_offset += correction; - - __archive_read_seek(a, zip->central_directory_offset, SEEK_SET); - zip->offset = zip->central_directory_offset; - __archive_rb_tree_init(&zip->tree, &rb_ops); - __archive_rb_tree_init(&zip->tree_rsrc, &rb_rsrc_ops); - - zip->zip_entries = calloc(zip->central_directory_entries, - sizeof(struct zip_entry)); - for (i = 0; i < zip->central_directory_entries; ++i) { - struct zip_entry *zip_entry = &zip->zip_entries[i]; - size_t filename_length, extra_length, comment_length; - uint32_t external_attributes; - const char *name, *p, *r; - - if ((p = __archive_read_ahead(a, 46, NULL)) == NULL) - return ARCHIVE_FATAL; - if (memcmp(p, "PK\001\002", 4) != 0) { - archive_set_error(&a->archive, - -1, "Invalid central directory signature"); - return ARCHIVE_FATAL; + static const int num_compression_methods = sizeof(compression_methods)/sizeof(compression_methods[0]); + int i=0; + while(compression >= 0 && i++ < num_compression_methods) { + if (compression_methods[i].id == compression) { + return compression_methods[i].name; } - zip->have_central_directory = 1; - /* version = p[4]; */ - zip_entry->system = p[5]; - /* version_required = archive_le16dec(p + 6); */ - zip_entry->flags = archive_le16dec(p + 8); - zip_entry->compression = (char)archive_le16dec(p + 10); - zip_entry->mtime = zip_time(p + 12); - zip_entry->crc32 = archive_le32dec(p + 16); - zip_entry->compressed_size = archive_le32dec(p + 20); - zip_entry->uncompressed_size = archive_le32dec(p + 24); - filename_length = archive_le16dec(p + 28); - extra_length = archive_le16dec(p + 30); - comment_length = archive_le16dec(p + 32); - /* disk_start = archive_le16dec(p + 34); */ /* Better be zero. */ - /* internal_attributes = archive_le16dec(p + 36); */ /* text bit */ - external_attributes = archive_le32dec(p + 38); - zip_entry->local_header_offset = - archive_le32dec(p + 42) + correction; - - /* If we can't guess the mode, leave it zero here; - when we read the local file header we might get - more information. */ - zip_entry->mode = 0; - if (zip_entry->system == 3) { - zip_entry->mode = external_attributes >> 16; - } - - /* - * Mac resource fork files are stored under the - * "__MACOSX/" directory, so we should check if - * it is. - */ - /* Make sure we have the file name. */ - if ((p = __archive_read_ahead(a, 46 + filename_length, NULL)) - == NULL) - return ARCHIVE_FATAL; - name = p + 46; - r = rsrc_basename(name, filename_length); - if (filename_length >= 9 && - strncmp("__MACOSX/", name, 9) == 0) { - /* If this file is not a resource fork nor - * a directory. We should treat it as a non - * resource fork file to expose it. */ - if (name[filename_length-1] != '/' && - (r - name < 3 || r[0] != '.' || r[1] != '_')) { - __archive_rb_tree_insert_node(&zip->tree, - &zip_entry->node); - /* Expose its parent directories. */ - expose_parent_dirs(zip, name, filename_length); - } else { - /* This file is a resource fork file or - * a directory. */ - archive_strncpy(&(zip_entry->rsrcname), name, - filename_length); - __archive_rb_tree_insert_node(&zip->tree_rsrc, - &zip_entry->node); - } - } else { - /* Generate resource fork name to find its resource - * file at zip->tree_rsrc. */ - archive_strcpy(&(zip_entry->rsrcname), "__MACOSX/"); - archive_strncat(&(zip_entry->rsrcname), name, r - name); - archive_strcat(&(zip_entry->rsrcname), "._"); - archive_strncat(&(zip_entry->rsrcname), - name + (r - name), filename_length - (r - name)); - /* Register an entry to RB tree to sort it by - * file offset. */ - __archive_rb_tree_insert_node(&zip->tree, - &zip_entry->node); - } - - /* We don't read the filename until we get to the - local file header. Reading it here would speed up - table-of-contents operations (removing the need to - find and read local file header to get the - filename) at the cost of requiring a lot of extra - space. */ - /* We don't read the extra block here. We assume it - will be duplicated at the local file header. */ - __archive_read_consume(a, - 46 + filename_length + extra_length + comment_length); } - - return ARCHIVE_OK; + return "??"; } -static int64_t -zip_read_consume(struct archive_read *a, int64_t bytes) +/* Convert an MSDOS-style date/time into Unix-style time. */ +static time_t +zip_time(const char *p) { - struct zip *zip = (struct zip *)a->format->data; - int64_t skip; + int msTime, msDate; + struct tm ts; + + msTime = (0xff & (unsigned)p[0]) + 256 * (0xff & (unsigned)p[1]); + msDate = (0xff & (unsigned)p[2]) + 256 * (0xff & (unsigned)p[3]); - skip = __archive_read_consume(a, bytes); - if (skip > 0) - zip->offset += skip; - return (skip); + memset(&ts, 0, sizeof(ts)); + ts.tm_year = ((msDate >> 9) & 0x7f) + 80; /* Years since 1900. */ + ts.tm_mon = ((msDate >> 5) & 0x0f) - 1; /* Month number. */ + ts.tm_mday = msDate & 0x1f; /* Day of month. */ + ts.tm_hour = (msTime >> 11) & 0x1f; + ts.tm_min = (msTime >> 5) & 0x3f; + ts.tm_sec = (msTime << 1) & 0x3e; + ts.tm_isdst = -1; + return mktime(&ts); } -static int -zip_read_mac_metadata(struct archive_read *a, struct archive_entry *entry, - struct zip_entry *rsrc) +/* + * The extra data is stored as a list of + * id1+size1+data1 + id2+size2+data2 ... + * triplets. id and size are 2 bytes each. + */ +static void +process_extra(const char *p, size_t extra_length, struct zip_entry* zip_entry) { - struct zip *zip = (struct zip *)a->format->data; - unsigned char *metadata, *mp; - int64_t offset = zip->offset; - size_t remaining_bytes, metadata_bytes; - ssize_t hsize; - int ret = ARCHIVE_OK, eof; + unsigned offset = 0; - switch(rsrc->compression) { - case 0: /* No compression. */ -#ifdef HAVE_ZLIB_H - case 8: /* Deflate compression. */ + while (offset < extra_length - 4) + { + unsigned short headerid = archive_le16dec(p + offset); + unsigned short datasize = archive_le16dec(p + offset + 2); + offset += 4; + if (offset + datasize > extra_length) + break; +#ifdef DEBUG + fprintf(stderr, "Header id 0x%x, length %d\n", + headerid, datasize); #endif - break; - default: /* Unsupported compression. */ - /* Return a warning. */ - archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, - "Unsupported ZIP compression method (%s)", - compression_name(rsrc->compression)); - /* We can't decompress this entry, but we will - * be able to skip() it and try the next entry. */ - return (ARCHIVE_WARN); - } - - if (rsrc->uncompressed_size > (128 * 1024)) { - archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, - "Mac metadata is too large: %jd > 128K bytes", - (intmax_t)rsrc->uncompressed_size); - return (ARCHIVE_WARN); - } - - metadata = malloc((size_t)rsrc->uncompressed_size); - if (metadata == NULL) { - archive_set_error(&a->archive, ENOMEM, - "Can't allocate memory for Mac metadata"); - return (ARCHIVE_FATAL); - } - - if (zip->offset < rsrc->local_header_offset) - zip_read_consume(a, rsrc->local_header_offset - zip->offset); - else if (zip->offset != rsrc->local_header_offset) { - __archive_read_seek(a, rsrc->local_header_offset, SEEK_SET); - zip->offset = zip->entry->local_header_offset; - } - - hsize = zip_get_local_file_header_size(a, 0); - zip_read_consume(a, hsize); - - remaining_bytes = (size_t)rsrc->compressed_size; - metadata_bytes = (size_t)rsrc->uncompressed_size; - mp = metadata; - eof = 0; - while (!eof && remaining_bytes) { - const unsigned char *p; - ssize_t bytes_avail; - size_t bytes_used; - - p = __archive_read_ahead(a, 1, &bytes_avail); - if (p == NULL) { - archive_set_error(&a->archive, - ARCHIVE_ERRNO_FILE_FORMAT, - "Truncated ZIP file header"); - ret = ARCHIVE_WARN; - goto exit_mac_metadata; - } - if ((size_t)bytes_avail > remaining_bytes) - bytes_avail = remaining_bytes; - switch(rsrc->compression) { - case 0: /* No compression. */ - memcpy(mp, p, bytes_avail); - bytes_used = (size_t)bytes_avail; - metadata_bytes -= bytes_used; - mp += bytes_used; - if (metadata_bytes == 0) - eof = 1; + switch (headerid) { + case 0x0001: + /* Zip64 extended information extra field. */ + zip_entry->flags |= LA_USED_ZIP64; + if (zip_entry->uncompressed_size == 0xffffffff) { + if (datasize < 8) + break; + zip_entry->uncompressed_size = + archive_le64dec(p + offset); + offset += 8; + datasize -= 8; + } + if (zip_entry->compressed_size == 0xffffffff) { + if (datasize < 8) + break; + zip_entry->compressed_size = + archive_le64dec(p + offset); + offset += 8; + datasize -= 8; + } + if (zip_entry->local_header_offset == 0xffffffff) { + if (datasize < 8) + break; + zip_entry->local_header_offset = + archive_le64dec(p + offset); + offset += 8; + datasize -= 8; + } + /* archive_le32dec(p + offset) gives disk + * on which file starts, but we don't handle + * multi-volume Zip files. */ break; -#ifdef HAVE_ZLIB_H - case 8: /* Deflate compression. */ + case 0x5455: { - int r; - - ret = zip_deflate_init(a, zip); - if (ret != ARCHIVE_OK) - goto exit_mac_metadata; - zip->stream.next_in = - (Bytef *)(uintptr_t)(const void *)p; - zip->stream.avail_in = (uInt)bytes_avail; - zip->stream.total_in = 0; - zip->stream.next_out = mp; - zip->stream.avail_out = (uInt)metadata_bytes; - zip->stream.total_out = 0; - - r = inflate(&zip->stream, 0); - switch (r) { - case Z_OK: - break; - case Z_STREAM_END: - eof = 1; - break; - case Z_MEM_ERROR: - archive_set_error(&a->archive, ENOMEM, - "Out of memory for ZIP decompression"); - ret = ARCHIVE_FATAL; - goto exit_mac_metadata; - default: - archive_set_error(&a->archive, - ARCHIVE_ERRNO_MISC, - "ZIP decompression failed (%d)", r); - ret = ARCHIVE_FATAL; - goto exit_mac_metadata; + /* Extended time field "UT". */ + int flags = p[offset]; + offset++; + datasize--; + /* Flag bits indicate which dates are present. */ + if (flags & 0x01) + { +#ifdef DEBUG + fprintf(stderr, "mtime: %lld -> %d\n", + (long long)zip_entry->mtime, + archive_le32dec(p + offset)); +#endif + if (datasize < 4) + break; + zip_entry->mtime = archive_le32dec(p + offset); + offset += 4; + datasize -= 4; + } + if (flags & 0x02) + { + if (datasize < 4) + break; + zip_entry->atime = archive_le32dec(p + offset); + offset += 4; + datasize -= 4; + } + if (flags & 0x04) + { + if (datasize < 4) + break; + zip_entry->ctime = archive_le32dec(p + offset); + offset += 4; + datasize -= 4; } - bytes_used = zip->stream.total_in; - metadata_bytes -= zip->stream.total_out; - mp += zip->stream.total_out; break; } -#endif - default: - bytes_used = 0; + case 0x5855: + { + /* Info-ZIP Unix Extra Field (old version) "UX". */ + if (datasize >= 8) { + zip_entry->atime = archive_le32dec(p + offset); + zip_entry->mtime = + archive_le32dec(p + offset + 4); + } + if (datasize >= 12) { + zip_entry->uid = + archive_le16dec(p + offset + 8); + zip_entry->gid = + archive_le16dec(p + offset + 10); + } break; } - zip_read_consume(a, bytes_used); - remaining_bytes -= bytes_used; - } - archive_entry_copy_mac_metadata(entry, metadata, - (size_t)rsrc->uncompressed_size - metadata_bytes); - - __archive_read_seek(a, offset, SEEK_SET); - zip->offset = offset; -exit_mac_metadata: - zip->decompress_init = 0; - free(metadata); - return (ret); -} - -static int -archive_read_format_zip_seekable_read_header(struct archive_read *a, - struct archive_entry *entry) -{ - struct zip *zip = (struct zip *)a->format->data; - struct zip_entry *rsrc; - int r, ret = ARCHIVE_OK; - - a->archive.archive_format = ARCHIVE_FORMAT_ZIP; - if (a->archive.archive_format_name == NULL) - a->archive.archive_format_name = "ZIP"; - - if (zip->zip_entries == NULL) { - r = slurp_central_directory(a, zip); - zip->entries_remaining = zip->central_directory_entries; - if (r != ARCHIVE_OK) - return r; - /* Get first entry whose local header offset is lower than - * other entries in the archive file. */ - zip->entry = - (struct zip_entry *)ARCHIVE_RB_TREE_MIN(&zip->tree); - } else if (zip->entry != NULL) { - /* Get next entry in local header offset order. */ - zip->entry = (struct zip_entry *)__archive_rb_tree_iterate( - &zip->tree, &zip->entry->node, ARCHIVE_RB_DIR_RIGHT); - } - - if (zip->entries_remaining <= 0 || zip->entry == NULL) - return ARCHIVE_EOF; - --zip->entries_remaining; - - if (zip->entry->rsrcname.s) - rsrc = (struct zip_entry *)__archive_rb_tree_find_node( - &zip->tree_rsrc, zip->entry->rsrcname.s); - else - rsrc = NULL; - - /* File entries are sorted by the header offset, we should mostly - * use zip_read_consume to advance a read point to avoid redundant - * data reading. */ - if (zip->offset < zip->entry->local_header_offset) - zip_read_consume(a, - zip->entry->local_header_offset - zip->offset); - else if (zip->offset != zip->entry->local_header_offset) { - __archive_read_seek(a, zip->entry->local_header_offset, - SEEK_SET); - zip->offset = zip->entry->local_header_offset; - } - zip->unconsumed = 0; - r = zip_read_local_file_header(a, entry, zip); - if (r != ARCHIVE_OK) - return r; - if ((zip->entry->mode & AE_IFMT) == AE_IFLNK) { - const void *p; - struct archive_string_conv *sconv; - size_t linkname_length = (size_t)archive_entry_size(entry); - - archive_entry_set_size(entry, 0); - p = __archive_read_ahead(a, linkname_length, NULL); - if (p == NULL) { - archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "Truncated Zip file"); - return ARCHIVE_FATAL; - } - - sconv = zip->sconv; - if (sconv == NULL && (zip->entry->flags & ZIP_UTF8_NAME)) - sconv = zip->sconv_utf8; - if (sconv == NULL) - sconv = zip->sconv_default; - if (archive_entry_copy_symlink_l(entry, p, linkname_length, - sconv) != 0) { - if (errno != ENOMEM && sconv == zip->sconv_utf8 && - (zip->entry->flags & ZIP_UTF8_NAME)) - archive_entry_copy_symlink_l(entry, p, - linkname_length, NULL); - if (errno == ENOMEM) { - archive_set_error(&a->archive, ENOMEM, - "Can't allocate memory for Symlink"); - return (ARCHIVE_FATAL); - } + case 0x6c65: + { + /* Experimental 'el' field */ /* - * Since there is no character-set regulation for - * symlink name, do not report the conversion error - * in an automatic conversion. + * Introduced Dec 2013 to provide a way to + * include external file attributes in local file + * header. This provides file type and permission + * information necessary to support full streaming + * extraction. Currently being discussed with + * other Zip developers... subject to change. */ - if (sconv != zip->sconv_utf8 || - (zip->entry->flags & ZIP_UTF8_NAME) == 0) { - archive_set_error(&a->archive, - ARCHIVE_ERRNO_FILE_FORMAT, - "Symlink cannot be converted " - "from %s to current locale.", - archive_string_conversion_charset_name( - sconv)); - ret = ARCHIVE_WARN; - } - } - } - if (rsrc) { - int ret2 = zip_read_mac_metadata(a, entry, rsrc); - if (ret2 < ret) - ret = ret2; - } - return (ret); -} - -static int -archive_read_format_zip_streamable_bid(struct archive_read *a, int best_bid) -{ - const char *p; - - (void)best_bid; /* UNUSED */ - - if ((p = __archive_read_ahead(a, 4, NULL)) == NULL) - return (-1); - - /* - * Bid of 30 here is: 16 bits for "PK", - * next 16-bit field has four options (-2 bits). - * 16 + 16-2 = 30. - */ - if (p[0] == 'P' && p[1] == 'K') { - if ((p[2] == '\001' && p[3] == '\002') - || (p[2] == '\003' && p[3] == '\004') - || (p[2] == '\005' && p[3] == '\006') - || (p[2] == '\007' && p[3] == '\010') - || (p[2] == '0' && p[3] == '0')) - return (30); - } - - /* TODO: It's worth looking ahead a little bit for a valid - * PK signature. In particular, that would make it possible - * to read some UUEncoded SFX files or SFX files coming from - * a network socket. */ - - return (0); -} - -static int -archive_read_format_zip_options(struct archive_read *a, - const char *key, const char *val) -{ - struct zip *zip; - int ret = ARCHIVE_FAILED; - - zip = (struct zip *)(a->format->data); - if (strcmp(key, "compat-2x") == 0) { - /* Handle filnames as libarchive 2.x */ - zip->init_default_conversion = (val != NULL) ? 1 : 0; - return (ARCHIVE_OK); - } else if (strcmp(key, "hdrcharset") == 0) { - if (val == NULL || val[0] == 0) - archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "zip: hdrcharset option needs a character-set name" - ); - else { - zip->sconv = archive_string_conversion_from_charset( - &a->archive, val, 0); - if (zip->sconv != NULL) { - if (strcmp(val, "UTF-8") == 0) - zip->sconv_utf8 = zip->sconv; - ret = ARCHIVE_OK; - } else - ret = ARCHIVE_FATAL; - } - return (ret); - } + int bitmap, bitmap_last; - /* Note: The "warn" return is just to inform the options - * supervisor that we didn't handle it. It will generate - * a suitable error if no one used this option. */ - return (ARCHIVE_WARN); -} - -static int -archive_read_format_zip_streamable_read_header(struct archive_read *a, - struct archive_entry *entry) -{ - struct zip *zip; - - a->archive.archive_format = ARCHIVE_FORMAT_ZIP; - if (a->archive.archive_format_name == NULL) - a->archive.archive_format_name = "ZIP"; + if (datasize < 1) + break; + bitmap_last = bitmap = 0xff & p[offset]; + offset += 1; + datasize -= 1; + + /* We only support first 7 bits of bitmap; skip rest. */ + while ((bitmap_last & 0x80) != 0 + && datasize >= 1) { + bitmap_last = p[offset]; + offset += 1; + datasize -= 1; + } - zip = (struct zip *)(a->format->data); + if (bitmap & 1) { + // 2 byte "version made by" + if (datasize < 2) + break; + zip_entry->system + = archive_le16dec(p + offset) >> 8; + offset += 2; + datasize -= 2; + } + if (bitmap & 2) { + // 2 byte "internal file attributes" + uint32_t internal_attributes; + if (datasize < 2) + break; + internal_attributes + = archive_le16dec(p + offset); + // Not used by libarchive at present. + (void)internal_attributes; /* UNUSED */ + offset += 2; + datasize -= 2; + } + if (bitmap & 4) { + // 4 byte "external file attributes" + uint32_t external_attributes; + if (datasize < 4) + break; + external_attributes + = archive_le32dec(p + offset); + if (zip_entry->system == 3) { + zip_entry->mode + = external_attributes >> 16; + } + offset += 4; + datasize -= 4; + } + if (bitmap & 8) { + // 2 byte comment length + comment + uint32_t comment_length; + if (datasize < 2) + break; + comment_length + = archive_le16dec(p + offset); + offset += 2; + datasize -= 2; - /* Make sure we have a zip_entry structure to use. */ - if (zip->zip_entries == NULL) { - zip->zip_entries = malloc(sizeof(struct zip_entry)); - if (zip->zip_entries == NULL) { - archive_set_error(&a->archive, ENOMEM, - "Out of memory"); - return ARCHIVE_FATAL; + if (datasize < comment_length) + break; + // Comment is not supported by libarchive + offset += comment_length; + datasize -= comment_length; + } + break; } - } - zip->entry = zip->zip_entries; - memset(zip->entry, 0, sizeof(struct zip_entry)); - - /* Search ahead for the next local file header. */ - zip_read_consume(a, zip->unconsumed); - zip->unconsumed = 0; - for (;;) { - int64_t skipped = 0; - const char *p, *end; - ssize_t bytes; - - p = __archive_read_ahead(a, 4, &bytes); - if (p == NULL) - return (ARCHIVE_FATAL); - end = p + bytes; - - while (p + 4 <= end) { - if (p[0] == 'P' && p[1] == 'K') { - if (p[2] == '\001' && p[3] == '\002') - /* Beginning of central directory. */ - return (ARCHIVE_EOF); + case 0x7855: + /* Info-ZIP Unix Extra Field (type 2) "Ux". */ +#ifdef DEBUG + fprintf(stderr, "uid %d gid %d\n", + archive_le16dec(p + offset), + archive_le16dec(p + offset + 2)); +#endif + if (datasize >= 2) + zip_entry->uid = archive_le16dec(p + offset); + if (datasize >= 4) + zip_entry->gid = + archive_le16dec(p + offset + 2); + break; + case 0x7875: + { + /* Info-Zip Unix Extra Field (type 3) "ux". */ + int uidsize = 0, gidsize = 0; - if (p[2] == '\003' && p[3] == '\004') { - /* Regular file entry. */ - zip_read_consume(a, skipped); - return zip_read_local_file_header(a, - entry, zip); + /* TODO: support arbitrary uidsize/gidsize. */ + if (datasize >= 1 && p[offset] == 1) {/* version=1 */ + if (datasize >= 4) { + /* get a uid size. */ + uidsize = p[offset+1]; + if (uidsize == 2) + zip_entry->uid = + archive_le16dec( + p + offset + 2); + else if (uidsize == 4 && datasize >= 6) + zip_entry->uid = + archive_le32dec( + p + offset + 2); + } + if (datasize >= (2 + uidsize + 3)) { + /* get a gid size. */ + gidsize = p[offset+2+uidsize]; + if (gidsize == 2) + zip_entry->gid = + archive_le16dec( + p+offset+2+uidsize+1); + else if (gidsize == 4 && + datasize >= (2 + uidsize + 5)) + zip_entry->gid = + archive_le32dec( + p+offset+2+uidsize+1); } - - if (p[2] == '\005' && p[3] == '\006') - /* End of central directory. */ - return (ARCHIVE_EOF); } - ++p; - ++skipped; + break; } - zip_read_consume(a, skipped); - } -} - -static ssize_t -zip_get_local_file_header_size(struct archive_read *a, size_t extra) -{ - const char *p; - ssize_t filename_length, extra_length; - - if ((p = __archive_read_ahead(a, extra + 30, NULL)) == NULL) { - archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, - "Truncated ZIP file header"); - return (ARCHIVE_WARN); + default: + break; + } + offset += datasize; } - p += extra; - - if (memcmp(p, "PK\003\004", 4) != 0) { - archive_set_error(&a->archive, -1, "Damaged Zip archive"); - return ARCHIVE_WARN; +#ifdef DEBUG + if (offset != extra_length) + { + fprintf(stderr, + "Extra data field contents do not match reported size!\n"); } - filename_length = archive_le16dec(p + 26); - extra_length = archive_le16dec(p + 28); - - return (30 + filename_length + extra_length); +#endif } /* @@ -957,16 +496,18 @@ zip_read_local_file_header(struct archive_read *a, struct archive_entry *entry, size_t len, filename_length, extra_length; struct archive_string_conv *sconv; struct zip_entry *zip_entry = zip->entry; - uint32_t local_crc32; - int64_t compressed_size, uncompressed_size; + struct zip_entry zip_entry_central_dir; int ret = ARCHIVE_OK; char version; + /* Save a copy of the original for consistency checks. */ + zip_entry_central_dir = *zip_entry; + zip->decompress_init = 0; zip->end_of_entry = 0; zip->entry_uncompressed_bytes_read = 0; zip->entry_compressed_bytes_read = 0; - zip->entry_crc32 = crc32(0, NULL, 0); + zip->entry_crc32 = zip->crc32func(0, NULL, 0); /* Setup default conversion. */ if (zip->sconv == NULL && !zip->init_default_conversion) { @@ -987,52 +528,26 @@ zip_read_local_file_header(struct archive_read *a, struct archive_entry *entry, } version = p[4]; zip_entry->system = p[5]; - zip_entry->flags = archive_le16dec(p + 6); + zip_entry->zip_flags = archive_le16dec(p + 6); + if (zip_entry->zip_flags & (ZIP_ENCRYPTED | ZIP_STRONG_ENCRYPTED)) { + zip->has_encrypted_entries = 1; + archive_entry_set_is_data_encrypted(entry, 1); + if (zip_entry->zip_flags & ZIP_CENTRAL_DIRECTORY_ENCRYPTED && + zip_entry->zip_flags & ZIP_ENCRYPTED && + zip_entry->zip_flags & ZIP_STRONG_ENCRYPTED) { + archive_entry_set_is_metadata_encrypted(entry, 1); + return ARCHIVE_FATAL; + } + } zip_entry->compression = (char)archive_le16dec(p + 8); zip_entry->mtime = zip_time(p + 10); - local_crc32 = archive_le32dec(p + 14); - compressed_size = archive_le32dec(p + 18); - uncompressed_size = archive_le32dec(p + 22); + zip_entry->crc32 = archive_le32dec(p + 14); + zip_entry->compressed_size = archive_le32dec(p + 18); + zip_entry->uncompressed_size = archive_le32dec(p + 22); filename_length = archive_le16dec(p + 26); extra_length = archive_le16dec(p + 28); - zip_read_consume(a, 30); - - if (zip->have_central_directory) { - /* If we read the central dir entry, we must have size - * information as well, so ignore the length-at-end flag. */ - zip_entry->flags &= ~ZIP_LENGTH_AT_END; - /* If we have values from both the local file header - and the central directory, warn about mismatches - which might indicate a damaged file. But some - writers always put zero in the local header; don't - bother warning about that. */ - if (local_crc32 != 0 && local_crc32 != zip_entry->crc32) { - archive_set_error(&a->archive, - ARCHIVE_ERRNO_FILE_FORMAT, - "Inconsistent CRC32 values"); - ret = ARCHIVE_WARN; - } - if (compressed_size != 0 - && compressed_size != zip_entry->compressed_size) { - archive_set_error(&a->archive, - ARCHIVE_ERRNO_FILE_FORMAT, - "Inconsistent compressed size"); - ret = ARCHIVE_WARN; - } - if (uncompressed_size != 0 - && uncompressed_size != zip_entry->uncompressed_size) { - archive_set_error(&a->archive, - ARCHIVE_ERRNO_FILE_FORMAT, - "Inconsistent uncompressed size"); - ret = ARCHIVE_WARN; - } - } else { - /* If we don't have the CD info, use whatever we do have. */ - zip_entry->crc32 = local_crc32; - zip_entry->compressed_size = compressed_size; - zip_entry->uncompressed_size = uncompressed_size; - } + __archive_read_consume(a, 30); /* Read the filename. */ if ((h = __archive_read_ahead(a, filename_length, NULL)) == NULL) { @@ -1040,7 +555,7 @@ zip_read_local_file_header(struct archive_read *a, struct archive_entry *entry, "Truncated ZIP file header"); return (ARCHIVE_FATAL); } - if (zip_entry->flags & ZIP_UTF8_NAME) { + if (zip_entry->zip_flags & ZIP_UTF8_NAME) { /* The filename is stored to be UTF-8. */ if (zip->sconv_utf8 == NULL) { zip->sconv_utf8 = @@ -1069,26 +584,38 @@ zip_read_local_file_header(struct archive_read *a, struct archive_entry *entry, archive_string_conversion_charset_name(sconv)); ret = ARCHIVE_WARN; } - zip_read_consume(a, filename_length); + __archive_read_consume(a, filename_length); - if (zip_entry->mode == 0) { + /* Work around a bug in Info-Zip: When reading from a pipe, it + * stats the pipe instead of synthesizing a file entry. */ + if ((zip_entry->mode & AE_IFMT) == AE_IFIFO) { + zip_entry->mode &= ~ AE_IFMT; + zip_entry->mode |= AE_IFREG; + } + + if ((zip_entry->mode & AE_IFMT) == 0) { /* Especially in streaming mode, we can end up - here without having seen any mode information. + here without having seen proper mode information. Guess from the filename. */ wp = archive_entry_pathname_w(entry); if (wp != NULL) { len = wcslen(wp); if (len > 0 && wp[len - 1] == L'/') - zip_entry->mode = AE_IFDIR | 0777; + zip_entry->mode |= AE_IFDIR; else - zip_entry->mode = AE_IFREG | 0666; + zip_entry->mode |= AE_IFREG; } else { cp = archive_entry_pathname(entry); len = (cp != NULL)?strlen(cp):0; if (len > 0 && cp[len - 1] == '/') - zip_entry->mode = AE_IFDIR | 0777; + zip_entry->mode |= AE_IFDIR; else - zip_entry->mode = AE_IFREG | 0666; + zip_entry->mode |= AE_IFREG; + } + if (zip_entry->mode == AE_IFDIR) { + zip_entry->mode |= 0775; + } else if (zip_entry->mode == AE_IFREG) { + zip_entry->mode |= 0664; } } @@ -1098,8 +625,53 @@ zip_read_local_file_header(struct archive_read *a, struct archive_entry *entry, "Truncated ZIP file header"); return (ARCHIVE_FATAL); } + process_extra(h, extra_length, zip_entry); - zip_read_consume(a, extra_length); + __archive_read_consume(a, extra_length); + + if (zip_entry->flags & LA_FROM_CENTRAL_DIRECTORY) { + /* If this came from the central dir, it's size info + * is definitive, so ignore the length-at-end flag. */ + zip_entry->zip_flags &= ~ZIP_LENGTH_AT_END; + /* If local header is missing a value, use the one from + the central directory. If both have it, warn about + mismatches. */ + if (zip_entry->crc32 == 0) { + zip_entry->crc32 = zip_entry_central_dir.crc32; + } else if (!zip->ignore_crc32 + && zip_entry->crc32 != zip_entry_central_dir.crc32) { + archive_set_error(&a->archive, + ARCHIVE_ERRNO_FILE_FORMAT, + "Inconsistent CRC32 values"); + ret = ARCHIVE_WARN; + } + if (zip_entry->compressed_size == 0) { + zip_entry->compressed_size + = zip_entry_central_dir.compressed_size; + } else if (zip_entry->compressed_size + != zip_entry_central_dir.compressed_size) { + archive_set_error(&a->archive, + ARCHIVE_ERRNO_FILE_FORMAT, + "Inconsistent compressed size: " + "%jd in central directory, %jd in local header", + (intmax_t)zip_entry_central_dir.compressed_size, + (intmax_t)zip_entry->compressed_size); + ret = ARCHIVE_WARN; + } + if (zip_entry->uncompressed_size == 0) { + zip_entry->uncompressed_size + = zip_entry_central_dir.uncompressed_size; + } else if (zip_entry->uncompressed_size + != zip_entry_central_dir.uncompressed_size) { + archive_set_error(&a->archive, + ARCHIVE_ERRNO_FILE_FORMAT, + "Inconsistent uncompressed size: " + "%jd in central directory, %jd in local header", + (intmax_t)zip_entry_central_dir.uncompressed_size, + (intmax_t)zip_entry->uncompressed_size); + ret = ARCHIVE_WARN; + } + } /* Populate some additional entry fields: */ archive_entry_set_mode(entry, zip_entry->mode); @@ -1108,14 +680,65 @@ zip_read_local_file_header(struct archive_read *a, struct archive_entry *entry, archive_entry_set_mtime(entry, zip_entry->mtime, 0); archive_entry_set_ctime(entry, zip_entry->ctime, 0); archive_entry_set_atime(entry, zip_entry->atime, 0); - /* Set the size only if it's meaningful. */ - if (0 == (zip_entry->flags & ZIP_LENGTH_AT_END)) - archive_entry_set_size(entry, zip_entry->uncompressed_size); + if ((zip->entry->mode & AE_IFMT) == AE_IFLNK) { + size_t linkname_length = 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; + } + if (__archive_read_consume(a, linkname_length) < 0) { + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "Read error skipping symlink target name"); + return ARCHIVE_FATAL; + } + + sconv = zip->sconv; + if (sconv == NULL && (zip->entry->zip_flags & ZIP_UTF8_NAME)) + sconv = zip->sconv_utf8; + if (sconv == NULL) + sconv = zip->sconv_default; + if (archive_entry_copy_symlink_l(entry, p, linkname_length, + sconv) != 0) { + if (errno != ENOMEM && sconv == zip->sconv_utf8 && + (zip->entry->zip_flags & ZIP_UTF8_NAME)) + archive_entry_copy_symlink_l(entry, p, + linkname_length, NULL); + if (errno == ENOMEM) { + archive_set_error(&a->archive, ENOMEM, + "Can't allocate memory for Symlink"); + return (ARCHIVE_FATAL); + } + /* + * Since there is no character-set regulation for + * symlink name, do not report the conversion error + * in an automatic conversion. + */ + if (sconv != zip->sconv_utf8 || + (zip->entry->zip_flags & ZIP_UTF8_NAME) == 0) { + archive_set_error(&a->archive, + ARCHIVE_ERRNO_FILE_FORMAT, + "Symlink cannot be converted " + "from %s to current locale.", + archive_string_conversion_charset_name( + sconv)); + ret = ARCHIVE_WARN; + } + } + zip_entry->uncompressed_size = zip_entry->compressed_size = 0; + } else if (0 == (zip_entry->zip_flags & ZIP_LENGTH_AT_END) + || zip_entry->uncompressed_size > 0) { + /* Set the size only if it's meaningful. */ + archive_entry_set_size(entry, zip_entry->uncompressed_size); + } zip->entry_bytes_remaining = zip_entry->compressed_size; /* If there's no body, force read_data() to return EOF immediately. */ - if (0 == (zip_entry->flags & ZIP_LENGTH_AT_END) + if (0 == (zip_entry->zip_flags & ZIP_LENGTH_AT_END) && zip->entry_bytes_remaining < 1) zip->end_of_entry = 1; @@ -1128,138 +751,6 @@ zip_read_local_file_header(struct archive_read *a, struct archive_entry *entry, return (ret); } -static const char * -compression_name(int compression) -{ - static const char *compression_names[] = { - "uncompressed", - "shrinking", - "reduced-1", - "reduced-2", - "reduced-3", - "reduced-4", - "imploded", - "reserved", - "deflation" - }; - - if (0 <= compression && compression < - (int)(sizeof(compression_names)/sizeof(compression_names[0]))) - return compression_names[compression]; - else - return "??"; -} - -/* Convert an MSDOS-style date/time into Unix-style time. */ -static time_t -zip_time(const char *p) -{ - int msTime, msDate; - struct tm ts; - - msTime = (0xff & (unsigned)p[0]) + 256 * (0xff & (unsigned)p[1]); - msDate = (0xff & (unsigned)p[2]) + 256 * (0xff & (unsigned)p[3]); - - memset(&ts, 0, sizeof(ts)); - ts.tm_year = ((msDate >> 9) & 0x7f) + 80; /* Years since 1900. */ - ts.tm_mon = ((msDate >> 5) & 0x0f) - 1; /* Month number. */ - ts.tm_mday = msDate & 0x1f; /* Day of month. */ - ts.tm_hour = (msTime >> 11) & 0x1f; - ts.tm_min = (msTime >> 5) & 0x3f; - ts.tm_sec = (msTime << 1) & 0x3e; - ts.tm_isdst = -1; - return mktime(&ts); -} - -static int -archive_read_format_zip_read_data(struct archive_read *a, - const void **buff, size_t *size, int64_t *offset) -{ - int r; - struct zip *zip = (struct zip *)(a->format->data); - - *offset = zip->entry_uncompressed_bytes_read; - *size = 0; - *buff = NULL; - - /* If we hit end-of-entry last time, return ARCHIVE_EOF. */ - if (zip->end_of_entry) - return (ARCHIVE_EOF); - - /* Return EOF immediately if this is a non-regular file. */ - if (AE_IFREG != (zip->entry->mode & AE_IFMT)) - return (ARCHIVE_EOF); - - if (zip->entry->flags & (ZIP_ENCRYPTED | ZIP_STRONG_ENCRYPTED)) { - archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, - "Encrypted file is unsupported"); - return (ARCHIVE_FAILED); - } - - zip_read_consume(a, zip->unconsumed); - zip->unconsumed = 0; - - switch(zip->entry->compression) { - case 0: /* No compression. */ - r = zip_read_data_none(a, buff, size, offset); - break; -#ifdef HAVE_ZLIB_H - case 8: /* Deflate compression. */ - r = zip_read_data_deflate(a, buff, size, offset); - break; -#endif - default: /* Unsupported compression. */ - /* Return a warning. */ - archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, - "Unsupported ZIP compression method (%s)", - compression_name(zip->entry->compression)); - /* We can't decompress this entry, but we will - * be able to skip() it and try the next entry. */ - return (ARCHIVE_FAILED); - break; - } - if (r != ARCHIVE_OK) - return (r); - /* Update checksum */ - if (*size) - zip->entry_crc32 = crc32(zip->entry_crc32, *buff, - (unsigned)*size); - /* If we hit the end, swallow any end-of-data marker. */ - if (zip->end_of_entry) { - /* Check file size, CRC against these values. */ - if (zip->entry->compressed_size != - zip->entry_compressed_bytes_read) { - archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "ZIP compressed data is wrong size " - "(read %jd, expected %jd)", - (intmax_t)zip->entry_compressed_bytes_read, - (intmax_t)zip->entry->compressed_size); - return (ARCHIVE_WARN); - } - /* Size field only stores the lower 32 bits of the actual - * size. */ - if ((zip->entry->uncompressed_size & UINT32_MAX) - != (zip->entry_uncompressed_bytes_read & UINT32_MAX)) { - archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "ZIP uncompressed data is wrong size " - "(read %jd, expected %jd)", - (intmax_t)zip->entry_uncompressed_bytes_read, - (intmax_t)zip->entry->uncompressed_size); - return (ARCHIVE_WARN); - } - /* Check computed CRC against header */ - if (zip->entry->crc32 != zip->entry_crc32) { - archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "ZIP bad CRC: 0x%lx should be 0x%lx", - (unsigned long)zip->entry_crc32, - (unsigned long)zip->entry->crc32); - return (ARCHIVE_WARN); - } - } - - return (ARCHIVE_OK); -} - /* * Read "uncompressed" data. There are three cases: * 1) We know the size of the data. This is always true for the @@ -1276,9 +767,10 @@ archive_read_format_zip_read_data(struct archive_read *a, * TODO: Technically, the PK\007\010 signature is optional. * In the original spec, the data descriptor contained CRC * and size fields but had no leading signature. In practice, - * newer writers seem to provide the signature pretty consistently, - * but we might need to do something more complex here if - * we want to handle older archives that lack that signature. + * newer writers seem to provide the signature pretty consistently. + * + * For uncompressed data, the PK\007\010 marker seems essential + * to be sure we've actually seen the end of the entry. * * Returns ARCHIVE_OK if successful, ARCHIVE_FATAL otherwise, sets * zip->end_of_entry if it consumes all of the data. @@ -1295,35 +787,40 @@ zip_read_data_none(struct archive_read *a, const void **_buff, zip = (struct zip *)(a->format->data); - if (zip->entry->flags & ZIP_LENGTH_AT_END) { + if (zip->entry->zip_flags & ZIP_LENGTH_AT_END) { const char *p; - /* Grab at least 16 bytes. */ - buff = __archive_read_ahead(a, 16, &bytes_avail); - if (bytes_avail < 16) { + /* Grab at least 24 bytes. */ + buff = __archive_read_ahead(a, 24, &bytes_avail); + if (bytes_avail < 24) { /* Zip archives have end-of-archive markers that are longer than this, so a failure to get at - least 16 bytes really does indicate a truncated + least 24 bytes really does indicate a truncated file. */ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, "Truncated ZIP file data"); return (ARCHIVE_FATAL); } - /* Check for a complete PK\007\010 signature. */ + /* Check for a complete PK\007\010 signature, followed + * by the correct 4-byte CRC. */ p = buff; - if (p[0] == 'P' && p[1] == 'K' + if (p[0] == 'P' && p[1] == 'K' && p[2] == '\007' && p[3] == '\010' - && archive_le32dec(p + 4) == zip->entry_crc32 - && archive_le32dec(p + 8) == - zip->entry_compressed_bytes_read - && archive_le32dec(p + 12) == - zip->entry_uncompressed_bytes_read) { - zip->entry->crc32 = archive_le32dec(p + 4); - zip->entry->compressed_size = archive_le32dec(p + 8); - zip->entry->uncompressed_size = archive_le32dec(p + 12); + && (archive_le32dec(p + 4) == zip->entry_crc32 + || zip->ignore_crc32)) { + if (zip->entry->flags & LA_USED_ZIP64) { + zip->entry->crc32 = archive_le32dec(p + 4); + zip->entry->compressed_size = archive_le64dec(p + 8); + zip->entry->uncompressed_size = archive_le64dec(p + 16); + zip->unconsumed = 24; + } else { + zip->entry->crc32 = archive_le32dec(p + 4); + zip->entry->compressed_size = archive_le32dec(p + 8); + zip->entry->uncompressed_size = archive_le32dec(p + 12); + zip->unconsumed = 16; + } zip->end_of_entry = 1; - zip->unconsumed = 16; return (ARCHIVE_OK); } /* If not at EOF, ensure we consume at least one byte. */ @@ -1430,7 +927,7 @@ zip_read_data_deflate(struct archive_read *a, const void **buff, * decompressor to combine reads by copying data. */ compressed_buff = __archive_read_ahead(a, 1, &bytes_avail); - if (0 == (zip->entry->flags & ZIP_LENGTH_AT_END) + if (0 == (zip->entry->zip_flags & ZIP_LENGTH_AT_END) && bytes_avail > zip->entry_bytes_remaining) { bytes_avail = (ssize_t)zip->entry_bytes_remaining; } @@ -1472,7 +969,7 @@ zip_read_data_deflate(struct archive_read *a, const void **buff, /* Consume as much as the compressor actually used. */ bytes_avail = zip->stream.total_in; - zip_read_consume(a, bytes_avail); + __archive_read_consume(a, bytes_avail); zip->entry_bytes_remaining -= bytes_avail; zip->entry_compressed_bytes_read += bytes_avail; @@ -1480,10 +977,10 @@ zip_read_data_deflate(struct archive_read *a, const void **buff, zip->entry_uncompressed_bytes_read += zip->stream.total_out; *buff = zip->uncompressed_buffer; - if (zip->end_of_entry && (zip->entry->flags & ZIP_LENGTH_AT_END)) { + if (zip->end_of_entry && (zip->entry->zip_flags & ZIP_LENGTH_AT_END)) { const char *p; - if (NULL == (p = __archive_read_ahead(a, 16, NULL))) { + if (NULL == (p = __archive_read_ahead(a, 24, NULL))) { archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, "Truncated ZIP end-of-file record"); @@ -1492,36 +989,378 @@ zip_read_data_deflate(struct archive_read *a, const void **buff, /* Consume the optional PK\007\010 marker. */ if (p[0] == 'P' && p[1] == 'K' && p[2] == '\007' && p[3] == '\010') { - zip->entry->crc32 = archive_le32dec(p + 4); - zip->entry->compressed_size = archive_le32dec(p + 8); - zip->entry->uncompressed_size = archive_le32dec(p + 12); - zip->unconsumed = 16; + p += 4; + zip->unconsumed = 4; + } + if (zip->entry->flags & LA_USED_ZIP64) { + zip->entry->crc32 = archive_le32dec(p); + zip->entry->compressed_size = archive_le64dec(p + 4); + zip->entry->uncompressed_size = archive_le64dec(p + 12); + zip->unconsumed += 20; + } else { + zip->entry->crc32 = archive_le32dec(p); + zip->entry->compressed_size = archive_le32dec(p + 4); + zip->entry->uncompressed_size = archive_le32dec(p + 8); + zip->unconsumed += 12; + } + } + + return (ARCHIVE_OK); +} +#endif + +static int +archive_read_format_zip_read_data(struct archive_read *a, + const void **buff, size_t *size, int64_t *offset) +{ + int r; + struct zip *zip = (struct zip *)(a->format->data); + + if (zip->has_encrypted_entries == ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW) { + zip->has_encrypted_entries = 0; + } + + *offset = zip->entry_uncompressed_bytes_read; + *size = 0; + *buff = NULL; + + /* If we hit end-of-entry last time, return ARCHIVE_EOF. */ + if (zip->end_of_entry) + return (ARCHIVE_EOF); + + /* Return EOF immediately if this is a non-regular file. */ + if (AE_IFREG != (zip->entry->mode & AE_IFMT)) + return (ARCHIVE_EOF); + + if (zip->entry->zip_flags & (ZIP_ENCRYPTED | ZIP_STRONG_ENCRYPTED)) { + zip->has_encrypted_entries = 1; + archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, + "Encrypted file is unsupported"); + return (ARCHIVE_FAILED); + } + + __archive_read_consume(a, zip->unconsumed); + zip->unconsumed = 0; + + switch(zip->entry->compression) { + case 0: /* No compression. */ + r = zip_read_data_none(a, buff, size, offset); + break; +#ifdef HAVE_ZLIB_H + case 8: /* Deflate compression. */ + r = zip_read_data_deflate(a, buff, size, offset); + break; +#endif + default: /* Unsupported compression. */ + /* Return a warning. */ + archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, + "Unsupported ZIP compression method (%s)", + compression_name(zip->entry->compression)); + /* We can't decompress this entry, but we will + * be able to skip() it and try the next entry. */ + return (ARCHIVE_FAILED); + break; + } + if (r != ARCHIVE_OK) + return (r); + /* Update checksum */ + if (*size) + zip->entry_crc32 = zip->crc32func(zip->entry_crc32, *buff, + (unsigned)*size); + /* If we hit the end, swallow any end-of-data marker. */ + if (zip->end_of_entry) { + /* Check file size, CRC against these values. */ + if (zip->entry->compressed_size != + zip->entry_compressed_bytes_read) { + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "ZIP compressed data is wrong size " + "(read %jd, expected %jd)", + (intmax_t)zip->entry_compressed_bytes_read, + (intmax_t)zip->entry->compressed_size); + return (ARCHIVE_WARN); + } + /* Size field only stores the lower 32 bits of the actual + * size. */ + if ((zip->entry->uncompressed_size & UINT32_MAX) + != (zip->entry_uncompressed_bytes_read & UINT32_MAX)) { + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "ZIP uncompressed data is wrong size " + "(read %jd, expected %jd)\n", + (intmax_t)zip->entry_uncompressed_bytes_read, + (intmax_t)zip->entry->uncompressed_size); + return (ARCHIVE_WARN); + } + /* Check computed CRC against header */ + if (zip->entry->crc32 != zip->entry_crc32 + && !zip->ignore_crc32) { + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "ZIP bad CRC: 0x%lx should be 0x%lx", + (unsigned long)zip->entry_crc32, + (unsigned long)zip->entry->crc32); + return (ARCHIVE_WARN); } } return (ARCHIVE_OK); } + +static int +archive_read_format_zip_cleanup(struct archive_read *a) +{ + struct zip *zip; + struct zip_entry *zip_entry, *next_zip_entry; + + zip = (struct zip *)(a->format->data); +#ifdef HAVE_ZLIB_H + if (zip->stream_valid) + inflateEnd(&zip->stream); + free(zip->uncompressed_buffer); #endif + if (zip->zip_entries) { + zip_entry = zip->zip_entries; + while (zip_entry != NULL) { + next_zip_entry = zip_entry->next; + archive_string_free(&zip_entry->rsrcname); + free(zip_entry); + zip_entry = next_zip_entry; + } + } + free(zip); + (a->format->data) = NULL; + return (ARCHIVE_OK); +} + +static int +archive_read_format_zip_has_encrypted_entries(struct archive_read *_a) +{ + if (_a && _a->format) { + struct zip * zip = (struct zip *)_a->format->data; + if (zip) { + return zip->has_encrypted_entries; + } + } + return ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW; +} static int -archive_read_format_zip_read_data_skip(struct archive_read *a) +archive_read_format_zip_options(struct archive_read *a, + const char *key, const char *val) { struct zip *zip; + int ret = ARCHIVE_FAILED; zip = (struct zip *)(a->format->data); + if (strcmp(key, "compat-2x") == 0) { + /* Handle filenames as libarchive 2.x */ + zip->init_default_conversion = (val != NULL) ? 1 : 0; + return (ARCHIVE_OK); + } else if (strcmp(key, "hdrcharset") == 0) { + if (val == NULL || val[0] == 0) + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "zip: hdrcharset option needs a character-set name" + ); + else { + zip->sconv = archive_string_conversion_from_charset( + &a->archive, val, 0); + if (zip->sconv != NULL) { + if (strcmp(val, "UTF-8") == 0) + zip->sconv_utf8 = zip->sconv; + ret = ARCHIVE_OK; + } else + ret = ARCHIVE_FATAL; + } + return (ret); + } else if (strcmp(key, "ignorecrc32") == 0) { + /* Mostly useful for testing. */ + if (val == NULL || val[0] == 0) { + zip->crc32func = real_crc32; + zip->ignore_crc32 = 0; + } else { + zip->crc32func = fake_crc32; + zip->ignore_crc32 = 1; + } + return (ARCHIVE_OK); + } else if (strcmp(key, "mac-ext") == 0) { + zip->process_mac_extensions = (val != NULL && val[0] != 0); + return (ARCHIVE_OK); + } + + /* Note: The "warn" return is just to inform the options + * supervisor that we didn't handle it. It will generate + * a suitable error if no one used this option. */ + return (ARCHIVE_WARN); +} + +int +archive_read_support_format_zip(struct archive *a) +{ + int r; + r = archive_read_support_format_zip_streamable(a); + if (r != ARCHIVE_OK) + return r; + return (archive_read_support_format_zip_seekable(a)); +} + +/* ------------------------------------------------------------------------ */ + +/* + * Streaming-mode support + */ + + +static int +archive_read_support_format_zip_capabilities_streamable(struct archive_read * a) +{ + (void)a; /* UNUSED */ + return (ARCHIVE_READ_FORMAT_CAPS_ENCRYPT_DATA | ARCHIVE_READ_FORMAT_CAPS_ENCRYPT_METADATA); +} + +static int +archive_read_format_zip_streamable_bid(struct archive_read *a, int best_bid) +{ + const char *p; + + (void)best_bid; /* UNUSED */ + + if ((p = __archive_read_ahead(a, 4, NULL)) == NULL) + return (-1); + + /* + * Bid of 29 here comes from: + * + 16 bits for "PK", + * + next 16-bit field has 6 options so contributes + * about 16 - log_2(6) ~= 16 - 2.6 ~= 13 bits + * + * So we've effectively verified ~29 total bits of check data. + */ + if (p[0] == 'P' && p[1] == 'K') { + if ((p[2] == '\001' && p[3] == '\002') + || (p[2] == '\003' && p[3] == '\004') + || (p[2] == '\005' && p[3] == '\006') + || (p[2] == '\006' && p[3] == '\006') + || (p[2] == '\007' && p[3] == '\010') + || (p[2] == '0' && p[3] == '0')) + return (29); + } + + /* TODO: It's worth looking ahead a little bit for a valid + * PK signature. In particular, that would make it possible + * to read some UUEncoded SFX files or SFX files coming from + * a network socket. */ + + return (0); +} + +static int +archive_read_format_zip_streamable_read_header(struct archive_read *a, + struct archive_entry *entry) +{ + struct zip *zip; + + a->archive.archive_format = ARCHIVE_FORMAT_ZIP; + if (a->archive.archive_format_name == NULL) + a->archive.archive_format_name = "ZIP"; + + zip = (struct zip *)(a->format->data); + + /* + * It should be sufficient to call archive_read_next_header() for + * a reader to determine if an entry is encrypted or not. If the + * encryption of an entry is only detectable when calling + * archive_read_data(), so be it. We'll do the same check there + * as well. + */ + if (zip->has_encrypted_entries == ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW) { + zip->has_encrypted_entries = 0; + } + + /* Make sure we have a zip_entry structure to use. */ + if (zip->zip_entries == NULL) { + zip->zip_entries = malloc(sizeof(struct zip_entry)); + if (zip->zip_entries == NULL) { + archive_set_error(&a->archive, ENOMEM, + "Out of memory"); + return ARCHIVE_FATAL; + } + } + zip->entry = zip->zip_entries; + memset(zip->entry, 0, sizeof(struct zip_entry)); + + /* Search ahead for the next local file header. */ + __archive_read_consume(a, zip->unconsumed); + zip->unconsumed = 0; + for (;;) { + int64_t skipped = 0; + const char *p, *end; + ssize_t bytes; + + p = __archive_read_ahead(a, 4, &bytes); + if (p == NULL) + return (ARCHIVE_FATAL); + end = p + bytes; + + while (p + 4 <= end) { + if (p[0] == 'P' && p[1] == 'K') { + if (p[2] == '\003' && p[3] == '\004') { + /* Regular file entry. */ + __archive_read_consume(a, skipped); + return zip_read_local_file_header(a, + entry, zip); + } + + /* + * TODO: We cannot restore permissions + * based only on the local file headers. + * Consider scanning the central + * directory and returning additional + * entries for at least directories. + * This would allow us to properly set + * directory permissions. + * + * This won't help us fix symlinks + * and may not help with regular file + * permissions, either. <sigh> + */ + if (p[2] == '\001' && p[3] == '\002') { + return (ARCHIVE_EOF); + } + + /* End of central directory? Must be an + * empty archive. */ + if ((p[2] == '\005' && p[3] == '\006') + || (p[2] == '\006' && p[3] == '\006')) + return (ARCHIVE_EOF); + } + ++p; + ++skipped; + } + __archive_read_consume(a, skipped); + } +} + +static int +archive_read_format_zip_read_data_skip_streamable(struct archive_read *a) +{ + struct zip *zip; + int64_t bytes_skipped; + + zip = (struct zip *)(a->format->data); + bytes_skipped = __archive_read_consume(a, zip->unconsumed); + zip->unconsumed = 0; + if (bytes_skipped < 0) + return (ARCHIVE_FATAL); /* If we've already read to end of data, we're done. */ if (zip->end_of_entry) return (ARCHIVE_OK); /* So we know we're streaming... */ - if (0 == (zip->entry->flags & ZIP_LENGTH_AT_END)) { + if (0 == (zip->entry->zip_flags & ZIP_LENGTH_AT_END) + || zip->entry->compressed_size > 0) { /* We know the compressed length, so we can just skip. */ - int64_t bytes_skipped = zip_read_consume(a, - zip->entry_bytes_remaining + zip->unconsumed); + bytes_skipped = __archive_read_consume(a, zip->entry_bytes_remaining); if (bytes_skipped < 0) return (ARCHIVE_FATAL); - zip->unconsumed = 0; return (ARCHIVE_OK); } @@ -1544,8 +1383,6 @@ archive_read_format_zip_read_data_skip(struct archive_read *a) #endif default: /* Uncompressed or unknown. */ /* Scan for a PK\007\010 signature. */ - zip_read_consume(a, zip->unconsumed); - zip->unconsumed = 0; for (;;) { const char *p, *buff; ssize_t bytes_avail; @@ -1563,180 +1400,772 @@ archive_read_format_zip_read_data_skip(struct archive_read *a) else if (p[3] == '\007') { p += 1; } else if (p[3] == '\010' && p[2] == '\007' && p[1] == 'K' && p[0] == 'P') { - zip_read_consume(a, p - buff + 16); + if (zip->entry->flags & LA_USED_ZIP64) + __archive_read_consume(a, p - buff + 24); + else + __archive_read_consume(a, p - buff + 16); return ARCHIVE_OK; } else { p += 4; } } - zip_read_consume(a, p - buff); + __archive_read_consume(a, p - buff); } } } -static int -archive_read_format_zip_cleanup(struct archive_read *a) +int +archive_read_support_format_zip_streamable(struct archive *_a) { + struct archive_read *a = (struct archive_read *)_a; struct zip *zip; + int r; - zip = (struct zip *)(a->format->data); -#ifdef HAVE_ZLIB_H - if (zip->stream_valid) - inflateEnd(&zip->stream); -#endif - if (zip->zip_entries && zip->central_directory_entries) { - unsigned i; - for (i = 0; i < zip->central_directory_entries; i++) - archive_string_free(&(zip->zip_entries[i].rsrcname)); + archive_check_magic(_a, ARCHIVE_READ_MAGIC, + ARCHIVE_STATE_NEW, "archive_read_support_format_zip"); + + zip = (struct zip *)malloc(sizeof(*zip)); + if (zip == NULL) { + archive_set_error(&a->archive, ENOMEM, + "Can't allocate zip data"); + return (ARCHIVE_FATAL); } - free(zip->zip_entries); - free(zip->uncompressed_buffer); - archive_string_free(&(zip->extra)); - free(zip); - (a->format->data) = NULL; + memset(zip, 0, sizeof(*zip)); + + /* Streamable reader doesn't support mac extensions. */ + zip->process_mac_extensions = 0; + + /* + * Until enough data has been read, we cannot tell about + * any encrypted entries yet. + */ + zip->has_encrypted_entries = ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW; + zip->crc32func = real_crc32; + + r = __archive_read_register_format(a, + zip, + "zip", + archive_read_format_zip_streamable_bid, + archive_read_format_zip_options, + archive_read_format_zip_streamable_read_header, + archive_read_format_zip_read_data, + archive_read_format_zip_read_data_skip_streamable, + NULL, + archive_read_format_zip_cleanup, + archive_read_support_format_zip_capabilities_streamable, + archive_read_format_zip_has_encrypted_entries); + + if (r != ARCHIVE_OK) + free(zip); return (ARCHIVE_OK); } +/* ------------------------------------------------------------------------ */ + /* - * The extra data is stored as a list of - * id1+size1+data1 + id2+size2+data2 ... - * triplets. id and size are 2 bytes each. + * Seeking-mode support */ + +static int +archive_read_support_format_zip_capabilities_seekable(struct archive_read * a) +{ + (void)a; /* UNUSED */ + return (ARCHIVE_READ_FORMAT_CAPS_ENCRYPT_DATA | ARCHIVE_READ_FORMAT_CAPS_ENCRYPT_METADATA); +} + +/* + * TODO: This is a performance sink because it forces the read core to + * drop buffered data from the start of file, which will then have to + * be re-read again if this bidder loses. + * + * We workaround this a little by passing in the best bid so far so + * that later bidders can do nothing if they know they'll never + * outbid. But we can certainly do better... + */ +static int +read_eocd(struct zip *zip, const char *p, int64_t current_offset) +{ + /* Sanity-check the EOCD we've found. */ + + /* This must be the first volume. */ + if (archive_le16dec(p + 4) != 0) + return 0; + /* Central directory must be on this volume. */ + if (archive_le16dec(p + 4) != 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) + return 0; + + /* Save the central directory location for later use. */ + zip->central_directory_offset = archive_le32dec(p + 16); + + /* This is just a tiny bit higher than the maximum + returned by the streaming Zip bidder. This ensures + that the more accurate seeking Zip parser wins + whenever seek is available. */ + return 32; +} + +static int +read_zip64_eocd(struct archive_read *a, struct zip *zip, const char *p) +{ + int64_t eocd64_offset; + int64_t eocd64_size; + + /* Sanity-check the locator record. */ + + /* Central dir must be on first volume. */ + if (archive_le32dec(p + 4) != 0) + return 0; + /* Must be only a single volume. */ + if (archive_le32dec(p + 16) != 1) + return 0; + + /* Find the Zip64 EOCD record. */ + eocd64_offset = archive_le64dec(p + 8); + if (__archive_read_seek(a, eocd64_offset, SEEK_SET) < 0) + return 0; + if ((p = __archive_read_ahead(a, 56, NULL)) == NULL) + return 0; + /* Make sure we can read all of it. */ + eocd64_size = archive_le64dec(p + 4) + 12; + if (eocd64_size < 56 || eocd64_size > 16384) + return 0; + if ((p = __archive_read_ahead(a, eocd64_size, NULL)) == NULL) + return 0; + + /* Sanity-check the EOCD64 */ + if (archive_le32dec(p + 16) != 0) /* Must be disk #0 */ + return 0; + if (archive_le32dec(p + 20) != 0) /* CD must be on disk #0 */ + return 0; + /* CD can't be split. */ + if (archive_le64dec(p + 24) != archive_le64dec(p + 32)) + return 0; + + /* Save the central directory offset for later use. */ + zip->central_directory_offset = archive_le64dec(p + 48); + + return 32; +} + +static int +archive_read_format_zip_seekable_bid(struct archive_read *a, int best_bid) +{ + struct zip *zip = (struct zip *)a->format->data; + int64_t file_size, current_offset; + const char *p; + int i, tail; + + /* If someone has already bid more than 32, then avoid + trashing the look-ahead buffers with a seek. */ + if (best_bid > 32) + return (-1); + + file_size = __archive_read_seek(a, 0, SEEK_END); + if (file_size <= 0) + return 0; + + /* Search last 16k of file for end-of-central-directory + * record (which starts with PK\005\006) or Zip64 locator + * record (which begins with PK\006\007) */ + tail = zipmin(1024 * 16, file_size); + current_offset = __archive_read_seek(a, -tail, SEEK_END); + if (current_offset < 0) + return 0; + if ((p = __archive_read_ahead(a, (size_t)tail, NULL)) == NULL) + return 0; + /* TODO: Rework this to search backwards from the end. We + * normally expect the EOCD record to be at the very end, so + * that should be significantly faster. Tricky part: Make + * sure we still prefer the Zip64 locator if it's present. */ + for (i = 0; i <= tail - 22;) { + switch (p[i + 3]) { + case 'P': i += 3; break; + case 'K': i += 2; break; + case 005: i += 1; break; + case 006: + if (memcmp(p + i, "PK\005\006", 4) == 0) { + int ret = read_eocd(zip, p + i, current_offset + i); + if (ret > 0) + return (ret); + } + i += 1; /* Look for PK\006\007 next */ + break; + case 007: + if (memcmp(p + i, "PK\006\007", 4) == 0) { + int ret = read_zip64_eocd(a, zip, p + i); + if (ret > 0) + return (ret); + } + i += 4; + break; + default: i += 4; break; + } + } + return 0; +} + +/* The red-black trees are only used in seeking mode to manage + * the in-memory copy of the central directory. */ + +static int +cmp_node(const struct archive_rb_node *n1, const struct archive_rb_node *n2) +{ + const struct zip_entry *e1 = (const struct zip_entry *)n1; + const struct zip_entry *e2 = (const struct zip_entry *)n2; + + if (e1->local_header_offset > e2->local_header_offset) + return -1; + if (e1->local_header_offset < e2->local_header_offset) + return 1; + return 0; +} + +static int +cmp_key(const struct archive_rb_node *n, const void *key) +{ + /* This function won't be called */ + (void)n; /* UNUSED */ + (void)key; /* UNUSED */ + return 1; +} + +static const struct archive_rb_tree_ops rb_ops = { + &cmp_node, &cmp_key +}; + +static int +rsrc_cmp_node(const struct archive_rb_node *n1, + const struct archive_rb_node *n2) +{ + const struct zip_entry *e1 = (const struct zip_entry *)n1; + const struct zip_entry *e2 = (const struct zip_entry *)n2; + + return (strcmp(e2->rsrcname.s, e1->rsrcname.s)); +} + +static int +rsrc_cmp_key(const struct archive_rb_node *n, const void *key) +{ + const struct zip_entry *e = (const struct zip_entry *)n; + return (strcmp((const char *)key, e->rsrcname.s)); +} + +static const struct archive_rb_tree_ops rb_rsrc_ops = { + &rsrc_cmp_node, &rsrc_cmp_key +}; + +static const char * +rsrc_basename(const char *name, size_t name_length) +{ + const char *s, *r; + + r = s = name; + for (;;) { + s = memchr(s, '/', name_length - (s - name)); + if (s == NULL) + break; + r = ++s; + } + return (r); +} + static void -process_extra(const char *p, size_t extra_length, struct zip_entry* zip_entry) +expose_parent_dirs(struct zip *zip, const char *name, size_t name_length) { - unsigned offset = 0; + struct archive_string str; + struct zip_entry *dir; + char *s; - while (offset < extra_length - 4) - { - unsigned short headerid = archive_le16dec(p + offset); - unsigned short datasize = archive_le16dec(p + offset + 2); - offset += 4; - if (offset + datasize > extra_length) + archive_string_init(&str); + archive_strncpy(&str, name, name_length); + for (;;) { + s = strrchr(str.s, '/'); + if (s == NULL) break; -#ifdef DEBUG - fprintf(stderr, "Header id 0x%x, length %d\n", - headerid, datasize); -#endif - switch (headerid) { - case 0x0001: - /* Zip64 extended information extra field. */ - if (datasize >= 8) - zip_entry->uncompressed_size = - archive_le64dec(p + offset); - if (datasize >= 16) - zip_entry->compressed_size = - archive_le64dec(p + offset + 8); + *s = '\0'; + /* Transfer the parent directory from zip->tree_rsrc RB + * tree to zip->tree RB tree to expose. */ + dir = (struct zip_entry *) + __archive_rb_tree_find_node(&zip->tree_rsrc, str.s); + if (dir == NULL) break; - case 0x5455: - { - /* Extended time field "UT". */ - int flags = p[offset]; - offset++; - datasize--; - /* Flag bits indicate which dates are present. */ - if (flags & 0x01) - { -#ifdef DEBUG - fprintf(stderr, "mtime: %lld -> %d\n", - (long long)zip_entry->mtime, - archive_le32dec(p + offset)); -#endif - if (datasize < 4) - break; - zip_entry->mtime = archive_le32dec(p + offset); - offset += 4; - datasize -= 4; - } - if (flags & 0x02) - { - if (datasize < 4) - break; - zip_entry->atime = archive_le32dec(p + offset); - offset += 4; - datasize -= 4; - } - if (flags & 0x04) - { - if (datasize < 4) - break; - zip_entry->ctime = archive_le32dec(p + offset); - offset += 4; - datasize -= 4; + __archive_rb_tree_remove_node(&zip->tree_rsrc, &dir->node); + archive_string_free(&dir->rsrcname); + __archive_rb_tree_insert_node(&zip->tree, &dir->node); + } + archive_string_free(&str); +} + +static int +slurp_central_directory(struct archive_read *a, struct zip *zip) +{ + ssize_t i; + unsigned found; + int64_t correction; + ssize_t bytes_avail; + const char *p; + + /* + * Find the start of the central directory. The end-of-CD + * record has our starting point, but there are lots of + * Zip archives which have had other data prepended to the + * file, which makes the recorded offsets all too small. + * So we search forward from the specified offset until we + * find the real start of the central directory. Then we + * know the correction we need to apply to account for leading + * padding. + */ + if (__archive_read_seek(a, zip->central_directory_offset, SEEK_SET) < 0) + return ARCHIVE_FATAL; + + found = 0; + while (!found) { + if ((p = __archive_read_ahead(a, 20, &bytes_avail)) == NULL) + return ARCHIVE_FATAL; + for (found = 0, i = 0; !found && i < bytes_avail - 4;) { + switch (p[i + 3]) { + case 'P': i += 3; break; + case 'K': i += 2; break; + case 001: i += 1; break; + case 002: + if (memcmp(p + i, "PK\001\002", 4) == 0) { + p += i; + found = 1; + } else + i += 4; + break; + case 005: i += 1; break; + case 006: + if (memcmp(p + i, "PK\005\006", 4) == 0) { + p += i; + found = 1; + } else if (memcmp(p + i, "PK\006\006", 4) == 0) { + p += i; + found = 1; + } else + i += 1; + break; + default: i += 4; break; } + } + __archive_read_consume(a, i); + } + correction = archive_filter_bytes(&a->archive, 0) - zip->central_directory_offset; + + __archive_rb_tree_init(&zip->tree, &rb_ops); + __archive_rb_tree_init(&zip->tree_rsrc, &rb_rsrc_ops); + + zip->central_directory_entries_total = 0; + while (1) { + struct zip_entry *zip_entry; + size_t filename_length, extra_length, comment_length; + uint32_t external_attributes; + const char *name, *r; + + if ((p = __archive_read_ahead(a, 4, NULL)) == NULL) + return ARCHIVE_FATAL; + if (memcmp(p, "PK\006\006", 4) == 0 + || memcmp(p, "PK\005\006", 4) == 0) { break; + } else if (memcmp(p, "PK\001\002", 4) != 0) { + archive_set_error(&a->archive, + -1, "Invalid central directory signature"); + return ARCHIVE_FATAL; } - case 0x5855: - { - /* Info-ZIP Unix Extra Field (old version) "UX". */ - if (datasize >= 8) { - zip_entry->atime = archive_le32dec(p + offset); - zip_entry->mtime = - archive_le32dec(p + offset + 4); - } - if (datasize >= 12) { - zip_entry->uid = - archive_le16dec(p + offset + 8); - zip_entry->gid = - archive_le16dec(p + offset + 10); + if ((p = __archive_read_ahead(a, 46, NULL)) == NULL) + return ARCHIVE_FATAL; + + zip_entry = calloc(1, sizeof(struct zip_entry)); + zip_entry->next = zip->zip_entries; + zip_entry->flags |= LA_FROM_CENTRAL_DIRECTORY; + zip->zip_entries = zip_entry; + zip->central_directory_entries_total++; + + /* version = p[4]; */ + zip_entry->system = p[5]; + /* version_required = archive_le16dec(p + 6); */ + zip_entry->zip_flags = archive_le16dec(p + 8); + if (zip_entry->zip_flags & (ZIP_ENCRYPTED | ZIP_STRONG_ENCRYPTED)){ + zip->has_encrypted_entries = 1; + } + zip_entry->compression = (char)archive_le16dec(p + 10); + zip_entry->mtime = zip_time(p + 12); + zip_entry->crc32 = archive_le32dec(p + 16); + zip_entry->compressed_size = archive_le32dec(p + 20); + zip_entry->uncompressed_size = archive_le32dec(p + 24); + filename_length = archive_le16dec(p + 28); + extra_length = archive_le16dec(p + 30); + comment_length = archive_le16dec(p + 32); + /* disk_start = archive_le16dec(p + 34); */ /* Better be zero. */ + /* internal_attributes = archive_le16dec(p + 36); */ /* text bit */ + external_attributes = archive_le32dec(p + 38); + zip_entry->local_header_offset = + archive_le32dec(p + 42) + correction; + + /* If we can't guess the mode, leave it zero here; + when we read the local file header we might get + more information. */ + zip_entry->mode = 0; + if (zip_entry->system == 3) { + zip_entry->mode = external_attributes >> 16; + } + + /* We're done with the regular data; get the filename and + * extra data. */ + __archive_read_consume(a, 46); + if ((p = __archive_read_ahead(a, filename_length + extra_length, NULL)) + == NULL) { + archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, + "Truncated ZIP file header"); + return ARCHIVE_FATAL; + } + process_extra(p + filename_length, extra_length, zip_entry); + + /* + * Mac resource fork files are stored under the + * "__MACOSX/" directory, so we should check if + * it is. + */ + if (!zip->process_mac_extensions) { + /* Treat every entry as a regular entry. */ + __archive_rb_tree_insert_node(&zip->tree, + &zip_entry->node); + } else { + name = p; + r = rsrc_basename(name, filename_length); + if (filename_length >= 9 && + strncmp("__MACOSX/", name, 9) == 0) { + /* If this file is not a resource fork nor + * a directory. We should treat it as a non + * resource fork file to expose it. */ + if (name[filename_length-1] != '/' && + (r - name < 3 || r[0] != '.' || r[1] != '_')) { + __archive_rb_tree_insert_node(&zip->tree, + &zip_entry->node); + /* Expose its parent directories. */ + expose_parent_dirs(zip, name, filename_length); + } else { + /* This file is a resource fork file or + * a directory. */ + archive_strncpy(&(zip_entry->rsrcname), name, + filename_length); + __archive_rb_tree_insert_node(&zip->tree_rsrc, + &zip_entry->node); + } + } else { + /* Generate resource fork name to find its resource + * file at zip->tree_rsrc. */ + archive_strcpy(&(zip_entry->rsrcname), "__MACOSX/"); + archive_strncat(&(zip_entry->rsrcname), name, r - name); + archive_strcat(&(zip_entry->rsrcname), "._"); + archive_strncat(&(zip_entry->rsrcname), + name + (r - name), filename_length - (r - name)); + /* Register an entry to RB tree to sort it by + * file offset. */ + __archive_rb_tree_insert_node(&zip->tree, + &zip_entry->node); } - break; } - case 0x7855: - /* Info-ZIP Unix Extra Field (type 2) "Ux". */ -#ifdef DEBUG - fprintf(stderr, "uid %d gid %d\n", - archive_le16dec(p + offset), - archive_le16dec(p + offset + 2)); + + /* Skip the comment too ... */ + __archive_read_consume(a, + filename_length + extra_length + comment_length); + } + + return ARCHIVE_OK; +} + +static ssize_t +zip_get_local_file_header_size(struct archive_read *a, size_t extra) +{ + const char *p; + ssize_t filename_length, extra_length; + + if ((p = __archive_read_ahead(a, extra + 30, NULL)) == NULL) { + archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, + "Truncated ZIP file header"); + return (ARCHIVE_WARN); + } + p += extra; + + if (memcmp(p, "PK\003\004", 4) != 0) { + archive_set_error(&a->archive, -1, "Damaged Zip archive"); + return ARCHIVE_WARN; + } + filename_length = archive_le16dec(p + 26); + extra_length = archive_le16dec(p + 28); + + return (30 + filename_length + extra_length); +} + +static int +zip_read_mac_metadata(struct archive_read *a, struct archive_entry *entry, + struct zip_entry *rsrc) +{ + struct zip *zip = (struct zip *)a->format->data; + unsigned char *metadata, *mp; + int64_t offset = archive_filter_bytes(&a->archive, 0); + size_t remaining_bytes, metadata_bytes; + ssize_t hsize; + int ret = ARCHIVE_OK, eof; + + switch(rsrc->compression) { + case 0: /* No compression. */ +#ifdef HAVE_ZLIB_H + case 8: /* Deflate compression. */ #endif - if (datasize >= 2) - zip_entry->uid = archive_le16dec(p + offset); - if (datasize >= 4) - zip_entry->gid = - archive_le16dec(p + offset + 2); + break; + default: /* Unsupported compression. */ + /* Return a warning. */ + archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, + "Unsupported ZIP compression method (%s)", + compression_name(rsrc->compression)); + /* We can't decompress this entry, but we will + * be able to skip() it and try the next entry. */ + return (ARCHIVE_WARN); + } + + if (rsrc->uncompressed_size > (4 * 1024 * 1024)) { + archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, + "Mac metadata is too large: %jd > 4M bytes", + (intmax_t)rsrc->uncompressed_size); + return (ARCHIVE_WARN); + } + + metadata = malloc((size_t)rsrc->uncompressed_size); + if (metadata == NULL) { + archive_set_error(&a->archive, ENOMEM, + "Can't allocate memory for Mac metadata"); + return (ARCHIVE_FATAL); + } + + if (offset < rsrc->local_header_offset) + __archive_read_consume(a, rsrc->local_header_offset - offset); + else if (offset != rsrc->local_header_offset) { + __archive_read_seek(a, rsrc->local_header_offset, SEEK_SET); + } + + hsize = zip_get_local_file_header_size(a, 0); + __archive_read_consume(a, hsize); + + remaining_bytes = (size_t)rsrc->compressed_size; + metadata_bytes = (size_t)rsrc->uncompressed_size; + mp = metadata; + eof = 0; + while (!eof && remaining_bytes) { + const unsigned char *p; + ssize_t bytes_avail; + size_t bytes_used; + + p = __archive_read_ahead(a, 1, &bytes_avail); + if (p == NULL) { + archive_set_error(&a->archive, + ARCHIVE_ERRNO_FILE_FORMAT, + "Truncated ZIP file header"); + ret = ARCHIVE_WARN; + goto exit_mac_metadata; + } + if ((size_t)bytes_avail > remaining_bytes) + bytes_avail = remaining_bytes; + switch(rsrc->compression) { + case 0: /* No compression. */ + memcpy(mp, p, bytes_avail); + bytes_used = (size_t)bytes_avail; + metadata_bytes -= bytes_used; + mp += bytes_used; + if (metadata_bytes == 0) + eof = 1; break; - case 0x7875: +#ifdef HAVE_ZLIB_H + case 8: /* Deflate compression. */ { - /* Info-Zip Unix Extra Field (type 3) "ux". */ - int uidsize = 0, gidsize = 0; + int r; - if (datasize >= 1 && p[offset] == 1) {/* version=1 */ - if (datasize >= 4) { - /* get a uid size. */ - uidsize = p[offset+1]; - if (uidsize == 2) - zip_entry->uid = - archive_le16dec( - p + offset + 2); - else if (uidsize == 4 && datasize >= 6) - zip_entry->uid = - archive_le32dec( - p + offset + 2); - } - if (datasize >= (2 + uidsize + 3)) { - /* get a gid size. */ - gidsize = p[offset+2+uidsize]; - if (gidsize == 2) - zip_entry->gid = - archive_le16dec( - p+offset+2+uidsize+1); - else if (gidsize == 4 && - datasize >= (2 + uidsize + 5)) - zip_entry->gid = - archive_le32dec( - p+offset+2+uidsize+1); - } + ret = zip_deflate_init(a, zip); + if (ret != ARCHIVE_OK) + goto exit_mac_metadata; + zip->stream.next_in = + (Bytef *)(uintptr_t)(const void *)p; + zip->stream.avail_in = (uInt)bytes_avail; + zip->stream.total_in = 0; + zip->stream.next_out = mp; + zip->stream.avail_out = (uInt)metadata_bytes; + zip->stream.total_out = 0; + + r = inflate(&zip->stream, 0); + switch (r) { + case Z_OK: + break; + case Z_STREAM_END: + eof = 1; + break; + case Z_MEM_ERROR: + archive_set_error(&a->archive, ENOMEM, + "Out of memory for ZIP decompression"); + ret = ARCHIVE_FATAL; + goto exit_mac_metadata; + default: + archive_set_error(&a->archive, + ARCHIVE_ERRNO_MISC, + "ZIP decompression failed (%d)", r); + ret = ARCHIVE_FATAL; + goto exit_mac_metadata; } + bytes_used = zip->stream.total_in; + metadata_bytes -= zip->stream.total_out; + mp += zip->stream.total_out; break; } +#endif default: + bytes_used = 0; break; } - offset += datasize; + __archive_read_consume(a, bytes_used); + remaining_bytes -= bytes_used; } -#ifdef DEBUG - if (offset != extra_length) - { - fprintf(stderr, - "Extra data field contents do not match reported size!\n"); + archive_entry_copy_mac_metadata(entry, metadata, + (size_t)rsrc->uncompressed_size - metadata_bytes); + +exit_mac_metadata: + __archive_read_seek(a, offset, SEEK_SET); + zip->decompress_init = 0; + free(metadata); + return (ret); +} + +static int +archive_read_format_zip_seekable_read_header(struct archive_read *a, + struct archive_entry *entry) +{ + struct zip *zip = (struct zip *)a->format->data; + struct zip_entry *rsrc; + int64_t offset; + int r, ret = ARCHIVE_OK; + + /* + * It should be sufficient to call archive_read_next_header() for + * a reader to determine if an entry is encrypted or not. If the + * encryption of an entry is only detectable when calling + * archive_read_data(), so be it. We'll do the same check there + * as well. + */ + if (zip->has_encrypted_entries == ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW) { + zip->has_encrypted_entries = 0; + } + + a->archive.archive_format = ARCHIVE_FORMAT_ZIP; + if (a->archive.archive_format_name == NULL) + a->archive.archive_format_name = "ZIP"; + + if (zip->zip_entries == NULL) { + r = slurp_central_directory(a, zip); + if (r != ARCHIVE_OK) + return r; + /* Get first entry whose local header offset is lower than + * other entries in the archive file. */ + zip->entry = + (struct zip_entry *)ARCHIVE_RB_TREE_MIN(&zip->tree); + } else if (zip->entry != NULL) { + /* Get next entry in local header offset order. */ + zip->entry = (struct zip_entry *)__archive_rb_tree_iterate( + &zip->tree, &zip->entry->node, ARCHIVE_RB_DIR_RIGHT); + } + + if (zip->entry == NULL) + return ARCHIVE_EOF; + + if (zip->entry->rsrcname.s) + rsrc = (struct zip_entry *)__archive_rb_tree_find_node( + &zip->tree_rsrc, zip->entry->rsrcname.s); + else + rsrc = NULL; + + /* File entries are sorted by the header offset, we should mostly + * use __archive_read_consume to advance a read point to avoid redundant + * data reading. */ + offset = archive_filter_bytes(&a->archive, 0); + if (offset < zip->entry->local_header_offset) + __archive_read_consume(a, + zip->entry->local_header_offset - offset); + else if (offset != zip->entry->local_header_offset) { + __archive_read_seek(a, zip->entry->local_header_offset, SEEK_SET); } + zip->unconsumed = 0; + r = zip_read_local_file_header(a, entry, zip); + if (r != ARCHIVE_OK) + return r; + if (rsrc) { + int ret2 = zip_read_mac_metadata(a, entry, rsrc); + if (ret2 < ret) + ret = ret2; + } + return (ret); +} + +/* + * We're going to seek for the next header anyway, so we don't + * need to bother doing anything here. + */ +static int +archive_read_format_zip_read_data_skip_seekable(struct archive_read *a) +{ + struct zip *zip; + zip = (struct zip *)(a->format->data); + + zip->unconsumed = 0; + return (ARCHIVE_OK); +} + +int +archive_read_support_format_zip_seekable(struct archive *_a) +{ + struct archive_read *a = (struct archive_read *)_a; + struct zip *zip; + int r; + + archive_check_magic(_a, ARCHIVE_READ_MAGIC, + ARCHIVE_STATE_NEW, "archive_read_support_format_zip_seekable"); + + zip = (struct zip *)malloc(sizeof(*zip)); + if (zip == NULL) { + archive_set_error(&a->archive, ENOMEM, + "Can't allocate zip data"); + return (ARCHIVE_FATAL); + } + memset(zip, 0, sizeof(*zip)); + +#ifdef HAVE_COPYFILE_H + /* Set this by default on Mac OS. */ + zip->process_mac_extensions = 1; #endif + + /* + * Until enough data has been read, we cannot tell about + * any encrypted entries yet. + */ + zip->has_encrypted_entries = ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW; + zip->crc32func = real_crc32; + + r = __archive_read_register_format(a, + zip, + "zip", + archive_read_format_zip_seekable_bid, + archive_read_format_zip_options, + archive_read_format_zip_seekable_read_header, + archive_read_format_zip_read_data, + archive_read_format_zip_read_data_skip_seekable, + NULL, + archive_read_format_zip_cleanup, + archive_read_support_format_zip_capabilities_seekable, + archive_read_format_zip_has_encrypted_entries); + + if (r != ARCHIVE_OK) + free(zip); + return (ARCHIVE_OK); } diff --git a/Utilities/cmlibarchive/libarchive/archive_util.c b/Utilities/cmlibarchive/libarchive/archive_util.c index 34d8081..b53beca 100644 --- a/Utilities/cmlibarchive/libarchive/archive_util.c +++ b/Utilities/cmlibarchive/libarchive/archive_util.c @@ -45,6 +45,15 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_util.c 201098 2009-12-28 02:58:1 #if defined(HAVE_WINCRYPT_H) && !defined(__CYGWIN__) #include <wincrypt.h> #endif +#ifdef HAVE_ZLIB_H +#include <cm_zlib.h> +#endif +#ifdef HAVE_LZMA_H +#include <lzma.h> +#endif +#ifdef HAVE_BZLIB_H +#include <cm_bzlib.h> +#endif #include "archive.h" #include "archive_private.h" @@ -54,6 +63,8 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_util.c 201098 2009-12-28 02:58:1 #define O_CLOEXEC 0 #endif +static int archive_utility_string_sort_helper(char **, unsigned int); + /* Generic initialization of 'struct archive' objects. */ int __archive_clean(struct archive *a) @@ -74,6 +85,38 @@ archive_version_string(void) return (ARCHIVE_VERSION_STRING); } +const char * +archive_version_details(void) +{ + static struct archive_string str; + static int init = 0; + + if (!init) { + archive_string_init(&str); + + archive_strcat(&str, ARCHIVE_VERSION_STRING); +#ifdef HAVE_ZLIB_H + archive_strcat(&str, " zlib/"); + archive_strcat(&str, ZLIB_VERSION); +#endif +#ifdef HAVE_LZMA_H + archive_strcat(&str, " liblzma/"); + archive_strcat(&str, LZMA_VERSION_STRING); +#endif +#ifdef HAVE_BZLIB_H + { + const char *p = BZ2_bzlibVersion(); + const char *sep = strchr(p, ','); + if (sep == NULL) + sep = p + strlen(p); + archive_strcat(&str, " bz2lib/"); + archive_strncat(&str, p, sep - p); + } +#endif + } + return str.s; +} + int archive_errno(struct archive *a) { @@ -499,3 +542,69 @@ __archive_ensure_cloexec_flag(int fd) } #endif } + +/* + * Utility function to sort a group of strings using quicksort. + */ +static int +archive_utility_string_sort_helper(char **strings, unsigned int n) +{ + unsigned int i, lesser_count, greater_count; + char **lesser, **greater, **tmp, *pivot; + int retval1, retval2; + + /* A list of 0 or 1 elements is already sorted */ + if (n <= 1) + return (ARCHIVE_OK); + + lesser_count = greater_count = 0; + lesser = greater = NULL; + pivot = strings[0]; + for (i = 1; i < n; i++) + { + if (strcmp(strings[i], pivot) < 0) + { + lesser_count++; + tmp = (char **)realloc(lesser, lesser_count * sizeof(char *)); + if (!tmp) + return (ARCHIVE_FATAL); + lesser = tmp; + lesser[lesser_count - 1] = strings[i]; + } + else + { + greater_count++; + tmp = (char **)realloc(greater, greater_count * sizeof(char *)); + if (!tmp) + return (ARCHIVE_FATAL); + greater = tmp; + greater[greater_count - 1] = strings[i]; + } + } + + /* quicksort(lesser) */ + retval1 = archive_utility_string_sort_helper(lesser, lesser_count); + for (i = 0; i < lesser_count; i++) + strings[i] = lesser[i]; + free(lesser); + + /* pivot */ + strings[lesser_count] = pivot; + + /* quicksort(greater) */ + retval2 = archive_utility_string_sort_helper(greater, greater_count); + for (i = 0; i < greater_count; i++) + strings[lesser_count + 1 + i] = greater[i]; + free(greater); + + return (retval1 < retval2) ? retval1 : retval2; +} + +int +archive_utility_string_sort(char **strings) +{ + unsigned int size = 0; + while (strings[size] != NULL) + size++; + return archive_utility_string_sort_helper(strings, size); +} diff --git a/Utilities/cmlibarchive/libarchive/archive_virtual.c b/Utilities/cmlibarchive/libarchive/archive_virtual.c index 0c4155f..de2595a 100644 --- a/Utilities/cmlibarchive/libarchive/archive_virtual.c +++ b/Utilities/cmlibarchive/libarchive/archive_virtual.c @@ -55,6 +55,14 @@ archive_filter_bytes(struct archive *a, int n) } int +archive_free(struct archive *a) +{ + if (a == NULL) + return (ARCHIVE_OK); + return ((a->vtable->archive_free)(a)); +} + +int archive_write_close(struct archive *a) { return ((a->vtable->archive_close)(a)); @@ -76,9 +84,7 @@ archive_write_fail(struct archive *a) int archive_write_free(struct archive *a) { - if (a == NULL) - return (ARCHIVE_OK); - return ((a->vtable->archive_free)(a)); + return archive_free(a); } #if ARCHIVE_VERSION_NUMBER < 4000000 @@ -93,9 +99,7 @@ archive_write_finish(struct archive *a) int archive_read_free(struct archive *a) { - if (a == NULL) - return (ARCHIVE_OK); - return ((a->vtable->archive_free)(a)); + return archive_free(a); } #if ARCHIVE_VERSION_NUMBER < 4000000 diff --git a/Utilities/cmlibarchive/libarchive/archive_windows.c b/Utilities/cmlibarchive/libarchive/archive_windows.c index d3bf758..d4e93fe 100644 --- a/Utilities/cmlibarchive/libarchive/archive_windows.c +++ b/Utilities/cmlibarchive/libarchive/archive_windows.c @@ -301,7 +301,7 @@ __la_open(const char *path, int flags, ...) ws = NULL; if ((flags & ~O_BINARY) == O_RDONLY) { /* - * When we open a directory, _open function returns + * When we open a directory, _open function returns * "Permission denied" error. */ attr = GetFileAttributesA(path); @@ -515,9 +515,9 @@ __hstat(HANDLE handle, struct ustat *st) else mode |= S_IFREG; st->st_mode = mode; - + fileTimeToUTC(&info.ftLastAccessTime, &t, &ns); - st->st_atime = t; + st->st_atime = t; st->st_atime_nsec = ns; fileTimeToUTC(&info.ftLastWriteTime, &t, &ns); st->st_mtime = t; @@ -525,7 +525,7 @@ __hstat(HANDLE handle, struct ustat *st) fileTimeToUTC(&info.ftCreationTime, &t, &ns); st->st_ctime = t; st->st_ctime_nsec = ns; - st->st_size = + st->st_size = ((int64_t)(info.nFileSizeHigh) * ((int64_t)MAXDWORD + 1)) + (int64_t)(info.nFileSizeLow); #ifdef SIMULATE_WIN_STAT @@ -599,7 +599,7 @@ __la_stat(const char *path, struct stat *st) struct ustat u; int ret; - handle = la_CreateFile(path, 0, 0, NULL, OPEN_EXISTING, + handle = la_CreateFile(path, 0, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); if (handle == INVALID_HANDLE_VALUE) { diff --git a/Utilities/cmlibarchive/libarchive/archive_windows.h b/Utilities/cmlibarchive/libarchive/archive_windows.h index 1dd61b6..9a19cdf 100644 --- a/Utilities/cmlibarchive/libarchive/archive_windows.h +++ b/Utilities/cmlibarchive/libarchive/archive_windows.h @@ -93,7 +93,7 @@ /* Alias the Windows _function to the POSIX equivalent. */ #define close _close -#define fcntl(fd, cmd, flg) /* No operation. */ +#define fcntl(fd, cmd, flg) /* No operation. */ #ifndef fileno #define fileno _fileno #endif @@ -113,13 +113,14 @@ #define lstat __la_stat #define open __la_open #define read __la_read -#if !defined(__BORLANDC__) +#if !defined(__BORLANDC__) && !defined(__WATCOMC__) #define setmode _setmode #endif #ifdef stat #undef stat #endif #define stat(path,stref) __la_stat(path,stref) +#if !defined(__WATCOMC__) #if !defined(__BORLANDC__) #define strdup _strdup #endif @@ -127,9 +128,12 @@ #if !defined(__BORLANDC__) #define umask _umask #endif +#endif #define waitpid __la_waitpid #define write __la_write +#if !defined(__WATCOMC__) + #ifndef O_RDONLY #define O_RDONLY _O_RDONLY #define O_WRONLY _O_WRONLY @@ -189,8 +193,6 @@ #define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) /* regular file */ #endif -#if !defined(__WATCOMC__) - #define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) /* Symbolic link */ #define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK) /* Socket */ @@ -210,7 +212,7 @@ #define _S_IXGRP (_S_IXUSR >> 3) /* read permission, group */ #define _S_IWGRP (_S_IWUSR >> 3) /* write permission, group */ #define _S_IRGRP (_S_IRUSR >> 3) /* execute/search permission, group */ -#define _S_IRWXO (_S_IRWXG >> 3) +#define _S_IRWXO (_S_IRWXG >> 3) #define _S_IXOTH (_S_IXGRP >> 3) /* read permission, other */ #define _S_IWOTH (_S_IWGRP >> 3) /* write permission, other */ #define _S_IROTH (_S_IRGRP >> 3) /* execute/search permission, other */ diff --git a/Utilities/cmlibarchive/libarchive/archive_write.c b/Utilities/cmlibarchive/libarchive/archive_write.c index b296069..8997193 100644 --- a/Utilities/cmlibarchive/libarchive/archive_write.c +++ b/Utilities/cmlibarchive/libarchive/archive_write.c @@ -503,8 +503,9 @@ _archive_write_close(struct archive *_a) archive_clear_error(&a->archive); - /* Finish the last entry. */ - if (a->archive.state == ARCHIVE_STATE_DATA) + /* Finish the last entry if a finish callback is specified */ + if (a->archive.state == ARCHIVE_STATE_DATA + && a->format_finish_entry != NULL) r = ((a->format_finish_entry)(a)); /* Finish off the archive. */ @@ -638,6 +639,9 @@ _archive_write_header(struct archive *_a, struct archive_entry *entry) /* Format and write header. */ r2 = ((a->format_write_header)(a, entry)); + if (r2 == ARCHIVE_FAILED) { + return (ARCHIVE_FAILED); + } if (r2 == ARCHIVE_FATAL) { a->archive.state = ARCHIVE_STATE_FATAL; return (ARCHIVE_FATAL); @@ -658,7 +662,8 @@ _archive_write_finish_entry(struct archive *_a) archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC, ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA, "archive_write_finish_entry"); - if (a->archive.state & ARCHIVE_STATE_DATA) + if (a->archive.state & ARCHIVE_STATE_DATA + && a->format_finish_entry != NULL) ret = (a->format_finish_entry)(a); a->archive.state = ARCHIVE_STATE_HEADER; return (ret); @@ -671,8 +676,13 @@ static ssize_t _archive_write_data(struct archive *_a, const void *buff, size_t s) { struct archive_write *a = (struct archive_write *)_a; + const size_t max_write = INT_MAX; + archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC, ARCHIVE_STATE_DATA, "archive_write_data"); + /* In particular, this catches attempts to pass negative values. */ + if (s > max_write) + s = max_write; archive_clear_error(&a->archive); return ((a->format_write_data)(a, buff, s)); } diff --git a/Utilities/cmlibarchive/libarchive/archive_write_add_filter_lrzip.c b/Utilities/cmlibarchive/libarchive/archive_write_add_filter_lrzip.c index 85fdf6a..da1cf5e 100644 --- a/Utilities/cmlibarchive/libarchive/archive_write_add_filter_lrzip.c +++ b/Utilities/cmlibarchive/libarchive/archive_write_add_filter_lrzip.c @@ -44,7 +44,7 @@ __FBSDID("$FreeBSD$"); struct write_lrzip { struct archive_write_program_data *pdata; int compression_level; - enum { lzma = 0, bzip2, gzip, lzo, zpaq } compression; + enum { lzma = 0, bzip2, gzip, lzo, none, zpaq } compression; }; static int archive_write_lrzip_open(struct archive_write_filter *); @@ -107,6 +107,8 @@ archive_write_lrzip_options(struct archive_write_filter *f, const char *key, data->compression = gzip; else if (strcmp(value, "lzo") == 0) data->compression = lzo; + else if (strcmp(value, "none") == 0) + data->compression = none; else if (strcmp(value, "zpaq") == 0) data->compression = zpaq; else @@ -148,6 +150,9 @@ archive_write_lrzip_open(struct archive_write_filter *f) case lzo: archive_strcat(&as, " -l"); break; + case none: + archive_strcat(&as, " -n"); + break; case zpaq: archive_strcat(&as, " -z"); break; diff --git a/Utilities/cmlibarchive/libarchive/archive_write_disk_acl.c b/Utilities/cmlibarchive/libarchive/archive_write_disk_acl.c index 9797203..5cbba54 100644 --- a/Utilities/cmlibarchive/libarchive/archive_write_disk_acl.c +++ b/Utilities/cmlibarchive/libarchive/archive_write_disk_acl.c @@ -43,7 +43,7 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_write_disk.c 201159 2009-12-29 0 #include "archive_acl_private.h" #include "archive_write_disk_private.h" -#if !defined(HAVE_POSIX_ACL) || !defined(ACL_TYPE_NFS4) +#ifndef HAVE_POSIX_ACL /* Default empty function body to satisfy mainline code. */ int archive_write_disk_set_acls(struct archive *a, int fd, const char *name, @@ -79,10 +79,12 @@ archive_write_disk_set_acls(struct archive *a, int fd, const char *name, ret = set_acl(a, fd, name, abstract_acl, ACL_TYPE_DEFAULT, ARCHIVE_ENTRY_ACL_TYPE_DEFAULT, "default"); return (ret); +#ifdef ACL_TYPE_NFS4 } else if (archive_acl_count(abstract_acl, ARCHIVE_ENTRY_ACL_TYPE_NFS4) > 0) { ret = set_acl(a, fd, name, abstract_acl, ACL_TYPE_NFS4, ARCHIVE_ENTRY_ACL_TYPE_NFS4, "nfs4"); return (ret); +#endif } else return ARCHIVE_OK; } @@ -94,6 +96,7 @@ static struct { {ARCHIVE_ENTRY_ACL_EXECUTE, ACL_EXECUTE}, {ARCHIVE_ENTRY_ACL_WRITE, ACL_WRITE}, {ARCHIVE_ENTRY_ACL_READ, ACL_READ}, +#ifdef ACL_TYPE_NFS4 {ARCHIVE_ENTRY_ACL_READ_DATA, ACL_READ_DATA}, {ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, ACL_LIST_DIRECTORY}, {ARCHIVE_ENTRY_ACL_WRITE_DATA, ACL_WRITE_DATA}, @@ -110,8 +113,10 @@ static struct { {ARCHIVE_ENTRY_ACL_WRITE_ACL, ACL_WRITE_ACL}, {ARCHIVE_ENTRY_ACL_WRITE_OWNER, ACL_WRITE_OWNER}, {ARCHIVE_ENTRY_ACL_SYNCHRONIZE, ACL_SYNCHRONIZE} +#endif }; +#ifdef ACL_TYPE_NFS4 static struct { int archive_inherit; int platform_inherit; @@ -121,6 +126,7 @@ static struct { {ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, ACL_ENTRY_NO_PROPAGATE_INHERIT}, {ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, ACL_ENTRY_INHERIT_ONLY} }; +#endif static int set_acl(struct archive *a, int fd, const char *name, @@ -130,7 +136,9 @@ set_acl(struct archive *a, int fd, const char *name, acl_t acl; acl_entry_t acl_entry; acl_permset_t acl_permset; +#ifdef ACL_TYPE_NFS4 acl_flagset_t acl_flagset; +#endif int ret; int ae_type, ae_permset, ae_tag, ae_id; uid_t ae_uid; @@ -171,14 +179,17 @@ set_acl(struct archive *a, int fd, const char *name, case ARCHIVE_ENTRY_ACL_OTHER: acl_set_tag_type(acl_entry, ACL_OTHER); break; +#ifdef ACL_TYPE_NFS4 case ARCHIVE_ENTRY_ACL_EVERYONE: acl_set_tag_type(acl_entry, ACL_EVERYONE); break; +#endif default: /* XXX */ break; } +#ifdef ACL_TYPE_NFS4 switch (ae_type) { case ARCHIVE_ENTRY_ACL_TYPE_ALLOW: acl_set_entry_type_np(acl_entry, ACL_ENTRY_TYPE_ALLOW); @@ -200,6 +211,7 @@ set_acl(struct archive *a, int fd, const char *name, // XXX error handling here. break; } +#endif acl_get_permset(acl_entry, &acl_permset); acl_clear_perms(acl_permset); @@ -210,6 +222,7 @@ set_acl(struct archive *a, int fd, const char *name, acl_perm_map[i].platform_perm); } +#ifdef ACL_TYPE_NFS4 acl_get_flagset_np(acl_entry, &acl_flagset); acl_clear_flags_np(acl_flagset); for (i = 0; i < (int)(sizeof(acl_inherit_map) / sizeof(acl_inherit_map[0])); ++i) { @@ -217,6 +230,7 @@ set_acl(struct archive *a, int fd, const char *name, acl_add_flag_np(acl_flagset, acl_inherit_map[i].platform_inherit); } +#endif } /* Try restoring the ACL through 'fd' if we can. */ diff --git a/Utilities/cmlibarchive/libarchive/archive_write_disk_windows.c b/Utilities/cmlibarchive/libarchive/archive_write_disk_windows.c index 0f0780a..ed62009 100644 --- a/Utilities/cmlibarchive/libarchive/archive_write_disk_windows.c +++ b/Utilities/cmlibarchive/libarchive/archive_write_disk_windows.c @@ -525,7 +525,7 @@ la_GetFunctionKernel32(const char *name) static int set; if (!set) { set = 1; - lib = LoadLibrary("kernel32.dll"); + lib = LoadLibrary(TEXT("kernel32.dll")); } if (lib == NULL) { fprintf(stderr, "Can't load kernel32.dll?!\n"); diff --git a/Utilities/cmlibarchive/libarchive/archive_write_format.3 b/Utilities/cmlibarchive/libarchive/archive_write_format.3 index dad2f7d..39d3006 100644 --- a/Utilities/cmlibarchive/libarchive/archive_write_format.3 +++ b/Utilities/cmlibarchive/libarchive/archive_write_format.3 @@ -24,13 +24,14 @@ .\" .\" $FreeBSD$ .\" -.Dd February 2, 2012 +.Dd February 14, 2013 .Dt ARCHIVE_WRITE_FORMAT 3 .Os .Sh NAME .Nm archive_write_set_format_cpio , .Nm archive_write_set_format_pax , .Nm archive_write_set_format_pax_restricted , +.Nm archive_write_set_format_raw , .Nm archive_write_set_format_shar , .Nm archive_write_set_format_shar_dump , .Nm archive_write_set_format_ustar @@ -46,6 +47,8 @@ Streaming Archive Library (libarchive, -larchive) .Ft int .Fn archive_write_set_format_pax_restricted "struct archive *" .Ft int +.Fn archive_write_set_format_raw "struct archive *" +.Ft int .Fn archive_write_set_format_shar "struct archive *" .Ft int .Fn archive_write_set_format_shar_dump "struct archive *" diff --git a/Utilities/cmlibarchive/libarchive/archive_write_set_format.c b/Utilities/cmlibarchive/libarchive/archive_write_set_format.c index 641d56f..9055753 100644 --- a/Utilities/cmlibarchive/libarchive/archive_write_set_format.c +++ b/Utilities/cmlibarchive/libarchive/archive_write_set_format.c @@ -47,6 +47,7 @@ struct { int code; int (*setter)(struct archive *); } codes[] = { 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 }, + { ARCHIVE_FORMAT_RAW, archive_write_set_format_raw }, { ARCHIVE_FORMAT_SHAR, archive_write_set_format_shar }, { ARCHIVE_FORMAT_SHAR_BASE, archive_write_set_format_shar }, { ARCHIVE_FORMAT_SHAR_DUMP, archive_write_set_format_shar_dump }, @@ -57,7 +58,7 @@ struct { int code; int (*setter)(struct archive *); } codes[] = archive_write_set_format_pax_restricted }, { ARCHIVE_FORMAT_TAR_USTAR, archive_write_set_format_ustar }, { ARCHIVE_FORMAT_XAR, archive_write_set_format_xar }, - { ARCHIVE_FORMAT_ZIP, archive_write_set_format_zip }, + { ARCHIVE_FORMAT_ZIP, archive_write_set_format_zip }, { 0, NULL } }; diff --git a/Utilities/cmlibarchive/libarchive/archive_write_set_format_by_name.c b/Utilities/cmlibarchive/libarchive/archive_write_set_format_by_name.c index af3105e..4f3ce7d 100644 --- a/Utilities/cmlibarchive/libarchive/archive_write_set_format_by_name.c +++ b/Utilities/cmlibarchive/libarchive/archive_write_set_format_by_name.c @@ -63,6 +63,7 @@ struct { const char *name; int (*setter)(struct archive *); } names[] = { "pax", archive_write_set_format_pax }, { "paxr", archive_write_set_format_pax_restricted }, { "posix", archive_write_set_format_pax }, + { "raw", archive_write_set_format_raw }, { "rpax", archive_write_set_format_pax_restricted }, { "shar", archive_write_set_format_shar }, { "shardump", archive_write_set_format_shar_dump }, diff --git a/Utilities/cmlibarchive/libarchive/archive_write_set_format_mtree.c b/Utilities/cmlibarchive/libarchive/archive_write_set_format_mtree.c index 9c0613c..4d343ea 100644 --- a/Utilities/cmlibarchive/libarchive/archive_write_set_format_mtree.c +++ b/Utilities/cmlibarchive/libarchive/archive_write_set_format_mtree.c @@ -128,6 +128,9 @@ struct mtree_entry { unsigned long fflags_clear; dev_t rdevmajor; dev_t rdevminor; + dev_t devmajor; + dev_t devminor; + int64_t ino; }; struct mtree_writer { @@ -210,6 +213,9 @@ struct mtree_writer { #define F_SHA256 0x00800000 /* SHA-256 digest */ #define F_SHA384 0x01000000 /* SHA-384 digest */ #define F_SHA512 0x02000000 /* SHA-512 digest */ +#define F_INO 0x04000000 /* inode number */ +#define F_RESDEV 0x08000000 /* device ID on which the + * entry resides */ /* Options */ int dironly; /* If it is set, ignore all files except @@ -823,8 +829,11 @@ mtree_entry_new(struct archive_write *a, struct archive_entry *entry, archive_entry_fflags(entry, &me->fflags_set, &me->fflags_clear); me->mtime = archive_entry_mtime(entry); me->mtime_nsec = archive_entry_mtime_nsec(entry); - me->rdevmajor = archive_entry_rdevmajor(entry); + me->rdevmajor = archive_entry_rdevmajor(entry); me->rdevminor = archive_entry_rdevminor(entry); + me->devmajor = archive_entry_devmajor(entry); + me->devminor = archive_entry_devminor(entry); + me->ino = archive_entry_ino(entry); me->size = archive_entry_size(entry); if (me->filetype == AE_IFDIR) { me->dir_info = calloc(1, sizeof(*me->dir_info)); @@ -882,7 +891,7 @@ archive_write_mtree_header(struct archive_write *a, mtree->first = 0; archive_strcat(&mtree->buf, "#mtree\n"); if ((mtree->keys & SET_KEYS) == 0) - mtree->output_global_set = 0;/* Disalbed. */ + mtree->output_global_set = 0;/* Disabled. */ } mtree->entry_bytes_remaining = archive_entry_size(entry); @@ -983,6 +992,15 @@ write_mtree_entry(struct archive_write *a, struct mtree_entry *me) if ((keys & F_UID) != 0) archive_string_sprintf(str, " uid=%jd", (intmax_t)me->uid); + if ((keys & F_INO) != 0) + archive_string_sprintf(str, " inode=%jd", (intmax_t)me->ino); + if ((keys & F_RESDEV) != 0) { + archive_string_sprintf(str, + " resdevice=native,%ju,%ju", + (uintmax_t)me->devmajor, + (uintmax_t)me->devminor); + } + switch (me->filetype) { case AE_IFLNK: if ((keys & F_TYPE) != 0) @@ -1117,7 +1135,7 @@ write_mtree_entry_tree(struct archive_write *a) } else { /* Whenever output_global_set is enabled * output global value(/set keywords) - * even if the directory entry is not allowd + * even if the directory entry is not allowed * to be written because the global values * can be used for the children. */ if (mtree->output_global_set) @@ -1296,6 +1314,8 @@ archive_write_mtree_options(struct archive_write *a, const char *key, if (strcmp(key, "indent") == 0) { mtree->indent = (value != NULL)? 1: 0; return (ARCHIVE_OK); + } else if (strcmp(key, "inode") == 0) { + keybit = F_INO; } break; case 'l': @@ -1314,7 +1334,9 @@ archive_write_mtree_options(struct archive_write *a, const char *key, keybit = F_NLINK; break; case 'r': - if (strcmp(key, "ripemd160digest") == 0 || + if (strcmp(key, "resdevice") == 0) { + keybit = F_RESDEV; + } else if (strcmp(key, "ripemd160digest") == 0 || strcmp(key, "rmd160") == 0 || strcmp(key, "rmd160digest") == 0) keybit = F_RMD160; @@ -1855,9 +1877,9 @@ mtree_entry_setup_filenames(struct archive_write *a, struct mtree_entry *file, return (ret); } - /* Make a basename from dirname and slash */ + /* Make a basename from file->parentdir.s and slash */ *slash = '\0'; - file->parentdir.length = slash - dirname; + file->parentdir.length = slash - file->parentdir.s; archive_strcpy(&(file->basename), slash + 1); return (ret); } @@ -2198,6 +2220,9 @@ mtree_entry_exchange_same_entry(struct archive_write *a, struct mtree_entry *np, np->mtime_nsec = file->mtime_nsec; np->rdevmajor = file->rdevmajor; np->rdevminor = file->rdevminor; + np->devmajor = file->devmajor; + np->devminor = file->devminor; + np->ino = file->ino; return (ARCHIVE_WARN); } diff --git a/Utilities/cmlibarchive/libarchive/archive_write_set_format_raw.c b/Utilities/cmlibarchive/libarchive/archive_write_set_format_raw.c new file mode 100644 index 0000000..feff936 --- /dev/null +++ b/Utilities/cmlibarchive/libarchive/archive_write_set_format_raw.c @@ -0,0 +1,125 @@ +/*- + * Copyright (c) 2013 Marek Kubica + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "archive_platform.h" + +#ifdef HAVE_ERRNO_H +#include <errno.h> +#endif + +#include "archive_entry.h" +#include "archive_write_private.h" + +static ssize_t archive_write_raw_data(struct archive_write *, + const void *buff, size_t s); +static int archive_write_raw_free(struct archive_write *); +static int archive_write_raw_header(struct archive_write *, + struct archive_entry *); + +struct raw { + int entries_written; +}; + +/* + * Set output format to 'raw' format. + */ +int +archive_write_set_format_raw(struct archive *_a) +{ + struct archive_write *a = (struct archive_write *)_a; + struct raw *raw; + + archive_check_magic(_a, ARCHIVE_WRITE_MAGIC, + ARCHIVE_STATE_NEW, "archive_write_set_format_raw"); + + /* If someone else was already registered, unregister them. */ + if (a->format_free != NULL) + (a->format_free)(a); + + raw = (struct raw *)calloc(1, sizeof(*raw)); + if (raw == NULL) { + archive_set_error(&a->archive, ENOMEM, "Can't allocate raw data"); + return (ARCHIVE_FATAL); + } + raw->entries_written = 0; + a->format_data = raw; + a->format_name = "raw"; + /* no options exist for this format */ + a->format_options = NULL; + a->format_write_header = archive_write_raw_header; + a->format_write_data = archive_write_raw_data; + a->format_finish_entry = NULL; + /* nothing needs to be done on closing */ + a->format_close = NULL; + a->format_free = archive_write_raw_free; + a->archive.archive_format = ARCHIVE_FORMAT_RAW; + a->archive.archive_format_name = "RAW"; + return (ARCHIVE_OK); +} + +static int +archive_write_raw_header(struct archive_write *a, struct archive_entry *entry) +{ + struct raw *raw = (struct raw *)a->format_data; + + if (archive_entry_filetype(entry) != AE_IFREG) { + archive_set_error(&a->archive, ERANGE, + "Raw format only supports filetype AE_IFREG"); + return (ARCHIVE_FATAL); + } + + + if (raw->entries_written > 0) { + archive_set_error(&a->archive, ERANGE, + "Raw format only supports one entry per archive"); + return (ARCHIVE_FATAL); + } + raw->entries_written++; + + return (ARCHIVE_OK); +} + +static ssize_t +archive_write_raw_data(struct archive_write *a, const void *buff, size_t s) +{ + int ret; + + ret = __archive_write_output(a, buff, s); + if (ret >= 0) + return (s); + else + return (ret); +} + +static int +archive_write_raw_free(struct archive_write *a) +{ + struct raw *raw; + + raw = (struct raw *)a->format_data; + free(raw); + a->format_data = NULL; + return (ARCHIVE_OK); +} diff --git a/Utilities/cmlibarchive/libarchive/archive_write_set_format_shar.c b/Utilities/cmlibarchive/libarchive/archive_write_set_format_shar.c index 9ec15f9..c033fb3 100644 --- a/Utilities/cmlibarchive/libarchive/archive_write_set_format_shar.c +++ b/Utilities/cmlibarchive/libarchive/archive_write_set_format_shar.c @@ -548,6 +548,7 @@ archive_write_shar_finish_entry(struct archive_write *a) archive_strcat(&shar->work, ":"); shar_quote(&shar->work, g, 1); } + archive_strcat(&shar->work, " "); shar_quote(&shar->work, archive_entry_pathname(shar->entry), 1); archive_strcat(&shar->work, "\n"); diff --git a/Utilities/cmlibarchive/libarchive/archive_write_set_format_zip.c b/Utilities/cmlibarchive/libarchive/archive_write_set_format_zip.c index 5a9f114..d856b2a 100644 --- a/Utilities/cmlibarchive/libarchive/archive_write_set_format_zip.c +++ b/Utilities/cmlibarchive/libarchive/archive_write_set_format_zip.c @@ -29,24 +29,6 @@ * Development supported by Google Summer of Code 2008. */ -/* - * The current implementation is very limited: - * - * - No encryption support. - * - No ZIP64 support. - * - No support for splitting and spanning. - * - Only supports regular file and folder entries. - * - * Note that generally data in ZIP files is little-endian encoded, - * with some exceptions. - * - * TODO: Since Libarchive is generally 64bit oriented, but this implementation - * does not yet support sizes exceeding 32bit, it is highly fragile for - * big archives. This should change when ZIP64 is finally implemented, otherwise - * some serious checking has to be done. - * - */ - #include "archive_platform.h" __FBSDID("$FreeBSD: head/lib/libarchive/archive_write_set_format_zip.c 201168 2009-12-29 06:15:32Z kientzle $"); @@ -77,25 +59,80 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_write_set_format_zip.c 201168 20 #include "archive_crc32.h" #endif -#define ZIP_SIGNATURE_LOCAL_FILE_HEADER 0x04034b50 -#define ZIP_SIGNATURE_DATA_DESCRIPTOR 0x08074b50 -#define ZIP_SIGNATURE_FILE_HEADER 0x02014b50 -#define ZIP_SIGNATURE_CENTRAL_DIRECTORY_END 0x06054b50 -#define ZIP_SIGNATURE_EXTRA_TIMESTAMP 0x5455 -#define ZIP_SIGNATURE_EXTRA_NEW_UNIX 0x7875 -#define ZIP_VERSION_EXTRACT 0x0014 /* ZIP version 2.0 is needed. */ -#define ZIP_VERSION_BY 0x0314 /* Made by UNIX, using ZIP version 2.0. */ -#define ZIP_FLAGS 0x08 /* Flagging bit 3 (count from 0) for using data descriptor. */ -#define ZIP_FLAGS_UTF8_NAME (1 << 11) +#define ZIP_ENTRY_FLAG_LENGTH_AT_END (1<<3) +#define ZIP_ENTRY_FLAG_UTF8_NAME (1 << 11) + enum compression { - COMPRESSION_STORE = 0 -#ifdef HAVE_ZLIB_H - , + COMPRESSION_UNSPECIFIED = -1, + COMPRESSION_STORE = 0, COMPRESSION_DEFLATE = 8 +}; + +#ifdef HAVE_ZLIB_H +#define COMPRESSION_DEFAULT COMPRESSION_DEFLATE +#else +#define COMPRESSION_DEFAULT COMPRESSION_STORE +#endif + +struct cd_segment { + struct cd_segment *next; + size_t buff_size; + unsigned char *buff; + unsigned char *p; +}; + +/* Bits used to enable/disable certain experimental features. */ +#define EXPERIMENT_LA 1 +#define EXPERIMENTS_ALL 0xffff + +struct zip { + + int64_t entry_offset; + int64_t entry_compressed_size; + int64_t entry_uncompressed_size; + int64_t entry_compressed_written; + int64_t entry_uncompressed_written; + int64_t entry_uncompressed_limit; + struct archive_entry *entry; + uint32_t entry_crc32; + enum compression entry_compression; + int entry_flags; + int entry_uses_zip64; + int experiments; + + unsigned char *file_header; + size_t file_header_extra_offset; + unsigned long (*crc32func)(unsigned long crc, const void *buff, size_t len); + + struct cd_segment *central_directory; + struct cd_segment *central_directory_last; + size_t central_directory_bytes; + size_t central_directory_entries; + + int64_t written_bytes; /* Overall position in file. */ + + struct archive_string_conv *opt_sconv; + struct archive_string_conv *sconv_default; + enum compression requested_compression; + int init_default_conversion; + +#define ZIP_FLAG_AVOID_ZIP64 1 +#define ZIP_FLAG_FORCE_ZIP64 2 +#define ZIP_FLAG_EXPERIMENT_EL 4 + int flags; + +#ifdef HAVE_ZLIB_H + z_stream stream; + size_t len_buf; + unsigned char *buf; #endif }; +/* Don't call this min or MIN, since those are already defined + on lots of platforms (but not all). */ +#define zipmin(a, b) ((a) > (b) ? (b) : (a)) + static ssize_t archive_write_zip_data(struct archive_write *, const void *buff, size_t s); static int archive_write_zip_close(struct archive_write *); @@ -108,106 +145,58 @@ static int archive_write_zip_options(struct archive_write *, static unsigned int dos_time(const time_t); static size_t path_length(struct archive_entry *); static int write_path(struct archive_entry *, struct archive_write *); +static void copy_path(struct archive_entry *, unsigned char *); +static struct archive_string_conv *get_sconv(struct archive_write *, struct zip *); -#define LOCAL_FILE_HEADER_SIGNATURE 0 -#define LOCAL_FILE_HEADER_VERSION 4 -#define LOCAL_FILE_HEADER_FLAGS 6 -#define LOCAL_FILE_HEADER_COMPRESSION 8 -#define LOCAL_FILE_HEADER_TIMEDATE 10 -#define LOCAL_FILE_HEADER_CRC32 14 -#define LOCAL_FILE_HEADER_COMPRESSED_SIZE 18 -#define LOCAL_FILE_HEADER_UNCOMPRESSED_SIZE 22 -#define LOCAL_FILE_HEADER_FILENAME_LENGTH 26 -#define LOCAL_FILE_HEADER_EXTRA_LENGTH 28 -#define SIZE_LOCAL_FILE_HEADER 30 - -#define FILE_HEADER_SIGNATURE 0 -#define FILE_HEADER_VERSION_BY 4 -#define FILE_HEADER_VERSION_EXTRACT 6 -#define FILE_HEADER_FLAGS 8 -#define FILE_HEADER_COMPRESSION 10 -#define FILE_HEADER_TIMEDATE 12 -#define FILE_HEADER_CRC32 16 -#define FILE_HEADER_COMPRESSED_SIZE 20 -#define FILE_HEADER_UNCOMPRESSED_SIZE 24 -#define FILE_HEADER_FILENAME_LENGTH 28 -#define FILE_HEADER_EXTRA_LENGTH 30 -#define FILE_HEADER_COMMENT_LENGTH 32 -#define FILE_HEADER_DISK_NUMBER 34 -#define FILE_HEADER_ATTRIBUTES_INTERNAL 36 -#define FILE_HEADER_ATTRIBUTES_EXTERNAL 38 -#define FILE_HEADER_OFFSET 42 -#define SIZE_FILE_HEADER 46 - - /* Not mandatory, but recommended by specification. */ -#define DATA_DESCRIPTOR_SIGNATURE 0 -#define DATA_DESCRIPTOR_CRC32 4 -#define DATA_DESCRIPTOR_COMPRESSED_SIZE 8 -#define DATA_DESCRIPTOR_UNCOMPRESSED_SIZE 12 -#define SIZE_DATA_DESCRIPTOR 16 - -#define EXTRA_DATA_LOCAL_TIME_ID 0 -#define EXTRA_DATA_LOCAL_TIME_SIZE 2 -#define EXTRA_DATA_LOCAL_TIME_FLAG 4 -#define EXTRA_DATA_LOCAL_MTIME 5 -#define EXTRA_DATA_LOCAL_ATIME 9 -#define EXTRA_DATA_LOCAL_CTIME 13 -#define EXTRA_DATA_LOCAL_UNIX_ID 17 -#define EXTRA_DATA_LOCAL_UNIX_SIZE 19 -#define EXTRA_DATA_LOCAL_UNIX_VERSION 21 -#define EXTRA_DATA_LOCAL_UNIX_UID_SIZE 22 -#define EXTRA_DATA_LOCAL_UNIX_UID 23 -#define EXTRA_DATA_LOCAL_UNIX_GID_SIZE 27 -#define EXTRA_DATA_LOCAL_UNIX_GID 28 -#define SIZE_EXTRA_DATA_LOCAL 32 - -#define EXTRA_DATA_CENTRAL_TIME_ID 0 -#define EXTRA_DATA_CENTRAL_TIME_SIZE 2 -#define EXTRA_DATA_CENTRAL_TIME_FLAG 4 -#define EXTRA_DATA_CENTRAL_MTIME 5 -#define EXTRA_DATA_CENTRAL_UNIX_ID 9 -#define EXTRA_DATA_CENTRAL_UNIX_SIZE 11 -#define SIZE_EXTRA_DATA_CENTRAL 13 - -#define CENTRAL_DIRECTORY_END_SIGNATURE 0 -#define CENTRAL_DIRECTORY_END_DISK 4 -#define CENTRAL_DIRECTORY_END_START_DISK 6 -#define CENTRAL_DIRECTORY_END_ENTRIES_DISK 8 -#define CENTRAL_DIRECTORY_END_ENTRIES 10 -#define CENTRAL_DIRECTORY_END_SIZE 12 -#define CENTRAL_DIRECTORY_END_OFFSET 16 -#define CENTRAL_DIRECTORY_END_COMMENT_LENGTH 20 -#define SIZE_CENTRAL_DIRECTORY_END 22 - -struct zip_file_header_link { - struct zip_file_header_link *next; - struct archive_entry *entry; - int64_t offset; - unsigned long crc32; - int64_t compressed_size; - enum compression compression; - int flags; -}; +static unsigned char * +cd_alloc(struct zip *zip, size_t length) +{ + unsigned char *p; + + if (zip->central_directory == NULL + || (zip->central_directory_last->p + length + > zip->central_directory_last->buff + zip->central_directory_last->buff_size)) { + struct cd_segment *segment = calloc(1, sizeof(*segment)); + if (segment == NULL) + return NULL; + segment->buff_size = 64 * 1024; + segment->buff = malloc(segment->buff_size); + if (segment->buff == NULL) { + free(segment); + return NULL; + } + segment->p = segment->buff; -struct zip { - uint8_t data_descriptor[SIZE_DATA_DESCRIPTOR]; - struct zip_file_header_link *central_directory; - struct zip_file_header_link *central_directory_end; - int64_t offset; - int64_t written_bytes; - int64_t remaining_data_bytes; - enum compression compression; - int flags; - struct archive_string_conv *opt_sconv; - struct archive_string_conv *sconv_default; - int init_default_conversion; + if (zip->central_directory == NULL) { + zip->central_directory + = zip->central_directory_last + = segment; + } else { + zip->central_directory_last->next = segment; + zip->central_directory_last = segment; + } + } -#ifdef HAVE_ZLIB_H - z_stream stream; - size_t len_buf; - unsigned char *buf; -#endif -}; + p = zip->central_directory_last->p; + zip->central_directory_last->p += length; + zip->central_directory_bytes += length; + return (p); +} + +static unsigned long +real_crc32(unsigned long crc, const void *buff, size_t len) +{ + return crc32(crc, buff, len); +} + +static unsigned long +fake_crc32(unsigned long crc, const void *buff, size_t len) +{ + (void)crc; /* UNUSED */ + (void)buff; /* UNUSED */ + (void)len; /* UNUSED */ + return 0; +} static int archive_write_zip_options(struct archive_write *a, const char *key, @@ -217,24 +206,49 @@ archive_write_zip_options(struct archive_write *a, const char *key, int ret = ARCHIVE_FAILED; if (strcmp(key, "compression") == 0) { + /* + * Set compression to use on all future entries. + * This only affects regular files. + */ if (val == NULL || val[0] == 0) { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "%s: compression option needs a compression name", a->format_name); } else if (strcmp(val, "deflate") == 0) { #ifdef HAVE_ZLIB_H - zip->compression = COMPRESSION_DEFLATE; + zip->requested_compression = COMPRESSION_DEFLATE; ret = ARCHIVE_OK; #else archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "deflate compression not supported"); #endif } else if (strcmp(val, "store") == 0) { - zip->compression = COMPRESSION_STORE; + zip->requested_compression = COMPRESSION_STORE; ret = ARCHIVE_OK; } return (ret); + } else if (strcmp(key, "experimental") == 0) { + if (val == NULL || val[0] == 0) { + zip->flags &= ~ ZIP_FLAG_EXPERIMENT_EL; + } else { + zip->flags |= ZIP_FLAG_EXPERIMENT_EL; + } + return (ARCHIVE_OK); + } else if (strcmp(key, "fakecrc32") == 0) { + /* + * FOR TESTING ONLY: disable CRC calculation to speed up + * certain complex tests. + */ + if (val == NULL || val[0] == 0) { + zip->crc32func = real_crc32; + } else { + zip->crc32func = fake_crc32; + } + return (ARCHIVE_OK); } else if (strcmp(key, "hdrcharset") == 0) { + /* + * Set the character set used in translating filenames. + */ if (val == NULL || val[0] == 0) { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "%s: hdrcharset option needs a character-set name", @@ -248,6 +262,21 @@ archive_write_zip_options(struct archive_write *a, const char *key, ret = ARCHIVE_FATAL; } return (ret); + } else if (strcmp(key, "zip64") == 0) { + /* + * Bias decisions about Zip64: force them to be + * generated in certain cases where they are not + * forbidden or avoid them in certain cases where they + * are not strictly required. + */ + if (val != NULL && *val != '\0') { + zip->flags |= ZIP_FLAG_FORCE_ZIP64; + zip->flags &= ~ZIP_FLAG_AVOID_ZIP64; + } else { + zip->flags &= ~ZIP_FLAG_FORCE_ZIP64; + zip->flags |= ZIP_FLAG_AVOID_ZIP64; + } + return (ARCHIVE_OK); } /* Note: The "warn" return is just to inform the options @@ -261,9 +290,9 @@ archive_write_zip_set_compression_deflate(struct archive *_a) { struct archive_write *a = (struct archive_write *)_a; int ret = ARCHIVE_FAILED; - + archive_check_magic(_a, ARCHIVE_WRITE_MAGIC, - ARCHIVE_STATE_NEW | ARCHIVE_STATE_HEADER, + ARCHIVE_STATE_NEW | ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA, "archive_write_zip_set_compression_deflate"); if (a->archive.archive_format != ARCHIVE_FORMAT_ZIP) { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, @@ -273,11 +302,12 @@ archive_write_zip_set_compression_deflate(struct archive *_a) } else { #ifdef HAVE_ZLIB_H struct zip *zip = a->format_data; - zip->compression = COMPRESSION_DEFLATE; + zip->requested_compression = COMPRESSION_DEFLATE; ret = ARCHIVE_OK; #else archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "deflate compression not supported"); + ret = ARCHIVE_FAILED; #endif } return (ret); @@ -289,9 +319,9 @@ archive_write_zip_set_compression_store(struct archive *_a) struct archive_write *a = (struct archive_write *)_a; struct zip *zip = a->format_data; int ret = ARCHIVE_FAILED; - + archive_check_magic(_a, ARCHIVE_WRITE_MAGIC, - ARCHIVE_STATE_NEW | ARCHIVE_STATE_HEADER, + ARCHIVE_STATE_NEW | ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA, "archive_write_zip_set_compression_deflate"); if (a->archive.archive_format != ARCHIVE_FORMAT_ZIP) { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, @@ -299,7 +329,7 @@ archive_write_zip_set_compression_store(struct archive *_a) " with zip format"); ret = ARCHIVE_FATAL; } else { - zip->compression = COMPRESSION_STORE; + zip->requested_compression = COMPRESSION_STORE; ret = ARCHIVE_OK; } return (ret); @@ -324,14 +354,12 @@ archive_write_set_format_zip(struct archive *_a) "Can't allocate zip data"); return (ARCHIVE_FATAL); } - zip->central_directory = NULL; - zip->central_directory_end = NULL; - zip->offset = 0; - zip->written_bytes = 0; - zip->remaining_data_bytes = 0; + + /* "Unspecified" lets us choose the appropriate compression. */ + zip->requested_compression = COMPRESSION_UNSPECIFIED; + zip->crc32func = real_crc32; #ifdef HAVE_ZLIB_H - zip->compression = COMPRESSION_DEFLATE; zip->len_buf = 65536; zip->buf = malloc(zip->len_buf); if (zip->buf == NULL) { @@ -340,8 +368,6 @@ archive_write_set_format_zip(struct archive *_a) "Can't allocate compression buffer"); return (ARCHIVE_FATAL); } -#else - zip->compression = COMPRESSION_STORE; #endif a->format_data = zip; @@ -355,9 +381,6 @@ archive_write_set_format_zip(struct archive *_a) a->archive.archive_format = ARCHIVE_FORMAT_ZIP; a->archive.archive_format_name = "ZIP"; - archive_le32enc(&zip->data_descriptor[DATA_DESCRIPTOR_SIGNATURE], - ZIP_SIGNATURE_DATA_DESCRIPTOR); - return (ARCHIVE_OK); } @@ -376,17 +399,21 @@ is_all_ascii(const char *p) static int archive_write_zip_header(struct archive_write *a, struct archive_entry *entry) { - struct zip *zip; - uint8_t h[SIZE_LOCAL_FILE_HEADER]; - uint8_t e[SIZE_EXTRA_DATA_LOCAL]; - uint8_t *d; - struct zip_file_header_link *l; - struct archive_string_conv *sconv; + unsigned char local_header[32]; + unsigned char local_extra[128]; + struct zip *zip = a->format_data; + unsigned char *e; + unsigned char *cd_extra; + size_t filename_length; + const char *symlink = NULL; + size_t symlink_size = 0; + struct archive_string_conv *sconv = get_sconv(a, zip); int ret, ret2 = ARCHIVE_OK; int64_t size; mode_t type; + int version_needed = 10; - /* Entries other than a regular file or a folder are skipped. */ + /* Ignore types of entries that we don't support. */ type = archive_entry_filetype(entry); if (type != AE_IFREG && type != AE_IFDIR && type != AE_IFLNK) { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, @@ -394,70 +421,64 @@ archive_write_zip_header(struct archive_write *a, struct archive_entry *entry) return ARCHIVE_FAILED; }; - /* Directory entries should have a size of 0. */ - if (type == AE_IFDIR) + /* If we're not using Zip64, reject large files. */ + if (zip->flags & ZIP_FLAG_AVOID_ZIP64) { + /* Reject entries over 4GB. */ + if (archive_entry_size_is_set(entry) + && (archive_entry_size(entry) > 0xffffffff)) { + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "Files > 4GB require Zip64 extensions"); + return ARCHIVE_FAILED; + } + /* Reject entries if archive is > 4GB. */ + if (zip->written_bytes > 0xffffffff) { + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "Archives > 4GB require Zip64 extensions"); + return ARCHIVE_FAILED; + } + } + + /* Only regular files can have size > 0. */ + if (type != AE_IFREG) archive_entry_set_size(entry, 0); - zip = a->format_data; - /* Setup default conversion. */ - if (zip->opt_sconv == NULL && !zip->init_default_conversion) { - zip->sconv_default = - archive_string_default_conversion_for_write(&(a->archive)); - zip->init_default_conversion = 1; - } - if (zip->flags == 0) { - /* Initialize the general purpose flags. */ - zip->flags = ZIP_FLAGS; - if (zip->opt_sconv != NULL) { - if (strcmp(archive_string_conversion_charset_name( - zip->opt_sconv), "UTF-8") == 0) - zip->flags |= ZIP_FLAGS_UTF8_NAME; -#if HAVE_NL_LANGINFO - } else if (strcmp(nl_langinfo(CODESET), "UTF-8") == 0) { - zip->flags |= ZIP_FLAGS_UTF8_NAME; -#endif - } + /* Reset information from last entry. */ + zip->entry_offset = zip->written_bytes; + zip->entry_uncompressed_limit = INT64_MAX; + zip->entry_compressed_size = 0; + zip->entry_uncompressed_size = 0; + zip->entry_compressed_written = 0; + zip->entry_uncompressed_written = 0; + zip->entry_flags = 0; + zip->entry_uses_zip64 = 0; + zip->entry_crc32 = zip->crc32func(0, NULL, 0); + if (zip->entry != NULL) { + archive_entry_free(zip->entry); + zip->entry = NULL; } - d = zip->data_descriptor; - size = archive_entry_size(entry); - zip->remaining_data_bytes = size; - /* Append archive entry to the central directory data. */ - l = (struct zip_file_header_link *) malloc(sizeof(*l)); - if (l == NULL) { - archive_set_error(&a->archive, ENOMEM, - "Can't allocate zip header data"); - return (ARCHIVE_FATAL); - } #if defined(_WIN32) && !defined(__CYGWIN__) /* Make sure the path separators in pahtname, hardlink and symlink * are all slash '/', not the Windows path separator '\'. */ - l->entry = __la_win_entry_in_posix_pathseparator(entry); - if (l->entry == entry) - l->entry = archive_entry_clone(entry); + zip->entry = __la_win_entry_in_posix_pathseparator(entry); + if (zip->entry == entry) + zip->entry = archive_entry_clone(entry); #else - l->entry = archive_entry_clone(entry); + zip->entry = archive_entry_clone(entry); #endif - if (l->entry == NULL) { + if (zip->entry == NULL) { archive_set_error(&a->archive, ENOMEM, "Can't allocate zip header data"); - free(l); return (ARCHIVE_FATAL); } - l->flags = zip->flags; - if (zip->opt_sconv != NULL) - sconv = zip->opt_sconv; - else - sconv = zip->sconv_default; + if (sconv != NULL) { const char *p; size_t len; if (archive_entry_pathname_l(entry, &p, &len, sconv) != 0) { if (errno == ENOMEM) { - archive_entry_free(l->entry); - free(l); archive_set_error(&a->archive, ENOMEM, "Can't allocate memory for Pathname"); return (ARCHIVE_FATAL); @@ -470,163 +491,283 @@ archive_write_zip_header(struct archive_write *a, struct archive_entry *entry) ret2 = ARCHIVE_WARN; } if (len > 0) - archive_entry_set_pathname(l->entry, p); + archive_entry_set_pathname(zip->entry, p); /* - * Although there is no character-set regulation for Symlink, - * it is suitable to convert a character-set of Symlinke to - * what those of the Pathname has been converted to. + * There is no standard for symlink handling; we convert + * it using the same character-set translation that we use + * for filename. */ if (type == AE_IFLNK) { if (archive_entry_symlink_l(entry, &p, &len, sconv)) { if (errno == ENOMEM) { - archive_entry_free(l->entry); - free(l); archive_set_error(&a->archive, ENOMEM, "Can't allocate memory " " for Symlink"); return (ARCHIVE_FATAL); } - /* - * Even if the strng conversion failed, - * we should not report the error since - * thre is no regulation for. - */ + /* No error if we can't convert. */ } else if (len > 0) - archive_entry_set_symlink(l->entry, p); + archive_entry_set_symlink(zip->entry, p); + } + } + + /* If filename isn't ASCII and we can use UTF-8, set the UTF-8 flag. */ + if (!is_all_ascii(archive_entry_pathname(zip->entry))) { + if (zip->opt_sconv != NULL) { + if (strcmp(archive_string_conversion_charset_name( + zip->opt_sconv), "UTF-8") == 0) + zip->entry_flags |= ZIP_ENTRY_FLAG_UTF8_NAME; +#if HAVE_NL_LANGINFO + } else if (strcmp(nl_langinfo(CODESET), "UTF-8") == 0) { + zip->entry_flags |= ZIP_ENTRY_FLAG_UTF8_NAME; +#endif } } - /* If all characters in a filename are ASCII, Reset UTF-8 Name flag. */ - if ((l->flags & ZIP_FLAGS_UTF8_NAME) != 0 && - is_all_ascii(archive_entry_pathname(l->entry))) - l->flags &= ~ZIP_FLAGS_UTF8_NAME; + filename_length = path_length(zip->entry); - /* Initialize the CRC variable and potentially the local crc32(). */ - l->crc32 = crc32(0, NULL, 0); + /* Determine appropriate compression and size for this entry. */ if (type == AE_IFLNK) { - const char *p = archive_entry_symlink(l->entry); - if (p != NULL) - size = strlen(p); + symlink = archive_entry_symlink(zip->entry); + if (symlink != NULL) + symlink_size = strlen(symlink); else - size = 0; - zip->remaining_data_bytes = 0; - archive_entry_set_size(l->entry, size); - l->compression = COMPRESSION_STORE; - l->compressed_size = size; + symlink_size = 0; + zip->entry_uncompressed_limit = symlink_size; + zip->entry_compressed_size = symlink_size; + zip->entry_uncompressed_size = symlink_size; + zip->entry_crc32 = zip->crc32func(zip->entry_crc32, + (const unsigned char *)symlink, symlink_size); + zip->entry_compression = COMPRESSION_STORE; + version_needed = 20; + } else if (type != AE_IFREG) { + zip->entry_compression = COMPRESSION_STORE; + zip->entry_uncompressed_limit = 0; + size = 0; + version_needed = 20; + } else if (archive_entry_size_is_set(zip->entry)) { + size = archive_entry_size(zip->entry); + zip->entry_uncompressed_limit = size; + zip->entry_compression = zip->requested_compression; + if (zip->entry_compression == COMPRESSION_UNSPECIFIED) { + zip->entry_compression = COMPRESSION_DEFAULT; + } + if (zip->entry_compression == COMPRESSION_STORE) { + zip->entry_compressed_size = size; + zip->entry_uncompressed_size = size; + version_needed = 10; + } else { + zip->entry_uncompressed_size = size; + version_needed = 20; + } + if ((zip->flags & ZIP_FLAG_FORCE_ZIP64) /* User asked. */ + || (zip->entry_uncompressed_size > ARCHIVE_LITERAL_LL(0xffffffff))) { /* Large entry. */ + zip->entry_uses_zip64 = 1; + version_needed = 45; + } + + /* We may know the size, but never the CRC. */ + zip->entry_flags |= ZIP_ENTRY_FLAG_LENGTH_AT_END; } else { - l->compression = zip->compression; - l->compressed_size = 0; + /* Prefer deflate if it's available, because deflate + * has a clear end-of-data marker that makes + * length-at-end more reliable. */ + zip->entry_compression = COMPRESSION_DEFAULT; + zip->entry_flags |= ZIP_ENTRY_FLAG_LENGTH_AT_END; + if ((zip->flags & ZIP_FLAG_AVOID_ZIP64) == 0) { + zip->entry_uses_zip64 = 1; + version_needed = 45; + } else if (zip->entry_compression == COMPRESSION_STORE) { + version_needed = 10; + } else { + version_needed = 20; + } } - l->next = NULL; - if (zip->central_directory == NULL) { - zip->central_directory = l; + + /* Format the local header. */ + memset(local_header, 0, sizeof(local_header)); + memcpy(local_header, "PK\003\004", 4); + archive_le16enc(local_header + 4, version_needed); + archive_le16enc(local_header + 6, zip->entry_flags); + archive_le16enc(local_header + 8, zip->entry_compression); + archive_le32enc(local_header + 10, dos_time(archive_entry_mtime(zip->entry))); + archive_le32enc(local_header + 14, zip->entry_crc32); + if (zip->entry_uses_zip64) { + /* Zip64 data in the local header "must" include both + * compressed and uncompressed sizes AND those fields + * are included only if these are 0xffffffff; + * THEREFORE these must be set this way, even if we + * know one of them is smaller. */ + archive_le32enc(local_header + 18, ARCHIVE_LITERAL_LL(0xffffffff)); + archive_le32enc(local_header + 22, ARCHIVE_LITERAL_LL(0xffffffff)); } else { - zip->central_directory_end->next = l; - } - zip->central_directory_end = l; - - /* Store the offset of this header for later use in central - * directory. */ - l->offset = zip->written_bytes; - - memset(h, 0, sizeof(h)); - archive_le32enc(&h[LOCAL_FILE_HEADER_SIGNATURE], - ZIP_SIGNATURE_LOCAL_FILE_HEADER); - archive_le16enc(&h[LOCAL_FILE_HEADER_VERSION], ZIP_VERSION_EXTRACT); - archive_le16enc(&h[LOCAL_FILE_HEADER_FLAGS], l->flags); - archive_le16enc(&h[LOCAL_FILE_HEADER_COMPRESSION], l->compression); - archive_le32enc(&h[LOCAL_FILE_HEADER_TIMEDATE], - dos_time(archive_entry_mtime(entry))); - archive_le16enc(&h[LOCAL_FILE_HEADER_FILENAME_LENGTH], - (uint16_t)path_length(l->entry)); - - switch (l->compression) { - case COMPRESSION_STORE: - /* Setting compressed and uncompressed sizes even when - * specification says to set to zero when using data - * descriptors. Otherwise the end of the data for an - * entry is rather difficult to find. */ - archive_le32enc(&h[LOCAL_FILE_HEADER_COMPRESSED_SIZE], - (uint32_t)size); - archive_le32enc(&h[LOCAL_FILE_HEADER_UNCOMPRESSED_SIZE], - (uint32_t)size); - break; -#ifdef HAVE_ZLIB_H - case COMPRESSION_DEFLATE: - archive_le32enc(&h[LOCAL_FILE_HEADER_UNCOMPRESSED_SIZE], - (uint32_t)size); + archive_le32enc(local_header + 18, zip->entry_compressed_size); + archive_le32enc(local_header + 22, zip->entry_uncompressed_size); + } + archive_le16enc(local_header + 26, filename_length); + + /* Format as much of central directory file header as we can: */ + zip->file_header = cd_alloc(zip, 46); + /* If (zip->file_header == NULL) XXXX */ + ++zip->central_directory_entries; + memset(zip->file_header, 0, 46); + memcpy(zip->file_header, "PK\001\002", 4); + /* "Made by PKZip 2.0 on Unix." */ + archive_le16enc(zip->file_header + 4, 3 * 256 + version_needed); + archive_le16enc(zip->file_header + 6, version_needed); + archive_le16enc(zip->file_header + 8, zip->entry_flags); + archive_le16enc(zip->file_header + 10, zip->entry_compression); + archive_le32enc(zip->file_header + 12, dos_time(archive_entry_mtime(zip->entry))); + archive_le16enc(zip->file_header + 28, filename_length); + /* Following Info-Zip, store mode in the "external attributes" field. */ + archive_le32enc(zip->file_header + 38, + archive_entry_mode(zip->entry) << 16); + e = cd_alloc(zip, filename_length); + /* If (e == NULL) XXXX */ + copy_path(zip->entry, e); + + /* Format extra data. */ + memset(local_extra, 0, sizeof(local_extra)); + e = local_extra; + + /* First, extra blocks that are the same between + * the local file header and the central directory. + * We format them once and then duplicate them. */ + + /* UT timestamp, length depends on what timestamps are set. */ + memcpy(e, "UT", 2); + archive_le16enc(e + 2, + 1 + + (archive_entry_mtime_is_set(entry) ? 4 : 0) + + (archive_entry_atime_is_set(entry) ? 4 : 0) + + (archive_entry_ctime_is_set(entry) ? 4 : 0)); + e += 4; + *e++ = + (archive_entry_mtime_is_set(entry) ? 1 : 0) + | (archive_entry_atime_is_set(entry) ? 2 : 0) + | (archive_entry_ctime_is_set(entry) ? 4 : 0); + if (archive_entry_mtime_is_set(entry)) { + archive_le32enc(e, (uint32_t)archive_entry_mtime(entry)); + e += 4; + } + if (archive_entry_atime_is_set(entry)) { + archive_le32enc(e, (uint32_t)archive_entry_atime(entry)); + e += 4; + } + if (archive_entry_ctime_is_set(entry)) { + archive_le32enc(e, (uint32_t)archive_entry_ctime(entry)); + e += 4; + } - zip->stream.zalloc = Z_NULL; - zip->stream.zfree = Z_NULL; - zip->stream.opaque = Z_NULL; - zip->stream.next_out = zip->buf; - zip->stream.avail_out = (uInt)zip->len_buf; - if (deflateInit2(&zip->stream, Z_DEFAULT_COMPRESSION, - Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY) != Z_OK) { - archive_set_error(&a->archive, ENOMEM, - "Can't init deflate compressor"); - return (ARCHIVE_FATAL); + /* ux Unix extra data, length 11, version 1 */ + /* TODO: If uid < 64k, use 2 bytes, ditto for gid. */ + memcpy(e, "ux\013\000\001", 5); + e += 5; + *e++ = 4; /* Length of following UID */ + archive_le32enc(e, (uint32_t)archive_entry_uid(entry)); + e += 4; + *e++ = 4; /* Length of following GID */ + archive_le32enc(e, (uint32_t)archive_entry_gid(entry)); + e += 4; + + /* Copy UT and ux into central directory as well. */ + zip->file_header_extra_offset = zip->central_directory_bytes; + cd_extra = cd_alloc(zip, e - local_extra); + memcpy(cd_extra, local_extra, e - local_extra); + + /* + * Following extra blocks vary between local header and + * central directory. These are the local header versions. + * Central directory versions get formatted in + * archive_write_zip_finish_entry() below. + */ + + /* "[Zip64 entry] in the local header MUST include BOTH + * original [uncompressed] and compressed size fields." */ + if (zip->entry_uses_zip64) { + unsigned char *zip64_start = e; + memcpy(e, "\001\000\020\000", 4); + e += 4; + archive_le64enc(e, zip->entry_uncompressed_size); + e += 8; + archive_le64enc(e, zip->entry_compressed_size); + e += 8; + archive_le16enc(zip64_start + 2, e - (zip64_start + 4)); + } + + if (zip->flags & ZIP_FLAG_EXPERIMENT_EL) { + /* Experimental 'el' extension to improve streaming. */ + unsigned char *external_info = e; + int included = 7; + memcpy(e, "el\000\000", 4); // 0x6c65 + 2-byte length + e += 4; + e[0] = included; /* bitmap of included fields */ + e += 1; + if (included & 1) { + archive_le16enc(e, /* "Version created by" */ + 3 * 256 + version_needed); + e += 2; } - break; -#endif + if (included & 2) { + archive_le16enc(e, 0); /* internal file attributes */ + e += 2; + } + if (included & 4) { + archive_le32enc(e, /* external file attributes */ + archive_entry_mode(zip->entry) << 16); + e += 4; + } + if (included & 8) { + // Libarchive does not currently support file comments. + } + archive_le16enc(external_info + 2, e - (external_info + 4)); } - /* Formatting extra data. */ - archive_le16enc(&h[LOCAL_FILE_HEADER_EXTRA_LENGTH], sizeof(e)); - archive_le16enc(&e[EXTRA_DATA_LOCAL_TIME_ID], - ZIP_SIGNATURE_EXTRA_TIMESTAMP); - archive_le16enc(&e[EXTRA_DATA_LOCAL_TIME_SIZE], 1 + 4 * 3); - e[EXTRA_DATA_LOCAL_TIME_FLAG] = 0x07; - archive_le32enc(&e[EXTRA_DATA_LOCAL_MTIME], - (uint32_t)archive_entry_mtime(entry)); - archive_le32enc(&e[EXTRA_DATA_LOCAL_ATIME], - (uint32_t)archive_entry_atime(entry)); - archive_le32enc(&e[EXTRA_DATA_LOCAL_CTIME], - (uint32_t)archive_entry_ctime(entry)); - - archive_le16enc(&e[EXTRA_DATA_LOCAL_UNIX_ID], - ZIP_SIGNATURE_EXTRA_NEW_UNIX); - archive_le16enc(&e[EXTRA_DATA_LOCAL_UNIX_SIZE], 1 + (1 + 4) * 2); - e[EXTRA_DATA_LOCAL_UNIX_VERSION] = 1; - e[EXTRA_DATA_LOCAL_UNIX_UID_SIZE] = 4; - archive_le32enc(&e[EXTRA_DATA_LOCAL_UNIX_UID], - (uint32_t)archive_entry_uid(entry)); - e[EXTRA_DATA_LOCAL_UNIX_GID_SIZE] = 4; - archive_le32enc(&e[EXTRA_DATA_LOCAL_UNIX_GID], - (uint32_t)archive_entry_gid(entry)); - - archive_le32enc(&d[DATA_DESCRIPTOR_UNCOMPRESSED_SIZE], - (uint32_t)size); - - ret = __archive_write_output(a, h, sizeof(h)); + /* Update local header with size of extra data and write it all out: */ + archive_le16enc(local_header + 28, e - local_extra); + + ret = __archive_write_output(a, local_header, 30); if (ret != ARCHIVE_OK) return (ARCHIVE_FATAL); - zip->written_bytes += sizeof(h); + zip->written_bytes += 30; - ret = write_path(l->entry, a); + ret = write_path(zip->entry, a); if (ret <= ARCHIVE_OK) return (ARCHIVE_FATAL); zip->written_bytes += ret; - ret = __archive_write_output(a, e, sizeof(e)); + ret = __archive_write_output(a, local_extra, e - local_extra); if (ret != ARCHIVE_OK) return (ARCHIVE_FATAL); - zip->written_bytes += sizeof(e); - - if (type == AE_IFLNK) { - const unsigned char *p; + zip->written_bytes += e - local_extra; - p = (const unsigned char *)archive_entry_symlink(l->entry); - ret = __archive_write_output(a, p, (size_t)size); + /* For symlinks, write the body now. */ + if (symlink != NULL) { + ret = __archive_write_output(a, symlink, (size_t)symlink_size); if (ret != ARCHIVE_OK) return (ARCHIVE_FATAL); - zip->written_bytes += size; - l->crc32 = crc32(l->crc32, p, (unsigned)size); + zip->entry_compressed_written += symlink_size; + zip->entry_uncompressed_written += symlink_size; + zip->written_bytes += symlink_size; } - if (ret2 != ARCHIVE_OK) - return (ret2); - return (ARCHIVE_OK); +#ifdef HAVE_ZLIB_H + if (zip->entry_compression == COMPRESSION_DEFLATE) { + zip->stream.zalloc = Z_NULL; + zip->stream.zfree = Z_NULL; + zip->stream.opaque = Z_NULL; + zip->stream.next_out = zip->buf; + zip->stream.avail_out = (uInt)zip->len_buf; + if (deflateInit2(&zip->stream, Z_DEFAULT_COMPRESSION, + Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY) != Z_OK) { + archive_set_error(&a->archive, ENOMEM, + "Can't init deflate compressor"); + return (ARCHIVE_FATAL); + } + } +#endif + + return (ret2); } static ssize_t @@ -634,22 +775,21 @@ archive_write_zip_data(struct archive_write *a, const void *buff, size_t s) { int ret; struct zip *zip = a->format_data; - struct zip_file_header_link *l = zip->central_directory_end; - if ((int64_t)s > zip->remaining_data_bytes) - s = (size_t)zip->remaining_data_bytes; + if ((int64_t)s > zip->entry_uncompressed_limit) + s = (size_t)zip->entry_uncompressed_limit; + zip->entry_uncompressed_written += s; if (s == 0) return 0; - switch (l->compression) { + switch (zip->entry_compression) { case COMPRESSION_STORE: ret = __archive_write_output(a, buff, s); - if (ret != ARCHIVE_OK) return (ret); + if (ret != ARCHIVE_OK) + return (ret); zip->written_bytes += s; - zip->remaining_data_bytes -= s; - l->compressed_size += s; - l->crc32 = crc32(l->crc32, buff, (unsigned)s); - return (s); + zip->entry_compressed_written += s; + break; #if HAVE_ZLIB_H case COMPRESSION_DEFLATE: zip->stream.next_in = (unsigned char*)(uintptr_t)buff; @@ -663,16 +803,13 @@ archive_write_zip_data(struct archive_write *a, const void *buff, size_t s) zip->len_buf); if (ret != ARCHIVE_OK) return (ret); - l->compressed_size += zip->len_buf; + zip->entry_compressed_written += zip->len_buf; zip->written_bytes += zip->len_buf; zip->stream.next_out = zip->buf; zip->stream.avail_out = (uInt)zip->len_buf; } } while (zip->stream.avail_in != 0); - zip->remaining_data_bytes -= s; - /* If we have it, use zlib's fast crc32() */ - l->crc32 = crc32(l->crc32, buff, (uInt)s); - return (s); + break; #endif default: @@ -680,153 +817,174 @@ archive_write_zip_data(struct archive_write *a, const void *buff, size_t s) "Invalid ZIP compression type"); return ARCHIVE_FATAL; } + + zip->entry_uncompressed_limit -= s; + zip->entry_crc32 = zip->crc32func(zip->entry_crc32, buff, (unsigned)s); + return (s); + } static int archive_write_zip_finish_entry(struct archive_write *a) { - /* Write the data descripter after file data has been written. */ - int ret; struct zip *zip = a->format_data; - uint8_t *d = zip->data_descriptor; - struct zip_file_header_link *l = zip->central_directory_end; -#if HAVE_ZLIB_H - size_t reminder; -#endif + int ret; - switch(l->compression) { - case COMPRESSION_STORE: - break; #if HAVE_ZLIB_H - case COMPRESSION_DEFLATE: + if (zip->entry_compression == COMPRESSION_DEFLATE) { for (;;) { + size_t remainder; ret = deflate(&zip->stream, Z_FINISH); if (ret == Z_STREAM_ERROR) return (ARCHIVE_FATAL); - reminder = zip->len_buf - zip->stream.avail_out; - ret = __archive_write_output(a, zip->buf, reminder); + remainder = zip->len_buf - zip->stream.avail_out; + ret = __archive_write_output(a, zip->buf, remainder); if (ret != ARCHIVE_OK) return (ret); - l->compressed_size += reminder; - zip->written_bytes += reminder; + zip->entry_compressed_written += remainder; + zip->written_bytes += remainder; zip->stream.next_out = zip->buf; if (zip->stream.avail_out != 0) break; zip->stream.avail_out = (uInt)zip->len_buf; } deflateEnd(&zip->stream); - break; + } #endif + + /* Write trailing data descriptor. */ + if ((zip->entry_flags & ZIP_ENTRY_FLAG_LENGTH_AT_END) != 0) { + char d[24]; + memcpy(d, "PK\007\010", 4); + archive_le32enc(d + 4, zip->entry_crc32); + if (zip->entry_uses_zip64) { + archive_le64enc(d + 8, (uint64_t)zip->entry_compressed_written); + archive_le64enc(d + 16, (uint64_t)zip->entry_uncompressed_written); + ret = __archive_write_output(a, d, 24); + zip->written_bytes += 24; + } else { + archive_le32enc(d + 8, (uint32_t)zip->entry_compressed_written); + archive_le32enc(d + 12, (uint32_t)zip->entry_uncompressed_written); + ret = __archive_write_output(a, d, 16); + zip->written_bytes += 16; + } + if (ret != ARCHIVE_OK) + return (ARCHIVE_FATAL); } - archive_le32enc(&d[DATA_DESCRIPTOR_CRC32], l->crc32); - archive_le32enc(&d[DATA_DESCRIPTOR_COMPRESSED_SIZE], - (uint32_t)l->compressed_size); - ret = __archive_write_output(a, d, SIZE_DATA_DESCRIPTOR); - if (ret != ARCHIVE_OK) - return (ARCHIVE_FATAL); - zip->written_bytes += SIZE_DATA_DESCRIPTOR; + /* Append Zip64 extra data to central directory information. */ + if (zip->entry_compressed_written > ARCHIVE_LITERAL_LL(0xffffffff) + || zip->entry_uncompressed_written > ARCHIVE_LITERAL_LL(0xffffffff) + || zip->entry_offset > ARCHIVE_LITERAL_LL(0xffffffff)) { + unsigned char zip64[32]; + unsigned char *z = zip64, *zd; + memcpy(z, "\001\000\000\000", 4); + z += 4; + if (zip->entry_uncompressed_written >= ARCHIVE_LITERAL_LL(0xffffffff)) { + archive_le64enc(z, zip->entry_uncompressed_written); + z += 8; + } + if (zip->entry_compressed_written >= ARCHIVE_LITERAL_LL(0xffffffff)) { + archive_le64enc(z, zip->entry_compressed_written); + z += 8; + } + if (zip->entry_offset >= ARCHIVE_LITERAL_LL(0xffffffff)) { + archive_le64enc(z, zip->entry_offset); + z += 8; + } + archive_le16enc(zip64 + 2, z - (zip64 + 4)); + zd = cd_alloc(zip, z - zip64); + if (zd == NULL) { + archive_set_error(&a->archive, ENOMEM, + "Can't allocate zip data"); + return (ARCHIVE_FATAL); + } + memcpy(zd, zip64, z - zip64); + /* Zip64 means version needs to be set to at least 4.5 */ + if (archive_le16dec(zip->file_header + 6) < 45) + archive_le16enc(zip->file_header + 6, 45); + } + + /* Fix up central directory file header. */ + archive_le32enc(zip->file_header + 16, zip->entry_crc32); + archive_le32enc(zip->file_header + 20, + zipmin(zip->entry_compressed_written, ARCHIVE_LITERAL_LL(0xffffffff))); + archive_le32enc(zip->file_header + 24, + zipmin(zip->entry_uncompressed_written, ARCHIVE_LITERAL_LL(0xffffffff))); + archive_le16enc(zip->file_header + 30, + zip->central_directory_bytes - zip->file_header_extra_offset); + archive_le32enc(zip->file_header + 42, + zipmin(zip->entry_offset, ARCHIVE_LITERAL_LL(0xffffffff))); + return (ARCHIVE_OK); } static int archive_write_zip_close(struct archive_write *a) { - struct zip *zip; - struct zip_file_header_link *l; - uint8_t h[SIZE_FILE_HEADER]; - uint8_t end[SIZE_CENTRAL_DIRECTORY_END]; - uint8_t e[SIZE_EXTRA_DATA_CENTRAL]; + uint8_t buff[64]; int64_t offset_start, offset_end; - int entries; + struct zip *zip = a->format_data; + struct cd_segment *segment; int ret; - zip = a->format_data; - l = zip->central_directory; - - /* - * Formatting central directory file header fields that are - * fixed for all entries. - * Fields not used (and therefor 0) are: - * - * - comment_length - * - disk_number - * - attributes_internal - */ - memset(h, 0, sizeof(h)); - archive_le32enc(&h[FILE_HEADER_SIGNATURE], ZIP_SIGNATURE_FILE_HEADER); - archive_le16enc(&h[FILE_HEADER_VERSION_BY], ZIP_VERSION_BY); - archive_le16enc(&h[FILE_HEADER_VERSION_EXTRACT], ZIP_VERSION_EXTRACT); - - entries = 0; offset_start = zip->written_bytes; - - /* Formatting individual header fields per entry and - * writing each entry. */ - while (l != NULL) { - archive_le16enc(&h[FILE_HEADER_FLAGS], l->flags); - archive_le16enc(&h[FILE_HEADER_COMPRESSION], l->compression); - archive_le32enc(&h[FILE_HEADER_TIMEDATE], - dos_time(archive_entry_mtime(l->entry))); - archive_le32enc(&h[FILE_HEADER_CRC32], l->crc32); - archive_le32enc(&h[FILE_HEADER_COMPRESSED_SIZE], - (uint32_t)l->compressed_size); - archive_le32enc(&h[FILE_HEADER_UNCOMPRESSED_SIZE], - (uint32_t)archive_entry_size(l->entry)); - archive_le16enc(&h[FILE_HEADER_FILENAME_LENGTH], - (uint16_t)path_length(l->entry)); - archive_le16enc(&h[FILE_HEADER_EXTRA_LENGTH], sizeof(e)); - archive_le16enc(&h[FILE_HEADER_ATTRIBUTES_EXTERNAL+2], - archive_entry_mode(l->entry)); - archive_le32enc(&h[FILE_HEADER_OFFSET], (uint32_t)l->offset); - - /* Formatting extra data. */ - archive_le16enc(&e[EXTRA_DATA_CENTRAL_TIME_ID], - ZIP_SIGNATURE_EXTRA_TIMESTAMP); - archive_le16enc(&e[EXTRA_DATA_CENTRAL_TIME_SIZE], 1 + 4); - e[EXTRA_DATA_CENTRAL_TIME_FLAG] = 0x07; - archive_le32enc(&e[EXTRA_DATA_CENTRAL_MTIME], - (uint32_t)archive_entry_mtime(l->entry)); - archive_le16enc(&e[EXTRA_DATA_CENTRAL_UNIX_ID], - ZIP_SIGNATURE_EXTRA_NEW_UNIX); - archive_le16enc(&e[EXTRA_DATA_CENTRAL_UNIX_SIZE], 0x0000); - - ret = __archive_write_output(a, h, sizeof(h)); + segment = zip->central_directory; + while (segment != NULL) { + ret = __archive_write_output(a, + segment->buff, segment->p - segment->buff); if (ret != ARCHIVE_OK) return (ARCHIVE_FATAL); - zip->written_bytes += sizeof(h); - - ret = write_path(l->entry, a); - if (ret <= ARCHIVE_OK) - return (ARCHIVE_FATAL); - zip->written_bytes += ret; + zip->written_bytes += segment->p - segment->buff; + segment = segment->next; + } + offset_end = zip->written_bytes; - ret = __archive_write_output(a, e, sizeof(e)); - if (ret != ARCHIVE_OK) - return (ARCHIVE_FATAL); - zip->written_bytes += sizeof(e); + /* If central dir info is too large, write Zip64 end-of-cd */ + if (offset_end - offset_start > ARCHIVE_LITERAL_LL(0xffffffff) + || offset_start > ARCHIVE_LITERAL_LL(0xffffffff) + || zip->central_directory_entries > 0xffffUL + || (zip->flags & ZIP_FLAG_FORCE_ZIP64)) { + /* Zip64 end-of-cd record */ + memset(buff, 0, 56); + memcpy(buff, "PK\006\006", 4); + archive_le64enc(buff + 4, 44); + archive_le16enc(buff + 12, 45); + archive_le16enc(buff + 14, 45); + /* This is disk 0 of 0. */ + archive_le64enc(buff + 24, zip->central_directory_entries); + archive_le64enc(buff + 32, zip->central_directory_entries); + archive_le64enc(buff + 40, offset_end - offset_start); + archive_le64enc(buff + 48, offset_start); + ret = __archive_write_output(a, buff, 56); + if (ret != ARCHIVE_OK) + return (ARCHIVE_FATAL); + zip->written_bytes += 56; + + /* Zip64 end-of-cd locator record. */ + memset(buff, 0, 20); + memcpy(buff, "PK\006\007", 4); + archive_le32enc(buff + 4, 0); + archive_le64enc(buff + 8, offset_end); + archive_le32enc(buff + 16, 1); + ret = __archive_write_output(a, buff, 20); + if (ret != ARCHIVE_OK) + return (ARCHIVE_FATAL); + zip->written_bytes += 20; - l = l->next; - entries++; } - offset_end = zip->written_bytes; - /* Formatting end of central directory. */ - memset(end, 0, sizeof(end)); - archive_le32enc(&end[CENTRAL_DIRECTORY_END_SIGNATURE], - ZIP_SIGNATURE_CENTRAL_DIRECTORY_END); - archive_le16enc(&end[CENTRAL_DIRECTORY_END_ENTRIES_DISK], entries); - archive_le16enc(&end[CENTRAL_DIRECTORY_END_ENTRIES], entries); - archive_le32enc(&end[CENTRAL_DIRECTORY_END_SIZE], - (uint32_t)(offset_end - offset_start)); - archive_le32enc(&end[CENTRAL_DIRECTORY_END_OFFSET], - (uint32_t)offset_start); - - /* Writing end of central directory. */ - ret = __archive_write_output(a, end, sizeof(end)); + /* Format and write end of central directory. */ + memset(buff, 0, sizeof(buff)); + memcpy(buff, "PK\005\006", 4); + archive_le16enc(buff + 8, zipmin(0xffffU, zip->central_directory_entries)); + archive_le16enc(buff + 10, zipmin(0xffffU, zip->central_directory_entries)); + archive_le32enc(buff + 12, (uint32_t)zipmin(ARCHIVE_LITERAL_LL(0xffffffff), (offset_end - offset_start))); + archive_le32enc(buff + 16, (uint32_t)zipmin(ARCHIVE_LITERAL_LL(0xffffffff), offset_start)); + ret = __archive_write_output(a, buff, 22); if (ret != ARCHIVE_OK) return (ARCHIVE_FATAL); - zip->written_bytes += sizeof(end); + zip->written_bytes += 22; return (ARCHIVE_OK); } @@ -834,18 +992,21 @@ static int archive_write_zip_free(struct archive_write *a) { struct zip *zip; - struct zip_file_header_link *l; + struct cd_segment *segment; zip = a->format_data; while (zip->central_directory != NULL) { - l = zip->central_directory; - zip->central_directory = l->next; - archive_entry_free(l->entry); - free(l); + segment = zip->central_directory; + zip->central_directory = segment->next; + free(segment->buff); + free(segment); } #ifdef HAVE_ZLIB_H free(zip->buf); #endif + archive_entry_free(zip->entry); + /* TODO: Free opt_sconv, sconv_default */ + free(zip); a->format_data = NULL; return (ARCHIVE_OK); @@ -918,7 +1079,7 @@ write_path(struct archive_entry *entry, struct archive_write *archive) return (ARCHIVE_FATAL); written_bytes += strlen(path); - /* Folders are recognized by a traling slash. */ + /* Folders are recognized by a trailing slash. */ if ((type == AE_IFDIR) & (path[strlen(path) - 1] != '/')) { ret = __archive_write_output(archive, "/", 1); if (ret != ARCHIVE_OK) @@ -928,3 +1089,38 @@ write_path(struct archive_entry *entry, struct archive_write *archive) return ((int)written_bytes); } + +static void +copy_path(struct archive_entry *entry, unsigned char *p) +{ + const char *path; + size_t pathlen; + mode_t type; + + path = archive_entry_pathname(entry); + pathlen = strlen(path); + type = archive_entry_filetype(entry); + + memcpy(p, path, pathlen); + + /* Folders are recognized by a trailing slash. */ + if ((type == AE_IFDIR) & (path[pathlen - 1] != '/')) { + p[pathlen] = '/'; + p[pathlen + 1] = '\0'; + } +} + + +static struct archive_string_conv * +get_sconv(struct archive_write *a, struct zip *zip) +{ + if (zip->opt_sconv != NULL) + return (zip->opt_sconv); + + if (!zip->init_default_conversion) { + zip->sconv_default = + archive_string_default_conversion_for_write(&(a->archive)); + zip->init_default_conversion = 1; + } + return (zip->sconv_default); +} diff --git a/Utilities/cmlibarchive/libarchive/filter_fork_windows.c b/Utilities/cmlibarchive/libarchive/filter_fork_windows.c index fa59cc9..ad271fe 100644 --- a/Utilities/cmlibarchive/libarchive/filter_fork_windows.c +++ b/Utilities/cmlibarchive/libarchive/filter_fork_windows.c @@ -36,7 +36,7 @@ __archive_create_child(const char *cmd, int *child_stdin, int *child_stdout) { HANDLE childStdout[2], childStdin[2],childStderr; SECURITY_ATTRIBUTES secAtts; - STARTUPINFO staInfo; + STARTUPINFOA staInfo; PROCESS_INFORMATION childInfo; struct archive_string cmdline; struct archive_string fullpath; diff --git a/Utilities/cmlibarchive/libarchive/mtree.5 b/Utilities/cmlibarchive/libarchive/mtree.5 index 983fff7..8c45a7d 100644 --- a/Utilities/cmlibarchive/libarchive/mtree.5 +++ b/Utilities/cmlibarchive/libarchive/mtree.5 @@ -28,7 +28,7 @@ .\" From: @(#)mtree.8 8.2 (Berkeley) 12/11/93 .\" $FreeBSD$ .\" -.Dd May 6, 2008 +.Dd September 4, 2013 .Dt MTREE 5 .Os .Sh NAME @@ -134,6 +134,52 @@ The checksum of the file using the default algorithm specified by the .Xr cksum 1 utility. +.It Cm device +The device number for +.Sy block +or +.Sy char +file types. +The value must be one of the following forms: +.Pp +.Bl -tag -width 4n +.It Ar format , Ns Ar major , Ns Ar minor Ns Bo , Ns Ar subunit Bc +A device with +.Ar major , minor +and optional +.Ar subunit +fields. +Their meaning is specified by the operating's system +.Ar format . +See below for valid formats. +.It Ar number +Opaque number (as stored on the file system). +.El +.Pp +The following values for +.Ar format +are recognized: +.Sy native , +.Sy 386bsd , +.Sy 4bsd , +.Sy bsdos , +.Sy freebsd , +.Sy hpux , +.Sy isc , +.Sy linux , +.Sy netbsd , +.Sy osf1 , +.Sy sco , +.Sy solaris , +.Sy sunos , +.Sy svr3 , +.Sy svr4 , +and +.Sy ultrix . +.Pp +See +.Xr mknod 8 +for more details. .It Cm contents The full pathname of a file that holds the contents of this file. .It Cm flags @@ -150,6 +196,8 @@ The file group as a numeric value. The file group as a symbolic name. .It Cm ignore Ignore any file hierarchy below this file. +.It Cm inode +The inode number. .It Cm link The target of the symbolic link when type=link. .It Cm md5 @@ -164,6 +212,16 @@ value. The number of hard links the file is expected to have. .It Cm nochange Make sure this file or directory exists but otherwise ignore all attributes. +.It Cm optional +The file is optional; do not complain about the file if it is not in +the file hierarchy. +.It Cm resdevice +The +.Dq resident +device number of the file, e.g. the ID of the device that +contains the file. +Its format is the same as the one for +.Cm device . .It Cm ripemd160digest The .Tn RIPEMD160 @@ -192,6 +250,24 @@ message digest of the file. .It Cm sha256digest A synonym for .Cm sha256 . +.It Cm sha384 +The +.Tn FIPS +180-2 +.Pq Dq Tn SHA-384 +message digest of the file. +.It Cm sha384digest +A synonym for +.Cm sha384 . +.It Cm sha512 +The +.Tn FIPS +180-2 +.Pq Dq Tn SHA-512 +message digest of the file. +.It Cm sha512digest +A synonym for +.Cm sha512 . .It Cm size The size, in bytes, of the file. .It Cm time diff --git a/cmake_uninstall.cmake.in b/cmake_uninstall.cmake.in index 7cd7fc1..d81f62a 100644 --- a/cmake_uninstall.cmake.in +++ b/cmake_uninstall.cmake.in @@ -3,7 +3,7 @@ if(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") endif() file(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files) -string(REGEX REPLACE "\n" ";" files "${files}") +string(REPLACE "\n" ";" files "${files}") foreach(file ${files}) message(STATUS "Uninstalling \"$ENV{DESTDIR}${file}\"") if(EXISTS "$ENV{DESTDIR}${file}") |