libzypp: zypp-curl/ng/network/zckhelper.cc Source File

libzypp 17.36.6

zckhelper.cc
Go to the documentation of this file.
1/*---------------------------------------------------------------------\
2| ____ _ __ __ ___ |
3| |__ / \ / / . \ . \ |
4| / / \ V /| _/ _/ |
5| / /__ | | | | | | |
6| /_____||_| |_| |_| |
7| |
8----------------------------------------------------------------------*/
9#include "zckhelper.h"
10#include <zypp-core/AutoDispose.h>
11#include <zypp-curl/ng/network/private/mediadebug_p.h>
12#include <fcntl.h>
13#include <fstream>
14
15extern "C" {
16 #include <zck.h>
17}
18
19namespace zyppng {
20
21 bool ZckHelper::isZchunkFile(const zypp::Pathname &file) {
22 std::ifstream dFile(file.c_str());
23 if (!dFile.is_open())
24 return false;
25
26 constexpr std::string_view magic("\0ZCK1", 5);
27
28 std::array<char, magic.size()> lead;
29 lead.fill('\0');
30 dFile.read(lead.data(), lead.size());
31 return (magic == std::string_view(lead.data(), lead.size()));
32 }
33
34 ZckHelper::PrepareResult ZckHelper::prepareZck( const zypp::Pathname &delta, const zypp::Pathname &target, const zypp::ByteCount &expectedFileSize )
35 {
36 const auto &setFailed = []( PrepareResult::Code code, std::string message ){
37 return PrepareResult {
38 ._code = code,
39 ._blocks = std::vector<Block>(),
40 ._bytesReused = 0,
41 ._message = std::move(message),
42 };
43 };
44
45 zypp::AutoFD src_fd = open( delta.asString().c_str(), O_RDONLY);
46 if(src_fd < 0)
47 return setFailed ( PrepareResult::Error, zypp::str::Format("Unable to open %1%") % delta );
48
49 zypp::AutoDispose<zckCtx *> zck_src ( zck_create(), []( auto ptr ) { if ( ptr ) zck_free( &ptr ); } );
50 if( !zck_src )
51 return setFailed ( PrepareResult::Error, zypp::str::Format("%1%") % zck_get_error(NULL) );
52
53 if(!zck_init_read(zck_src, src_fd))
54 return setFailed ( PrepareResult::Error, zypp::str::Format( "Unable to open %1%: %2%") % delta % zck_get_error(zck_src) );
55
56 zypp::AutoFD target_fd = open( target.asString().c_str(), O_RDWR);
57 if(target_fd < 0)
58 return setFailed ( PrepareResult::Error, zypp::str::Format("Unable to open %1%") % target );
59
60 zypp::AutoDispose<zckCtx *> zckTarget ( zck_create(), []( auto ptr ) { if ( ptr ) zck_free( &ptr ); } );
61 if( !zckTarget )
62 return setFailed ( PrepareResult::Error, zypp::str::Format("%1%") % zck_get_error(NULL) );
63
64 if(!zck_init_read(zckTarget, target_fd))
65 return setFailed ( PrepareResult::Error, zypp::str::Format( "Unable to open %1%: %2%") % target % zck_get_error(zckTarget) );
66
67 // Returns 0 for error, -1 for invalid checksum and 1 for valid checksum
68 switch ( zck_find_valid_chunks(zckTarget) ) {
69 case 0: // Returns 0 if there was a error
70 return setFailed ( PrepareResult::Error, zypp::str::Format( "Unable to open %1%: %2%") % target % zck_get_error(zckTarget) );
71 case 1: // getting a 1 would mean the file is already complete, basically impossible but lets handle it anyway
72 return PrepareResult {
73 ._code = PrepareResult::NothingToDo
74 };
75 }
76
77 const auto srcHashType = zck_get_chunk_hash_type( zckTarget );
78 const auto targetHashType = zck_get_chunk_hash_type( zckTarget );
79
80 auto _fileSize = expectedFileSize;
81
82 const size_t fLen = zck_get_length( zckTarget );
83 if ( expectedFileSize > 0 ) {
84 // check if the file size as reported by zchunk is equal to the one we expect
85 if ( expectedFileSize != fLen ) {
86 return setFailed(
87 PrepareResult::ExceedsMaxLen,
88 zypp::str::Format("Zchunk header reports a different filesize than what was expected ( Zck: %1% != Exp: %2%).") % fLen % _fileSize
89 );
90 }
91 } else {
92 _fileSize = fLen;
93 }
94
95 if( srcHashType != targetHashType )
96 return setFailed ( PrepareResult::Error, zypp::str::Format( "ERROR: Chunk hash types don't match. Source Hash: %1% vs Target Hash: %2%")
97 % zck_hash_name_from_type ( srcHashType )
98 % zck_hash_name_from_type ( targetHashType ) );
99
100 std::vector<Block> ranges;
101
102 if(!zck_copy_chunks( zck_src, zckTarget ))
103 return setFailed ( PrepareResult::Error, zypp::str::Format( "Unable to copy chunks from deltafile.") );
104
105 // we calculate what is already downloaded by substracting the block sizes we still need to download from the full file size
106 auto bytesReused = _fileSize;
107
108 auto chunk = zck_get_first_chunk( zckTarget );
109 do {
110 // Get validity of current chunk: 1 = valid, 0 = missing, -1 = invalid
111 if ( zck_get_chunk_valid( chunk ) == 1 )
112 continue;
113
114 zypp::AutoFREE<char> zckDigest( zck_get_chunk_digest( chunk ) );
115 UByteArray chksumVec = zypp::Digest::hexStringToUByteArray( std::string_view( zckDigest.value() ) );
116 std::string chksumName;
117 std::optional<size_t> chksumCompareLen;
118
119 switch ( targetHashType ) {
120 case ZCK_HASH_SHA1: {
121 chksumName = zypp::Digest::sha1();
122 break;
123 }
124 case ZCK_HASH_SHA256: {
125 chksumName = zypp::Digest::sha256();
126 break;
127 }
128 case ZCK_HASH_SHA512: {
129 chksumName = zypp::Digest::sha512();
130 break;
131 }
132 case ZCK_HASH_SHA512_128: {
133 // defined in zchunk as
134 // SHA-512/128 (first 128 bits of SHA-512 checksum)
135 chksumName = zypp::Digest::sha512();
136 chksumCompareLen = chksumVec.size();
137 break;
138 }
139 default: {
140 return setFailed ( PrepareResult::Error, zypp::str::Format( "Unsupported chunk hash type: %1%.") % zck_hash_name_from_type( targetHashType ) );
141 }
142 }
143
144 const auto s = static_cast<size_t>( zck_get_chunk_start( chunk ) );
145 const auto l = static_cast<size_t>( zck_get_chunk_comp_size ( chunk ) );
146
147 MIL_MEDIA << "Downloading block " << s << " with length " << l << " checksum " << zckDigest.value() << " type " << chksumName << std::endl;
148 ranges.push_back( Block {
149 ._start = s,
150 ._len = l,
151 ._chksumtype = chksumName,
152 ._checksum = std::move( chksumVec ),
153 ._relevantDigestLen = std::move(chksumCompareLen)
154 } );
155
156 // substract the block length from the already downloaded bytes size
157 bytesReused -= l;
158
159 } while ( (chunk = zck_get_next_chunk( chunk )) );
160
161 return PrepareResult {
162 ._code = PrepareResult::Success,
163 ._blocks = std::move(ranges),
164 ._bytesReused = std::move(bytesReused),
165 ._message = std::string()
166 };
167 }
168
169 bool ZckHelper::validateZckFile(const zypp::Pathname &file, std::string &error)
170 {
171 const auto &setFailed = [&]( std::string &&err ) {
172 error = std::move(err);
173 return false;
174 };
175
176 zypp::AutoFD target_fd = open( file.asString().c_str(), O_RDONLY );
177 if( target_fd < 0 )
178 return setFailed ( zypp::str::Format("Unable to open %1%") % file );
179
180 zypp::AutoDispose<zckCtx *> zckTarget ( zck_create(), []( auto ptr ) { if ( ptr ) zck_free( &ptr ); } );
181 if( !zckTarget )
182 return setFailed ( zypp::str::Format("%1%") % zck_get_error(nullptr) );
183
184 if(!zck_init_read(zckTarget, target_fd))
185 return setFailed ( zypp::str::Format( "Unable to open %1%: %2%") % file % zck_get_error(zckTarget) );
186
187 /* Validate the chunk and data checksums for the current file.
188 * Returns 0 for error, -1 for invalid checksum and 1 for valid checksum */
189 const auto res = zck_validate_checksums( zckTarget );
190 if ( res == 0 || res == -1 ) {
191 if( zck_is_error(nullptr) ) {
192 std::string err = zck_get_error(NULL);
193 zck_clear_error(NULL);
194 return setFailed( std::move(err) );
195 }
196 if( zck_is_error(zckTarget) )
197 return setFailed( zck_get_error(zckTarget) );
198 return setFailed( "zck_validate_checksums returned a unknown error." );
199 }
200
201 return true;
202 }
203
204
205
206
207
208} // namespace zyppng
zypp::AutoDispose
Reference counted access to a Tp object calling a custom Dispose function when the last AutoDispose h...
Definition AutoDispose.h:95
zypp::AutoDispose::value
reference value() const
Reference to the Tp object.
Definition AutoDispose.h:138
zypp::ByteCount
Store and operate with byte count.
Definition ByteCount.h:32
zypp::Digest::sha512
static const std::string & sha512()
sha512
Definition Digest.cc:56
zypp::Digest::sha1
static const std::string & sha1()
sha1
Definition Digest.cc:44
zypp::Digest::sha256
static const std::string & sha256()
sha256
Definition Digest.cc:50
zypp::UByteArray
Definition ByteArray.h:46
zypp::filesystem::Pathname
Pathname.
Definition Pathname.h:47
zypp::filesystem::Pathname::c_str
const char * c_str() const
String representation.
Definition Pathname.h:112
zypp::filesystem::Pathname::asString
const std::string & asString() const
String representation.
Definition Pathname.h:93
zyppng::ZckHelper::Block
RangeDesc Block
Definition zckhelper.h:25
zyppng::ZckHelper::validateZckFile
static bool validateZckFile(const zypp::Pathname &file, std::string &error)
Definition zckhelper.cc:169
zyppng::ZckHelper::isZchunkFile
static bool isZchunkFile(const zypp::Pathname &file)
Definition zckhelper.cc:21
zyppng::ZckHelper::prepareZck
static PrepareResult prepareZck(const zypp::Pathname &delta, const zypp::Pathname &target, const zypp::ByteCount &expectedFileSize)
Definition zckhelper.cc:34
mediadebug_p.h
MIL_MEDIA
#define MIL_MEDIA
Definition mediadebug_p.h:29
zypp::target
Definition KeyRing.h:325
zyppng
Definition MediaCurl2.h:22
zypp::AutoFD
AutoDispose<int> calling ::close
Definition AutoDispose.h:310
zypp::AutoFREE
Definition AutoDispose.h:332
zypp::str::Format
Convenient building of std::string with boost::format.
Definition String.h:253
zyppng::ZckHelper::PrepareResult
Definition zckhelper.h:27
zyppng::ZckHelper::PrepareResult::Code
Code
Definition zckhelper.h:28
zyppng::ZckHelper::PrepareResult::NothingToDo
@ NothingToDo
Definition zckhelper.h:30
zyppng::ZckHelper::PrepareResult::Error
@ Error
Definition zckhelper.h:29
zyppng::ZckHelper::PrepareResult::Success
@ Success
Definition zckhelper.h:32
zyppng::ZckHelper::PrepareResult::ExceedsMaxLen
@ ExceedsMaxLen
Definition zckhelper.h:31
zckhelper.h
AutoDispose.h