Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package libzypp for openSUSE:Factory checked in at 2025-07-21 19:58:44 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/libzypp (Old) and /work/SRC/openSUSE:Factory/.libzypp.new.8875 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "libzypp" Mon Jul 21 19:58:44 2025 rev:520 rq:1294450 version:17.37.12 Changes: -------- --- /work/SRC/openSUSE:Factory/libzypp/libzypp.changes 2025-07-15 16:42:14.259982221 +0200 +++ /work/SRC/openSUSE:Factory/.libzypp.new.8875/libzypp.changes 2025-07-21 19:58:53.819597973 +0200 @@ -1,0 +2,8 @@ +Thu Jul 17 23:37:54 CEST 2025 - m...@suse.de + +- Allow explicit request to probe an added repo's URL + (bsc#1246466) +- Fix tests with -DISABLE_MEDIABACKEND_TESTS=1 (fixes #661) +- version 17.37.12 (35) + +------------------------------------------------------------------- Old: ---- libzypp-17.37.11.tar.bz2 New: ---- libzypp-17.37.12.tar.bz2 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ libzypp.spec ++++++ --- /var/tmp/diff_new_pack.Gb0FpC/_old 2025-07-21 19:58:54.559628340 +0200 +++ /var/tmp/diff_new_pack.Gb0FpC/_new 2025-07-21 19:58:54.559628340 +0200 @@ -72,7 +72,7 @@ %endif Name: libzypp -Version: 17.37.11 +Version: 17.37.12 Release: 0 License: GPL-2.0-or-later URL: https://github.com/openSUSE/libzypp ++++++ libzypp-17.37.11.tar.bz2 -> libzypp-17.37.12.tar.bz2 ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libzypp-17.37.11/CMakeLists.txt new/libzypp-17.37.12/CMakeLists.txt --- old/libzypp-17.37.11/CMakeLists.txt 2025-07-07 17:40:11.000000000 +0200 +++ new/libzypp-17.37.12/CMakeLists.txt 2025-07-18 22:21:29.000000000 +0200 @@ -221,8 +221,6 @@ check_symbol_exists( xmlCtxtSetErrorHandler "libxml/SAX2.h" XMLCTXTSETERRORHANDLER_FOUND ) IF(${XMLCTXTSETERRORHANDLER_FOUND}) target_compile_definitions( zypp_general_compiler_flags INTERFACE HAVE_LIBXML2_XMLCTXTSETERRORHANDLER ) - ELSE() - message(" WADDAFACGGGG ") ENDIF() cmake_pop_check_state() @@ -357,7 +355,7 @@ FIND_PROGRAM( CPPCHECK cppcheck ) if ( CPPCHECK ) message( "Enabling cppcheck") - set(ZYPP_CXX_CPPCHECK ${CPPCHECK};–std=c++17;--suppress=rethrowNoCurrentException) + set(ZYPP_CXX_CPPCHECK ${CPPCHECK};--std=c++17;--suppress=rethrowNoCurrentException) else ( CPPCHECK ) message(WARNING "cppcheck not found.") endif( CPPCHECK ) @@ -445,9 +443,7 @@ ADD_EXECUTABLE( ${loop_var}_test ${loop_var}_test.cc ) SET(TEST_REQ_LIBS ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY} ) - IF(NOT DISABLE_MEDIABACKEND_TESTS) - LIST( APPEND TEST_REQ_LIBS zypp_test_utils ) - ENDIF() + LIST( APPEND TEST_REQ_LIBS zypp_test_utils ) TARGET_LINK_LIBRARIES( ${loop_var}_test PUBLIC zypp_exe_compiler_flags ) TARGET_LINK_LIBRARIES( ${loop_var}_test PUBLIC ${TEST_REQ_LIBS} ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libzypp-17.37.11/VERSION.cmake new/libzypp-17.37.12/VERSION.cmake --- old/libzypp-17.37.11/VERSION.cmake 2025-07-14 12:09:34.000000000 +0200 +++ new/libzypp-17.37.12/VERSION.cmake 2025-07-17 23:46:27.000000000 +0200 @@ -61,8 +61,8 @@ SET(LIBZYPP_MAJOR "17") SET(LIBZYPP_COMPATMINOR "35") SET(LIBZYPP_MINOR "37") -SET(LIBZYPP_PATCH "11") +SET(LIBZYPP_PATCH "12") # -# LAST RELEASED: 17.37.11 (35) +# LAST RELEASED: 17.37.12 (35) # (The number in parenthesis is LIBZYPP_COMPATMINOR) #======= diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libzypp-17.37.11/package/libzypp.changes new/libzypp-17.37.12/package/libzypp.changes --- old/libzypp-17.37.11/package/libzypp.changes 2025-07-14 12:09:34.000000000 +0200 +++ new/libzypp-17.37.12/package/libzypp.changes 2025-07-17 23:46:27.000000000 +0200 @@ -1,4 +1,12 @@ ------------------------------------------------------------------- +Thu Jul 17 23:37:54 CEST 2025 - m...@suse.de + +- Allow explicit request to probe an added repo's URL + (bsc#1246466) +- Fix tests with -DISABLE_MEDIABACKEND_TESTS=1 (fixes #661) +- version 17.37.12 (35) + +------------------------------------------------------------------- Mon Jul 14 12:06:07 CEST 2025 - m...@suse.de - Add runtime check for a broken rpm-4.18.0 --runpostrans diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libzypp-17.37.11/tests/CMakeLists.txt new/libzypp-17.37.12/tests/CMakeLists.txt --- old/libzypp-17.37.11/tests/CMakeLists.txt 2023-07-19 11:53:07.000000000 +0200 +++ new/libzypp-17.37.12/tests/CMakeLists.txt 2025-07-14 17:50:11.000000000 +0200 @@ -1,9 +1,7 @@ ADD_DEFINITIONS( -DTESTS_SRC_DIR="${CMAKE_CURRENT_SOURCE_DIR}" -DTESTS_BUILD_DIR="${CMAKE_CURRENT_BINARY_DIR}" ) -IF( NOT DISABLE_MEDIABACKEND_TESTS ) ADD_SUBDIRECTORY(lib) -ENDIF() ENABLE_TESTING() INCLUDE_DIRECTORIES( ${LIBZYPP_SOURCE_DIR}/tests/lib ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libzypp-17.37.11/tests/lib/CMakeLists.txt new/libzypp-17.37.12/tests/lib/CMakeLists.txt --- old/libzypp-17.37.11/tests/lib/CMakeLists.txt 2025-07-08 11:38:22.000000000 +0200 +++ new/libzypp-17.37.12/tests/lib/CMakeLists.txt 2025-07-14 17:50:11.000000000 +0200 @@ -1,70 +1,82 @@ -find_program( NGINX nginx ) -find_program( VSFTPD vsftpd ) -find_program( SQUIDPROXY squid ) -find_program( SQUIDPROXY_AUTH basic_ncsa_auth HINTS ${CMAKE_INSTALL_BINDIR} ${CMAKE_INSTALL_SBINDIR} ${CMAKE_INSTALL_LIBEXECDIR} "/usr/libexec" "/usr/lib" PATH_SUFFIXES squid) -find_library( LIBFCGI NAMES fcgi ) -find_library( LIBFCGI++ NAMES fcgi++ ) - -if ( NOT NGINX ) - message( FATAL_ERROR "nginx not found" ) -else() - message ( "Using nginx binary at: ${NGINX}" ) - ADD_DEFINITIONS( -DWEBSRV_BINARY="${NGINX}" ) -endif() - -if ( NOT VSFTPD ) - message( FATAL_ERROR "vsftpd not found" ) -else() - message ( "Using vsftpd binary at: ${VSFTPD}" ) - ADD_DEFINITIONS( -DFTPSRV_BINARY="${VSFTPD}" ) -endif() - -if ( NOT SQUIDPROXY ) - message( FATAL_ERROR "squid not found" ) -else() - message ( "Using squid binary at: ${SQUIDPROXY}" ) - ADD_DEFINITIONS( -DPROXYSRV_BINARY="${SQUIDPROXY}" ) -endif() - -if ( NOT SQUIDPROXY_AUTH ) - message( FATAL_ERROR "basic_ncsa_auth not found" ) -else() - message ( "Using basic_ncsa_auth binary at: ${SQUIDPROXY_AUTH}" ) - ADD_DEFINITIONS( -DPROXYAUTH_BINARY="${SQUIDPROXY_AUTH}" ) -endif() +add_definitions( -DSRCDIR="${CMAKE_CURRENT_SOURCE_DIR}") -if ( NOT LIBFCGI ) - message( FATAL_ERROR "libfcgi not found" ) -else() - message ( "Using libfcgi library at: ${LIBFCGI}" ) -endif() +if( NOT DISABLE_MEDIABACKEND_TESTS ) + find_program( NGINX nginx ) + find_program( VSFTPD vsftpd ) + find_program( SQUIDPROXY squid ) + find_program( SQUIDPROXY_AUTH basic_ncsa_auth HINTS ${CMAKE_INSTALL_BINDIR} ${CMAKE_INSTALL_SBINDIR} ${CMAKE_INSTALL_LIBEXECDIR} "/usr/libexec" "/usr/lib" PATH_SUFFIXES squid) + find_library( LIBFCGI NAMES fcgi ) + find_library( LIBFCGI++ NAMES fcgi++ ) + + if ( NOT NGINX ) + message( FATAL_ERROR "nginx not found" ) + else() + message ( "Using nginx binary at: ${NGINX}" ) + ADD_DEFINITIONS( -DWEBSRV_BINARY="${NGINX}" ) + endif() + + if ( NOT VSFTPD ) + message( FATAL_ERROR "vsftpd not found" ) + else() + message ( "Using vsftpd binary at: ${VSFTPD}" ) + ADD_DEFINITIONS( -DFTPSRV_BINARY="${VSFTPD}" ) + endif() + + if ( NOT SQUIDPROXY ) + message( FATAL_ERROR "squid not found" ) + else() + message ( "Using squid binary at: ${SQUIDPROXY}" ) + ADD_DEFINITIONS( -DPROXYSRV_BINARY="${SQUIDPROXY}" ) + endif() + + if ( NOT SQUIDPROXY_AUTH ) + message( FATAL_ERROR "basic_ncsa_auth not found" ) + else() + message ( "Using basic_ncsa_auth binary at: ${SQUIDPROXY_AUTH}" ) + ADD_DEFINITIONS( -DPROXYAUTH_BINARY="${SQUIDPROXY_AUTH}" ) + endif() + + if ( NOT LIBFCGI ) + message( FATAL_ERROR "libfcgi not found" ) + else() + message ( "Using libfcgi library at: ${LIBFCGI}" ) + endif() + + if ( NOT LIBFCGI++ ) + message( FATAL_ERROR "libfcgi++ not found" ) + else() + message ( "Using libfcgi++ library at: ${LIBFCGI++}" ) + endif() + + set( MEDIA_SOURCES + FtpServer.h + FtpServer.cc + ProxyServer.h + ProxyServer.cc + WebServer.h + WebServer.cc + ) -if ( NOT LIBFCGI++ ) - message( FATAL_ERROR "libfcgi++ not found" ) -else() - message ( "Using libfcgi++ library at: ${LIBFCGI++}" ) endif() -add_definitions( -DSRCDIR="${CMAKE_CURRENT_SOURCE_DIR}") - ADD_LIBRARY(zypp_test_utils STATIC - FtpServer.h - FtpServer.cc - ProxyServer.h - ProxyServer.cc TestSetup.h TestTools.h TestTools.cc - WebServer.h - WebServer.cc + ${MEDIA_SOURCES} ) -# These headers are in different subdirectories depending on the -# distribution -CHECK_INCLUDE_FILE( fastcgi/fcgiapp.h FASTCGI_HEADER_DIR ) -IF ( FASTCGI_HEADER_DIR ) - target_compile_definitions( zypp_test_utils PRIVATE FCGI_IN_SUBDIR=1) -ENDIF ( FASTCGI_HEADER_DIR ) - target_link_libraries( zypp_test_utils PRIVATE zypp_lib_compiler_flags ) -TARGET_LINK_LIBRARIES( zypp_test_utils PUBLIC ${LIBFCGI} ${LIBFCGI++} pthread ) + +if( NOT DISABLE_MEDIABACKEND_TESTS ) + + # These headers are in different subdirectories depending on the + # distribution + CHECK_INCLUDE_FILE( fastcgi/fcgiapp.h FASTCGI_HEADER_DIR ) + IF ( FASTCGI_HEADER_DIR ) + target_compile_definitions( zypp_test_utils PRIVATE FCGI_IN_SUBDIR=1) + ENDIF ( FASTCGI_HEADER_DIR ) + + TARGET_LINK_LIBRARIES( zypp_test_utils PUBLIC ${LIBFCGI} ${LIBFCGI++} pthread ) +endif() + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libzypp-17.37.11/tests/media/MediaCurl_test.cc new/libzypp-17.37.12/tests/media/MediaCurl_test.cc --- old/libzypp-17.37.11/tests/media/MediaCurl_test.cc 2025-07-07 17:40:11.000000000 +0200 +++ new/libzypp-17.37.12/tests/media/MediaCurl_test.cc 2025-07-18 22:21:30.000000000 +0200 @@ -78,6 +78,55 @@ BOOST_REQUIRE_EQUAL( primaryRequests, 1 ); } +BOOST_DATA_TEST_CASE( base_provide_zck_no_hdrsize, bdata::make( withSSL ) * bdata::make( backend ), withSSL, backend ) +{ + + int primaryRequests = 0; + + zypp::Pathname testRoot = zypp::Pathname(TESTS_SRC_DIR)/"zyppng/data/downloader"; + WebServer web( testRoot.c_str(), 10001, withSSL ); + BOOST_REQUIRE( web.start() ); + + web.addRequestHandler("primary", [ & ]( WebServer::Request &req ){ + primaryRequests++; + req.rout << "Location: /primary.xml.zck\r\n\r\n"; + return; + }); + + zypp::media::MediaManager mm; + zypp::media::MediaAccessId id; + + zypp::Url mediaUrl = web.url(); + mediaUrl.setQueryParam( "mediahandler", backend ); + + if( withSSL ) { + mediaUrl.setQueryParam("ssl_capath", web.caPath().asString() ); + } + + BOOST_CHECK_NO_THROW( id = mm.open( mediaUrl ) ); + BOOST_CHECK_NO_THROW( mm.attach(id) ); + zypp_defer { + mm.releaseAll (); + mm.close (id); + }; + + zypp::OnMediaLocation loc("/handler/primary"); + loc.setDeltafile( testRoot/"primary-deltatemplate.xml.zck" ); + loc.setDownloadSize( makeBytes(274638) ); + loc.setHeaderChecksum( zypp::CheckSum( zypp::Digest::sha256(), "90a1a1b99ba3b6c8ae9f14b0c8b8c43141c69ec3388bfa3b9915fbeea03926b7") ); + + BOOST_CHECK_NO_THROW( mm.provideFile( id, loc ) ); + + // if zck is enabled, we have 2 requests, otherwise its just a normal provide +#ifdef ENABLE_ZCHUNK_COMPRESSION + if ( backend == "curl2" ) + BOOST_REQUIRE_EQUAL( primaryRequests, 3 ); // lead + header + chunks + else +#endif + BOOST_REQUIRE_EQUAL( primaryRequests, 1 ); +} + + // case request with filesize not matching BOOST_DATA_TEST_CASE( base_provide_wrong_filesize, bdata::make( withSSL ) * bdata::make( backend ), withSSL, backend ) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libzypp-17.37.11/tools/zypp-media-http/downloader/downloader.cc new/libzypp-17.37.12/tools/zypp-media-http/downloader/downloader.cc --- old/libzypp-17.37.11/tools/zypp-media-http/downloader/downloader.cc 2025-02-24 14:59:49.000000000 +0100 +++ new/libzypp-17.37.12/tools/zypp-media-http/downloader/downloader.cc 2025-07-18 22:21:30.000000000 +0200 @@ -101,7 +101,7 @@ bool DownloadPrivateBase::hasZckInfo() const { if ( zypp::indeterminate(_specHasZckInfo) ) - _specHasZckInfo = ( _spec.headerSize() > 0 && ZckHelper::isZchunkFile( _spec.deltaFile() ) ); + _specHasZckInfo = ( _spec.headerSize() > 0 && ZckLoader::isZchunkFile( _spec.deltaFile() ) ); return bool(_specHasZckInfo); } #endif diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libzypp-17.37.11/tools/zypp-media-http/downloader/private/downloaderstates/initial_p.cc new/libzypp-17.37.12/tools/zypp-media-http/downloader/private/downloaderstates/initial_p.cc --- old/libzypp-17.37.11/tools/zypp-media-http/downloader/private/downloaderstates/initial_p.cc 2025-02-24 14:59:49.000000000 +0100 +++ new/libzypp-17.37.12/tools/zypp-media-http/downloader/private/downloaderstates/initial_p.cc 2025-07-18 22:21:30.000000000 +0200 @@ -33,7 +33,7 @@ } #if ENABLE_ZCHUNK_COMPRESSION - bool deltaZck = ZckHelper::isZchunkFile( spec.deltaFile() ); + bool deltaZck = ZckLoader::isZchunkFile( spec.deltaFile() ); #endif if ( spec.metalinkEnabled() ) { #if ENABLE_ZCHUNK_COMPRESSION diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libzypp-17.37.11/tools/zypp-media-http/downloader/private/downloaderstates/preparemulti_p.cc new/libzypp-17.37.12/tools/zypp-media-http/downloader/private/downloaderstates/preparemulti_p.cc --- old/libzypp-17.37.11/tools/zypp-media-http/downloader/private/downloaderstates/preparemulti_p.cc 2025-02-24 14:59:49.000000000 +0100 +++ new/libzypp-17.37.12/tools/zypp-media-http/downloader/private/downloaderstates/preparemulti_p.cc 2025-07-18 22:21:30.000000000 +0200 @@ -39,7 +39,7 @@ const auto &url = spec.url(); const auto &targetPath = spec.targetPath(); #if ENABLE_ZCHUNK_COMPRESSION - _haveZckData = (ZckHelper::isZchunkFile( spec.deltaFile() ) && spec.headerSize() > 0); + _haveZckData = (ZckLoader::isZchunkFile( spec.deltaFile() ) && spec.headerSize() > 0); MIL << " Upgrading request for URL: "<< url << " to multipart download , which zckunk=" << _haveZckData << std::endl; #else MIL << " Upgrading request for URL: "<< url << " to multipart download , which zckunk=false" << std::endl; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libzypp-17.37.11/tools/zypp-media-http/downloader/private/downloaderstates/zck_p.cc new/libzypp-17.37.12/tools/zypp-media-http/downloader/private/downloaderstates/zck_p.cc --- old/libzypp-17.37.11/tools/zypp-media-http/downloader/private/downloaderstates/zck_p.cc 2025-02-24 14:59:49.000000000 +0100 +++ new/libzypp-17.37.12/tools/zypp-media-http/downloader/private/downloaderstates/zck_p.cc 2025-07-18 22:21:30.000000000 +0200 @@ -71,7 +71,7 @@ void DLZckHeadState::gotFinished() { - if ( ZckHelper::isZchunkFile( stateMachine()._spec.targetPath() ) ) + if ( ZckLoader::isZchunkFile( stateMachine()._spec.targetPath() ) ) return BasicDownloaderStateBase::gotFinished(); failed ( "Downloaded header is not a zchunk header"); } @@ -101,21 +101,21 @@ // @TODO get this from zchunk file? _fileSize = spec.expectedFileSize(); - auto prepareRes = ZckHelper::prepareZck ( spec.deltaFile (), spec.targetPath (), _fileSize ); + auto prepareRes = ZckLoader::prepareZck ( spec.deltaFile (), spec.targetPath (), _fileSize ); switch( prepareRes._code ) { - case ZckHelper::PrepareResult::Error: { + case ZckLoader::PrepareResult::Error: { return setFailed ( std::move(prepareRes._message) ); } - case ZckHelper::PrepareResult::ExceedsMaxLen: { + case ZckLoader::PrepareResult::ExceedsMaxLen: { return setFailed( NetworkRequestErrorPrivate::customError( NetworkRequestError::ExceededMaxLen, std::move(prepareRes._message) ) ); } - case ZckHelper::PrepareResult::NothingToDo: { + case ZckLoader::PrepareResult::NothingToDo: { return setFinished(); } - case ZckHelper::PrepareResult::Success: + case ZckLoader::PrepareResult::Success: // handle down below break; } @@ -137,7 +137,7 @@ _preferredChunkSize = sm._spec.preferredChunkSize(); } - std::for_each( prepareRes._blocks.begin (), prepareRes._blocks.end(), [&]( const ZckHelper::Block &block ) { + std::for_each( prepareRes._blocks.begin (), prepareRes._blocks.end(), [&]( const ZckLoader::Block &block ) { _ranges.push_back ( Block{ block } ); }); @@ -160,7 +160,7 @@ const auto &spec = stateMachine()._spec; std::string err; - if ( !ZckHelper::validateZckFile ( spec.targetPath(), err ) ) { + if ( !ZckLoader::validateZckFile ( spec.targetPath(), err ) ) { return setFailed ( std::move(err) ); } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libzypp-17.37.11/zypp/RepoManager.cc new/libzypp-17.37.12/zypp/RepoManager.cc --- old/libzypp-17.37.11/zypp/RepoManager.cc 2025-07-04 16:20:12.000000000 +0200 +++ new/libzypp-17.37.12/zypp/RepoManager.cc 2025-07-17 19:50:16.000000000 +0200 @@ -178,11 +178,11 @@ repo::RepoType RepoManager::probe( const Url & url ) const { return _pimpl->ngMgr().probe( {url} ).unwrap(); } - void RepoManager::addRepository( const RepoInfo &info, const ProgressData::ReceiverFnc & progressrcv ) + void RepoManager::addRepository( const RepoInfo &info, const TriBool & forcedProbe, const ProgressData::ReceiverFnc & progressrcv ) { callback::SendReport<ProgressReport> report; auto adapt = zyppng::ProgressObserverAdaptor( progressrcv, report ); - RepoInfo updatedRepo = _pimpl->ngMgr().addRepository( info, adapt.observer() ).unwrap(); + RepoInfo updatedRepo = _pimpl->ngMgr().addRepository( info, adapt.observer(), forcedProbe ).unwrap(); // We should fix the API as we must inject those paths // into the repoinfo in order to keep it usable. @@ -192,6 +192,9 @@ oinfo.setPackagesPath( zyppng::packagescache_path_for_repoinfo( _pimpl->ngMgr().options(), updatedRepo ).unwrap() ); } + void RepoManager::addRepository( const RepoInfo &info, const ProgressData::ReceiverFnc & progressrcv ) + { addRepository( info, indeterminate, progressrcv ); } + void RepoManager::addRepositories( const Url &url, const ProgressData::ReceiverFnc & progressrcv ) { return _pimpl->ngMgr().addRepositories( url, nullptr ).unwrap(); } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libzypp-17.37.11/zypp/RepoManager.h new/libzypp-17.37.12/zypp/RepoManager.h --- old/libzypp-17.37.11/zypp/RepoManager.h 2025-06-18 11:57:31.000000000 +0200 +++ new/libzypp-17.37.12/zypp/RepoManager.h 2025-07-17 19:50:16.000000000 +0200 @@ -31,6 +31,7 @@ #include <zypp/RepoManagerOptions.h> #include <utility> #include <zypp-core/ui/ProgressData> +#include <zypp-core/TriBool.h> /////////////////////////////////////////////////////////////////// namespace zypp @@ -380,7 +381,9 @@ */ void addRepository( const RepoInfo &info, const ProgressData::ReceiverFnc & progressrcv = ProgressData::ReceiverFnc() ); - + /** \overload Explicitly request probing or no probing. */ + void addRepository( const RepoInfo &info, const TriBool & forcedProbe, + const ProgressData::ReceiverFnc & progressrcv = ProgressData::ReceiverFnc() ); /** * \short Adds repositores from a repo file to the list of known repositories. * \param url Url of the repo file. The URL is subject to repo variable expansion. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libzypp-17.37.11/zypp/media/MediaCurl2.cc new/libzypp-17.37.12/zypp/media/MediaCurl2.cc --- old/libzypp-17.37.11/zypp/media/MediaCurl2.cc 2025-06-18 11:57:31.000000000 +0200 +++ new/libzypp-17.37.12/zypp/media/MediaCurl2.cc 2025-07-18 22:21:30.000000000 +0200 @@ -342,65 +342,60 @@ // HERE add zchunk logic if required if ( !srcFile.deltafile().empty() - && zyppng::ZckHelper::isZchunkFile (srcFile.deltafile ()) - && srcFile.headerSize () > 0 ) { + && zyppng::ZckLoader::isZchunkFile (srcFile.deltafile ()) ) { - // first fetch the zck header - std::optional<zypp::Digest> digest; - UByteArray sum; - - const auto &headerSum = srcFile.headerChecksum(); - if ( !headerSum.empty () ) { - digest = zypp::Digest(); - if ( !digest->create( headerSum.type() ) ) { - ERR << "Unknown header checksum type " << headerSum.type() << std::endl; - return false; - } - sum = zypp::Digest::hexStringToUByteArray( headerSum.checksum() ); - } + zyppng::Ref<zyppng::ZckLoader> zckHelper = std::make_shared<zyppng::ZckLoader>(); - reqData._req->addRequestRange( 0, srcFile.headerSize(), std::move(digest), sum ); - executeRequest ( reqData, nullptr ); + const auto &fetchChunks = [&]( const std::vector<zyppng::ZckLoader::Block> &blocks ){ - reqData._req->resetRequestRanges(); - - auto res = zyppng::ZckHelper::prepareZck( srcFile.deltafile(), target, srcFile.downloadSize() ); - switch(res._code) { - case zyppng::ZckHelper::PrepareResult::Error: { - ERR << "Failed to setup zchunk because of: " << res._message << std::endl; - return false; - } - case zyppng::ZckHelper::PrepareResult::NothingToDo: - return true; // already done - case zyppng::ZckHelper::PrepareResult::ExceedsMaxLen: - ZYPP_THROW( MediaFileSizeExceededException( reqData._req->url(), srcFile.downloadSize(), res._message )); - case zyppng::ZckHelper::PrepareResult::Success: - break; - } + reqData._req->resetRequestRanges(); - for ( const auto &block : res._blocks ) { - if ( block._checksum.size() && block._chksumtype.size() ) { - std::optional<zypp::Digest> dig = zypp::Digest(); - if ( !dig->create( block._chksumtype ) ) { - WAR_MEDIA << "Trying to create Digest with chksum type " << block._chksumtype << " failed " << std::endl; - return false; + for ( const auto &block : blocks ) { + if ( block._checksum.size() && block._chksumtype.size() ) { + std::optional<zypp::Digest> dig = zypp::Digest(); + if ( !dig->create( block._chksumtype ) ) { + WAR_MEDIA << "Trying to create Digest with chksum type " << block._chksumtype << " failed " << std::endl; + zckHelper->setFailed( str::Str() << "Trying to create Digest with chksum type " << block._chksumtype << " failed " ); + return; + } + + if ( zypp::env::ZYPP_MEDIA_CURL_DEBUG() > 3 ) + DBG_MEDIA << "Starting block " << block._start << " with checksum " << zypp::Digest::digestVectorToString( block._checksum ) << "." << std::endl; + reqData._req->addRequestRange( block._start, block._len, std::move(dig), block._checksum, {}, block._relevantDigestLen, block._chksumPad ); + } else { + if ( zypp::env::ZYPP_MEDIA_CURL_DEBUG() > 3 ) + DBG_MEDIA << "Starting block " << block._start << " without checksum!" << std::endl; + reqData._req->addRequestRange( block._start, block._len ); } + }; - if ( zypp::env::ZYPP_MEDIA_CURL_DEBUG() > 3 ) - DBG_MEDIA << "Starting block " << block._start << " with checksum " << zypp::Digest::digestVectorToString( block._checksum ) << "." << std::endl; - reqData._req->addRequestRange( block._start, block._len, std::move(dig), block._checksum, {}, block._relevantDigestLen, block._chksumPad ); - } + executeRequest ( reqData, &report ); + zckHelper->cont().unwrap(); }; - executeRequest ( reqData, &report ); - //we might have the file ready - std::string err; - if ( !zyppng::ZckHelper::validateZckFile( target, err) ) { - ERR << "ZCK failed with error: " << err << std::endl; - return false; + zyppng::ZckLoader::PrepareResult res; + const auto &fin = [&]( zyppng::ZckLoader::PrepareResult result ){ + res = std::move(result); + }; + + const auto &hdrSize = srcFile.headerSize(); + const auto &dSize = srcFile.downloadSize(); + zckHelper->connectFunc( &zyppng::ZckLoader::sigBlocksRequired, fetchChunks ); + zckHelper->connectFunc( &zyppng::ZckLoader::sigFinished, fin ); + zckHelper->buildZchunkFile( target, srcFile.deltafile(), dSize ? dSize : std::optional<zypp::ByteCount>{}, hdrSize ? hdrSize : std::optional<zypp::ByteCount>{} ).unwrap(); + + switch(res._code) { + case zyppng::ZckLoader::PrepareResult::Error: { + ERR << "Failed to setup zchunk because of: " << res._message << std::endl; + return false; + } + case zyppng::ZckLoader::PrepareResult::ExceedsMaxLen: + ZYPP_THROW( MediaFileSizeExceededException( reqData._req->url(), srcFile.downloadSize(), res._message )); + case zyppng::ZckLoader::PrepareResult::Success: + case zyppng::ZckLoader::PrepareResult::NothingToDo: + return true; //done } - return true; } #endif return false; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libzypp-17.37.11/zypp/misc/YamlTestcaseHelpers.h new/libzypp-17.37.12/zypp/misc/YamlTestcaseHelpers.h --- old/libzypp-17.37.11/zypp/misc/YamlTestcaseHelpers.h 2025-01-09 16:00:09.000000000 +0100 +++ new/libzypp-17.37.12/zypp/misc/YamlTestcaseHelpers.h 2025-07-18 22:21:30.000000000 +0200 @@ -29,7 +29,7 @@ for ( YAML::const_iterator it = setup.begin(); it != setup.end(); it++ ) { const std::string &key = it->first.as<std::string>(); - const auto &data = it->second; + const auto &data = (*it).second; MIL << "Found key " << key << std::endl; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libzypp-17.37.11/zypp/ng/repo/workflows/repomanagerwf.cc new/libzypp-17.37.12/zypp/ng/repo/workflows/repomanagerwf.cc --- old/libzypp-17.37.11/zypp/ng/repo/workflows/repomanagerwf.cc 2025-06-18 11:57:31.000000000 +0200 +++ new/libzypp-17.37.12/zypp/ng/repo/workflows/repomanagerwf.cc 2025-07-17 19:50:16.000000000 +0200 @@ -888,8 +888,9 @@ ZYPP_ENABLE_LOGIC_BASE(Executor, OpType); - AddRepoLogic( RepoManagerPtrType &&repoMgrRef, RepoInfo &&info, ProgressObserverRef &&myProgress ) + AddRepoLogic( RepoManagerPtrType &&repoMgrRef, RepoInfo &&info, ProgressObserverRef &&myProgress, const zypp::TriBool & forcedProbe ) : _repoMgrRef( std::move(repoMgrRef) ) + , _doProbeUrl( zypp::indeterminate(forcedProbe) ? _repoMgrRef->options().probe : bool(forcedProbe) ) , _info( std::move(info) ) , _myProgress ( std::move(myProgress) ) {} @@ -908,7 +909,7 @@ return makeReadyResult( expected<RepoInfo>::error( ZYPP_EXCPT_PTR(zypp::repo::RepoAlreadyExistsException(_info)) ) ); // check the first url for now - if ( _repoMgrRef->options().probe ) + if ( _doProbeUrl ) { DBG << "unknown repository type, probing" << std::endl; return assert_urls(_info) @@ -941,19 +942,20 @@ } RepoManagerPtrType _repoMgrRef; + bool _doProbeUrl; ///< RepoManagerOptions::probe opt. overwritten in by ctor arg \a forcedProbe RepoInfo _info; ProgressObserverRef _myProgress; }; }; - AsyncOpRef<expected<RepoInfo> > addRepository( AsyncRepoManagerRef mgr, RepoInfo info, ProgressObserverRef myProgress ) + AsyncOpRef<expected<RepoInfo> > addRepository( AsyncRepoManagerRef mgr, RepoInfo info, ProgressObserverRef myProgress, const zypp::TriBool & forcedProbe ) { - return SimpleExecutor<AddRepoLogic, AsyncOp<expected<RepoInfo>>>::run( std::move(mgr), std::move(info), std::move(myProgress) ); + return SimpleExecutor<AddRepoLogic, AsyncOp<expected<RepoInfo>>>::run( std::move(mgr), std::move(info), std::move(myProgress), forcedProbe ); } - expected<RepoInfo> addRepository( SyncRepoManagerRef mgr, const RepoInfo &info, ProgressObserverRef myProgress ) + expected<RepoInfo> addRepository( SyncRepoManagerRef mgr, const RepoInfo &info, ProgressObserverRef myProgress, const zypp::TriBool & forcedProbe ) { - return SimpleExecutor<AddRepoLogic, SyncOp<expected<RepoInfo>>>::run( std::move(mgr), RepoInfo(info), std::move(myProgress) ); + return SimpleExecutor<AddRepoLogic, SyncOp<expected<RepoInfo>>>::run( std::move(mgr), RepoInfo(info), std::move(myProgress), forcedProbe ); } namespace { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libzypp-17.37.11/zypp/ng/repo/workflows/repomanagerwf.h new/libzypp-17.37.12/zypp/ng/repo/workflows/repomanagerwf.h --- old/libzypp-17.37.11/zypp/ng/repo/workflows/repomanagerwf.h 2025-06-18 11:57:31.000000000 +0200 +++ new/libzypp-17.37.12/zypp/ng/repo/workflows/repomanagerwf.h 2025-07-17 19:50:16.000000000 +0200 @@ -56,8 +56,8 @@ AsyncOpRef<expected<repo::AsyncRefreshContextRef> > buildCache( repo::AsyncRefreshContextRef refCtx, zypp::RepoManagerFlags::CacheBuildPolicy policy, ProgressObserverRef progressObserver = nullptr ); expected<repo::SyncRefreshContextRef> buildCache( repo::SyncRefreshContextRef refCtx, zypp::RepoManagerFlags::CacheBuildPolicy policy, ProgressObserverRef progressObserver = nullptr ); - AsyncOpRef<expected<RepoInfo>> addRepository( AsyncRepoManagerRef mgr, RepoInfo info, ProgressObserverRef myProgress = nullptr ); - expected<RepoInfo> addRepository( SyncRepoManagerRef mgr, const RepoInfo &info, ProgressObserverRef myProgress = nullptr ); + AsyncOpRef<expected<RepoInfo>> addRepository( AsyncRepoManagerRef mgr, RepoInfo info, ProgressObserverRef myProgress = nullptr, const zypp::TriBool & forcedProbe = zypp::indeterminate ); + expected<RepoInfo> addRepository( SyncRepoManagerRef mgr, const RepoInfo &info, ProgressObserverRef myProgress = nullptr, const zypp::TriBool & forcedProbe = zypp::indeterminate ); AsyncOpRef<expected<void>> addRepositories( AsyncRepoManagerRef mgr, zypp::Url url, ProgressObserverRef myProgress = nullptr ); expected<void> addRepositories( SyncRepoManagerRef mgr, zypp::Url url, ProgressObserverRef myProgress = nullptr ); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libzypp-17.37.11/zypp/ng/repomanager.cc new/libzypp-17.37.12/zypp/ng/repomanager.cc --- old/libzypp-17.37.11/zypp/ng/repomanager.cc 2025-06-18 11:57:31.000000000 +0200 +++ new/libzypp-17.37.12/zypp/ng/repomanager.cc 2025-07-17 19:50:16.000000000 +0200 @@ -991,9 +991,9 @@ } template<typename ZyppContextRefType> - expected<RepoInfo> RepoManager<ZyppContextRefType>::addRepository(const RepoInfo &info, ProgressObserverRef myProgress) + expected<RepoInfo> RepoManager<ZyppContextRefType>::addRepository(const RepoInfo &info, ProgressObserverRef myProgress, const zypp::TriBool & forcedProbe ) { - return joinPipeline( _zyppContext, RepoManagerWorkflow::addRepository( shared_this<RepoManager<ZyppContextRefType>>(), info, std::move(myProgress) ) ); + return joinPipeline( _zyppContext, RepoManagerWorkflow::addRepository( shared_this<RepoManager<ZyppContextRefType>>(), info, std::move(myProgress), forcedProbe ) ); } template<typename ZyppContextRefType> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libzypp-17.37.11/zypp/ng/repomanager.h new/libzypp-17.37.12/zypp/ng/repomanager.h --- old/libzypp-17.37.11/zypp/ng/repomanager.h 2025-06-18 11:57:31.000000000 +0200 +++ new/libzypp-17.37.12/zypp/ng/repomanager.h 2025-07-17 19:50:16.000000000 +0200 @@ -13,6 +13,7 @@ #define ZYPP_NG_REPOMANAGER_INCLUDED #include <utility> +#include <optional> #include <zypp/RepoManagerFlags.h> #include <zypp/RepoManagerOptions.h> @@ -39,7 +40,6 @@ using ServiceInfo = zypp::ServiceInfo; using RepoManagerOptions = zypp::RepoManagerOptions; using PluginRepoverification = zypp_private::repo::PluginRepoverification; - ZYPP_FWD_DECL_TYPE_WITH_REFS( Context ); ZYPP_FWD_DECL_TYPE_WITH_REFS( SyncContext ); ZYPP_FWD_DECL_TYPE_WITH_REFS( ProgressObserver ); @@ -410,7 +410,7 @@ /*! * Adds the repository in \a info and returns the updated \ref RepoInfo object. */ - expected<RepoInfo> addRepository( const RepoInfo & info, ProgressObserverRef myProgress = nullptr ); + expected<RepoInfo> addRepository( const RepoInfo & info, const ProgressObserverRef myProgress = nullptr, const zypp::TriBool & forcedProbe = zypp::indeterminate ); expected<void> addRepositories( const zypp::Url & url, ProgressObserverRef myProgress = nullptr ); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libzypp-17.37.11/zypp/target/rpm/RpmDb.cc new/libzypp-17.37.12/zypp/target/rpm/RpmDb.cc --- old/libzypp-17.37.11/zypp/target/rpm/RpmDb.cc 2025-07-14 12:09:34.000000000 +0200 +++ new/libzypp-17.37.12/zypp/target/rpm/RpmDb.cc 2025-07-18 22:21:30.000000000 +0200 @@ -2035,6 +2035,7 @@ // to figure out which script is currently executed. Otherwise we // can't tell which output belongs to which script. static const str::regex rx( "^D: (%.*): (scriptlet start|running .* scriptlet)" ); + static const str::regex rx2( "^Running (%[^)]*[)])$" ); str::smatch what; std::string line; bool silent = true; // discard everything before 1st scriptlet @@ -2046,12 +2047,21 @@ if ( str::startsWith( line, "D:" ) ) { // rpm debug output if ( str::regex_match( line, what, rx ) ) { // forward ripoff header + DBG << "Verbose RIPOFF:"+what[1] << endl; output_r( "RIPOFF:"+what[1] ); if ( silent ) silent = false; } continue; } + if ( str::regex_match( line, what, rx2 ) ) { // preliminary for 1218459, but rpm needs fixing + // forward ripoff header + DBG << "NonVerbose RIPOFF:"+what[1] << endl; + // output_r( "RIPOFF:"+what[1] ); + // if ( silent ) + // silent = false; + continue; + } if ( silent ) { continue; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libzypp-17.37.11/zypp-curl/ng/network/zckhelper.cc new/libzypp-17.37.12/zypp-curl/ng/network/zckhelper.cc --- old/libzypp-17.37.11/zypp-curl/ng/network/zckhelper.cc 2025-02-24 14:59:49.000000000 +0100 +++ new/libzypp-17.37.12/zypp-curl/ng/network/zckhelper.cc 2025-07-18 22:21:30.000000000 +0200 @@ -13,12 +13,300 @@ #include <fstream> extern "C" { - #include <zck.h> +#include <zck.h> } namespace zyppng { - bool ZckHelper::isZchunkFile(const zypp::Pathname &file) { + ZckError::ZckError(const std::string &msg_r) : Exception(msg_r) + { } + + ZckError::ZckError(std::string &&msg_r) : Exception(std::move(msg_r)) + { } + + expected<void> ZckLoader::buildZchunkFile(const zypp::Pathname &target, const zypp::Pathname &delta, const std::optional<zypp::ByteCount> &expectedFileSize, const std::optional<zypp::ByteCount> &zcKHeaderSize) + { + if ( _state != Initial && _state != Finished ) { + return expected<void>::error( ZYPP_EXCPT_PTR(ZckError("Called buildZchunkFile in invalid state!")) ); + } + + _zchunkContext = zypp::AutoDispose<zckCtx *> ( zck_create(), []( auto ptr ) { if ( ptr ) zck_free( &ptr ); } ); + if( !_zchunkContext ) + return expected<void>::error( ZYPP_EXCPT_PTR(ZckError( zypp::str::Format("Failed to create zchunk context: %1%") % zck_get_error(NULL) )) ); + + _targetFd = open( target.asString().c_str(), O_RDWR ); + if( _targetFd < 0 ) + return expected<void>::error( ZYPP_EXCPT_PTR(ZckError( zypp::str::Format("Unable to open %1%") % target )) ); + + if(!zck_init_adv_read(_zchunkContext, _targetFd)) + return expected<void>::error( ZYPP_EXCPT_PTR(ZckError( zypp::str::Format( "Unable to init read for %1%: %2%") % target % zck_get_error(_zchunkContext) )) ); + + _target = target; + _delta = delta; + _zcKHeaderSize = zcKHeaderSize; + _expectedFileSize = expectedFileSize; + _bytesReused = 0; + + std::vector<Block> initialBlocks; + if ( _zcKHeaderSize ) { + Block b; + b._start = 0; + b._len = *_zcKHeaderSize; + initialBlocks.push_back (b); + _state = DownloadHeader; + } else { + Block b; + b._start = 0; + b._len = minZchunkDownloadSize(); + initialBlocks.push_back (b); + _state = DownloadLead; + } + + _sigBlocksRequired.emit( initialBlocks ); + return expected<void>::success(); + } + + expected<void> ZckLoader::cont() + { + const auto &emitFailed = [this]( PrepareResult::Code code, std::string message ){ + _state = Finished; + _sigFinished.emit( PrepareResult { + ._code = code, + ._blocks = std::vector<Block>(), + ._bytesReused = 0, + ._message = std::move(message), + }); + + if ( _targetFd ) + ftruncate ( _targetFd, 0 ); + + return expected<void>::success(); + }; + + switch( _state ) { + case DownloadLead: { + // calling code claims to have downloaded the lead. + if ( !zck_read_lead( _zchunkContext ) ) + return emitFailed( PrepareResult::Error, zypp::str::Format( "Unable to read lead from %1%: %2%") % _target % zck_get_error(_zchunkContext) ); + + // get actual lead length, no need to fetch it again + const auto start = zck_get_lead_length(_zchunkContext); + + // not adding the header checksums here, zck will validate it when reading the header + Block b; + b._start = start; + b._len = zck_get_header_length(_zchunkContext) - start; + + _state = DownloadHeader; + _sigBlocksRequired.emit( std::vector<Block>{b} ); + + break; + } + case DownloadHeader: { + // calling code claims to have downloaded the full header, lets check + if ( _zcKHeaderSize ) { + // if the zckHeaderSize was known initially the DownloadLead state was skipped. We need to read the lead here + if ( !zck_read_lead( _zchunkContext ) ) { + return emitFailed( PrepareResult::Error, zypp::str::Format( "Unable to read lead from %1%: %2%") % _target % zck_get_error(_zchunkContext) ); + } + } + + if(!zck_read_header(_zchunkContext)) { + return emitFailed( PrepareResult::Error, zypp::str::Format( "Unable to read the header from %1%: %2%") % _target % zck_get_error(_zchunkContext) ); + } + + // yay we have downloaded the header , now we know all chunks from the target file. Next step is to calculate + // what we can reuse and request the missing chunks + + zypp::AutoFD src_fd = open( _delta.asString().c_str(), O_RDONLY); + if(src_fd < 0) { + return emitFailed ( PrepareResult::Error, zypp::str::Format("Unable to open %1%") % _delta ); + } + + zypp::AutoDispose<zckCtx *> zck_src ( zck_create(), []( auto ptr ) { if ( ptr ) zck_free( &ptr ); } ); + if( !zck_src ) { + return emitFailed ( PrepareResult::Error, zypp::str::Format("%1%") % zck_get_error(NULL) ); + } + + if(!zck_init_read(zck_src, src_fd)) { + return emitFailed ( PrepareResult::Error, zypp::str::Format( "Unable to open %1%: %2%") % _delta % zck_get_error(zck_src) ); + } + + { + // Returns 0 for error, -1 for invalid checksum and 1 for valid checksum + switch ( zck_find_valid_chunks(_zchunkContext) ) { + case 0: { // Returns 0 if there was a error + return emitFailed ( PrepareResult::Error, zypp::str::Format( "Unable to open %1%: %2%") % _target % zck_get_error(_zchunkContext) ); + } + case 1: { // getting a 1 would mean the file is already complete, basically impossible but lets handle it anyway + _state = Finished; + _sigFinished.emit(PrepareResult { + ._code = PrepareResult::Success + }); + return expected<void>::success(); + } + } + + const auto srcHashType = zck_get_chunk_hash_type( _zchunkContext ); + const auto targetHashType = zck_get_chunk_hash_type( _zchunkContext ); + + zypp::ByteCount fileSize = zck_get_length( _zchunkContext ); + if ( _expectedFileSize && _expectedFileSize.value() != fileSize ) { + // check if the file size as reported by zchunk is equal to the one we expect + return emitFailed( + PrepareResult::ExceedsMaxLen, + zypp::str::Format("Zchunk header reports a different filesize than what was expected ( Zck: %1% != Exp: %2%).") % fileSize % *_expectedFileSize + ); + } + + if ( ftruncate ( _targetFd, fileSize ) < 0 ) { + return emitFailed ( PrepareResult::Error, zypp::str::Format( "Failed to truncate file to required filesize.") ); + } + + if( srcHashType != targetHashType ) { + return emitFailed ( PrepareResult::Error, zypp::str::Format( "ERROR: Chunk hash types don't match. Source Hash: %1% vs Target Hash: %2%") + % zck_hash_name_from_type ( srcHashType ) + % zck_hash_name_from_type ( targetHashType ) ); + } + + std::vector<Block> ranges; + + if(!zck_copy_chunks( zck_src, _zchunkContext )) + return emitFailed ( PrepareResult::Error, zypp::str::Format( "Unable to copy chunks from deltafile.") ); + + // we calculate what is already downloaded by substracting the block sizes we still need to download from the full file size + auto bytesReused = fileSize; + + auto chunk = zck_get_first_chunk( _zchunkContext ); + + if ( !chunk ) { + return emitFailed ( PrepareResult::Error, zypp::str::Format( "Unable to get first chunk: %1%.") % zck_get_error(_zchunkContext) ); + } + + do { + // Get validity of current chunk: 1 = valid, 0 = missing, -1 = invalid + if ( zck_get_chunk_valid( chunk ) == 1 ) + continue; + + zypp::AutoFREE<char> zckDigest( zck_get_chunk_digest( chunk ) ); + UByteArray chksumVec = zypp::Digest::hexStringToUByteArray( std::string_view( zckDigest.value() ) ); + std::string chksumName; + std::optional<size_t> chksumCompareLen; + + switch ( targetHashType ) { + case ZCK_HASH_SHA1: { + chksumName = zypp::Digest::sha1(); + break; + } + case ZCK_HASH_SHA256: { + chksumName = zypp::Digest::sha256(); + break; + } + case ZCK_HASH_SHA512: { + chksumName = zypp::Digest::sha512(); + break; + } + case ZCK_HASH_SHA512_128: { + // defined in zchunk as + // SHA-512/128 (first 128 bits of SHA-512 checksum) + chksumName = zypp::Digest::sha512(); + chksumCompareLen = chksumVec.size(); + break; + } + default: { + return emitFailed ( PrepareResult::Error, zypp::str::Format( "Unsupported chunk hash type: %1%.") % zck_hash_name_from_type( targetHashType ) ); + } + } + + const auto s = static_cast<size_t>( zck_get_chunk_start( chunk ) ); + const auto l = static_cast<size_t>( zck_get_chunk_comp_size ( chunk ) ); + + MIL_MEDIA << "Downloading block " << s << " with length " << l << " checksum " << zckDigest.value() << " type " << chksumName << std::endl; + ranges.push_back( Block { + ._start = s, + ._len = l, + ._chksumtype = chksumName, + ._checksum = std::move( chksumVec ), + ._relevantDigestLen = std::move(chksumCompareLen) + } ); + + // substract the block length from the already downloaded bytes size + bytesReused -= l; + + } while ( (chunk = zck_get_next_chunk( chunk )) ); + + + _state = DownloadChunks; + _bytesReused = bytesReused; + _sigBlocksRequired.emit( ranges ); + } + break; + } + case DownloadChunks: { + // all data should be there now. + + /* Validate the chunk and data checksums for the current file. + * Returns 0 for error, -1 for invalid checksum and 1 for valid checksum */ + const auto res = zck_validate_checksums( _zchunkContext ); + if ( res == 0 || res == -1 ) { + if( zck_is_error(nullptr) ) { + std::string err = zck_get_error(NULL); + zck_clear_error(NULL); + return emitFailed( PrepareResult::Error, std::move(err) ); + } + if( zck_is_error(_zchunkContext) ) + return emitFailed( PrepareResult::Error, zck_get_error(_zchunkContext) ); + return emitFailed( PrepareResult::Error, "zck_validate_checksums returned a unknown error." ); + } + + _state = Finished; + PrepareResult pres; + pres._code = PrepareResult::Success; + pres._bytesReused = _bytesReused; + _sigFinished.emit(pres); + break; + } + + case Initial: + case Finished: { + return expected<void>::error( ZYPP_EXCPT_PTR(ZckError( zypp::str::Format("Continue called in invalid state.") )) ); + } + } + // continuation worked + return expected<void>::success(); + } + + void ZckLoader::setFailed(const std::string &msg) + { + _state = Finished; + + if ( _targetFd ) + ftruncate ( _targetFd, 0 ); + + _sigFinished.emit( PrepareResult { + ._code = PrepareResult::Error, + ._blocks = std::vector<Block>(), + ._bytesReused = 0, + ._message = msg, + }); + } + + SignalProxy<void (const std::vector<ZckLoader::Block> &)> ZckLoader::sigBlocksRequired() + { + return _sigBlocksRequired; + } + + SignalProxy<void (ZckLoader::PrepareResult)> ZckLoader::sigFinished() + { + return _sigFinished; + } + + zypp::ByteCount ZckLoader::minZchunkDownloadSize() + { + return zck_get_min_download_size(); + } + + bool ZckLoader::isZchunkFile(const zypp::Pathname &file) { std::ifstream dFile(file.c_str()); if (!dFile.is_open()) return false; @@ -31,14 +319,14 @@ return (magic == std::string_view(lead.data(), lead.size())); } - ZckHelper::PrepareResult ZckHelper::prepareZck( const zypp::Pathname &delta, const zypp::Pathname &target, const zypp::ByteCount &expectedFileSize ) + ZckLoader::PrepareResult ZckLoader::prepareZck( const zypp::Pathname &delta, const zypp::Pathname &target, const zypp::ByteCount &expectedFileSize ) { const auto &setFailed = []( PrepareResult::Code code, std::string message ){ return PrepareResult { ._code = code, - ._blocks = std::vector<Block>(), - ._bytesReused = 0, - ._message = std::move(message), + ._blocks = std::vector<Block>(), + ._bytesReused = 0, + ._message = std::move(message), }; }; @@ -94,79 +382,79 @@ if( srcHashType != targetHashType ) return setFailed ( PrepareResult::Error, zypp::str::Format( "ERROR: Chunk hash types don't match. Source Hash: %1% vs Target Hash: %2%") - % zck_hash_name_from_type ( srcHashType ) - % zck_hash_name_from_type ( targetHashType ) ); + % zck_hash_name_from_type ( srcHashType ) + % zck_hash_name_from_type ( targetHashType ) ); std::vector<Block> ranges; if(!zck_copy_chunks( zck_src, zckTarget )) return setFailed ( PrepareResult::Error, zypp::str::Format( "Unable to copy chunks from deltafile.") ); - // we calculate what is already downloaded by substracting the block sizes we still need to download from the full file size - auto bytesReused = _fileSize; + // we calculate what is already downloaded by substracting the block sizes we still need to download from the full file size + auto bytesReused = _fileSize; - auto chunk = zck_get_first_chunk( zckTarget ); - do { - // Get validity of current chunk: 1 = valid, 0 = missing, -1 = invalid - if ( zck_get_chunk_valid( chunk ) == 1 ) - continue; - - zypp::AutoFREE<char> zckDigest( zck_get_chunk_digest( chunk ) ); - UByteArray chksumVec = zypp::Digest::hexStringToUByteArray( std::string_view( zckDigest.value() ) ); - std::string chksumName; - std::optional<size_t> chksumCompareLen; - - switch ( targetHashType ) { - case ZCK_HASH_SHA1: { - chksumName = zypp::Digest::sha1(); - break; - } - case ZCK_HASH_SHA256: { - chksumName = zypp::Digest::sha256(); - break; - } - case ZCK_HASH_SHA512: { - chksumName = zypp::Digest::sha512(); - break; - } - case ZCK_HASH_SHA512_128: { - // defined in zchunk as - // SHA-512/128 (first 128 bits of SHA-512 checksum) - chksumName = zypp::Digest::sha512(); - chksumCompareLen = chksumVec.size(); - break; - } - default: { - return setFailed ( PrepareResult::Error, zypp::str::Format( "Unsupported chunk hash type: %1%.") % zck_hash_name_from_type( targetHashType ) ); - } - } + auto chunk = zck_get_first_chunk( zckTarget ); + do { + // Get validity of current chunk: 1 = valid, 0 = missing, -1 = invalid + if ( zck_get_chunk_valid( chunk ) == 1 ) + continue; + + zypp::AutoFREE<char> zckDigest( zck_get_chunk_digest( chunk ) ); + UByteArray chksumVec = zypp::Digest::hexStringToUByteArray( std::string_view( zckDigest.value() ) ); + std::string chksumName; + std::optional<size_t> chksumCompareLen; + + switch ( targetHashType ) { + case ZCK_HASH_SHA1: { + chksumName = zypp::Digest::sha1(); + break; + } + case ZCK_HASH_SHA256: { + chksumName = zypp::Digest::sha256(); + break; + } + case ZCK_HASH_SHA512: { + chksumName = zypp::Digest::sha512(); + break; + } + case ZCK_HASH_SHA512_128: { + // defined in zchunk as + // SHA-512/128 (first 128 bits of SHA-512 checksum) + chksumName = zypp::Digest::sha512(); + chksumCompareLen = chksumVec.size(); + break; + } + default: { + return setFailed ( PrepareResult::Error, zypp::str::Format( "Unsupported chunk hash type: %1%.") % zck_hash_name_from_type( targetHashType ) ); + } + } - const auto s = static_cast<size_t>( zck_get_chunk_start( chunk ) ); - const auto l = static_cast<size_t>( zck_get_chunk_comp_size ( chunk ) ); + const auto s = static_cast<size_t>( zck_get_chunk_start( chunk ) ); + const auto l = static_cast<size_t>( zck_get_chunk_comp_size ( chunk ) ); - MIL_MEDIA << "Downloading block " << s << " with length " << l << " checksum " << zckDigest.value() << " type " << chksumName << std::endl; - ranges.push_back( Block { - ._start = s, - ._len = l, - ._chksumtype = chksumName, - ._checksum = std::move( chksumVec ), - ._relevantDigestLen = std::move(chksumCompareLen) - } ); + MIL_MEDIA << "Downloading block " << s << " with length " << l << " checksum " << zckDigest.value() << " type " << chksumName << std::endl; + ranges.push_back( Block { + ._start = s, + ._len = l, + ._chksumtype = chksumName, + ._checksum = std::move( chksumVec ), + ._relevantDigestLen = std::move(chksumCompareLen) + } ); - // substract the block length from the already downloaded bytes size - bytesReused -= l; + // substract the block length from the already downloaded bytes size + bytesReused -= l; - } while ( (chunk = zck_get_next_chunk( chunk )) ); + } while ( (chunk = zck_get_next_chunk( chunk )) ); - return PrepareResult { - ._code = PrepareResult::Success, + return PrepareResult { + ._code = PrepareResult::Success, ._blocks = std::move(ranges), ._bytesReused = std::move(bytesReused), ._message = std::string() - }; + }; } - bool ZckHelper::validateZckFile(const zypp::Pathname &file, std::string &error) + bool ZckLoader::validateZckFile(const zypp::Pathname &file, std::string &error) { const auto &setFailed = [&]( std::string &&err ) { error = std::move(err); @@ -201,8 +489,4 @@ return true; } - - - - } // namespace zyppng diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libzypp-17.37.11/zypp-curl/ng/network/zckhelper.h new/libzypp-17.37.12/zypp-curl/ng/network/zckhelper.h --- old/libzypp-17.37.11/zypp-curl/ng/network/zckhelper.h 2025-02-24 14:59:49.000000000 +0100 +++ new/libzypp-17.37.12/zypp-curl/ng/network/zckhelper.h 2025-07-18 22:21:30.000000000 +0200 @@ -17,10 +17,32 @@ #include <zypp-curl/ng/network/curlmultiparthandler.h> #include <zypp-curl/ng/network/rangedesc.h> +#include <zypp-core/AutoDispose.h> +#include <zypp-core/zyppng/base/Base> + +extern "C" { + typedef struct zckCtx zckCtx; +} + namespace zyppng { - class ZckHelper { + class ZckError : public zypp::Exception + { public: + ZckError( const std::string & msg_r ); + ZckError( std::string && msg_r ); + }; + + class ZckLoader : public Base { + public: + + enum State { + Initial, + DownloadLead, + DownloadHeader, + DownloadChunks, + Finished + }; using Block = RangeDesc; @@ -38,6 +60,41 @@ std::string _message; }; + + /*! + * This function kickstarts the build process. The sigBlocksRequired and sigFinished signals need to be connected in order to + * download required blocks or get the finished event. + */ + expected<void> buildZchunkFile( const zypp::Pathname &target, const zypp::Pathname &delta, const std::optional<zypp::ByteCount> &expectedFileSize, const std::optional<zypp::ByteCount> &zcKHeaderSize ); + + /*! + * Advances the statemachine after sigBlocksRequired was triggered and blocks have been downloaded + * into the targetFile + */ + expected<void> cont(); + + /*! + * Advances the statemanchine into the failed state and emits sigFinished + */ + void setFailed( const std::string &msg ); + + /** + * Signal to notify the caller about required blocks, once the blocks are downloaded call + * \ref cont to continue with the process + */ + SignalProxy<void(const std::vector<Block> &)> sigBlocksRequired(); + + /** + * Called once the zchunk build process is finished, either with error or success + */ + SignalProxy<void( PrepareResult )> sigFinished(); + + + /** + * The minimum size to download to have enough data to know the full header size + */ + static zypp::ByteCount minZchunkDownloadSize(); + /*! * Checks if a given file is a zck file */ @@ -53,6 +110,21 @@ * Checks if a given zck file is internally valid */ static bool validateZckFile( const zypp::Pathname &file, std::string &error ); + + + private: + State _state = Initial; + zypp::AutoDispose<zckCtx *> _zchunkContext; + zypp::AutoFD _targetFd; + zypp::ByteCount _bytesReused = 0; + + zypp::Pathname _target; + zypp::Pathname _delta; + std::optional<zypp::ByteCount> _expectedFileSize; + std::optional<zypp::ByteCount> _zcKHeaderSize; + + Signal<void(const std::vector<Block> &)> _sigBlocksRequired; + Signal<void( PrepareResult )> _sigFinished; }; } #endif