libzypp  17.36.7
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>
12 #include <fcntl.h>
13 #include <fstream>
14 
15 extern "C" {
16  #include <zck.h>
17 }
18 
19 namespace zyppng {
20 
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 {
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(
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 {
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
static const std::string & sha256()
sha256
Definition: Digest.cc:50
static const std::string & sha1()
sha1
Definition: Digest.cc:44
Store and operate with byte count.
Definition: ByteCount.h:31
const char * c_str() const
String representation.
Definition: Pathname.h:112
Convenient building of std::string with boost::format.
Definition: String.h:252
AutoDispose<int> calling ::close
Definition: AutoDispose.h:309
static bool isZchunkFile(const zypp::Pathname &file)
Definition: zckhelper.cc:21
static const std::string & sha512()
sha512
Definition: Digest.cc:56
const std::string & asString() const
String representation.
Definition: Pathname.h:93
#define MIL_MEDIA
Definition: mediadebug_p.h:29
reference value() const
Reference to the Tp object.
Definition: AutoDispose.h:138
static bool validateZckFile(const zypp::Pathname &file, std::string &error)
Definition: zckhelper.cc:169
Reference counted access to a Tp object calling a custom Dispose function when the last AutoDispose h...
Definition: AutoDispose.h:94
static PrepareResult prepareZck(const zypp::Pathname &delta, const zypp::Pathname &target, const zypp::ByteCount &expectedFileSize)
Definition: zckhelper.cc:34