libzypp  17.31.31
metalink_p.cc
Go to the documentation of this file.
1 /*---------------------------------------------------------------------\
2 | ____ _ __ __ ___ |
3 | |__ / \ / / . \ . \ |
4 | / / \ V /| _/ _/ |
5 | / /__ | | | | | | |
6 | /_____||_| |_| |_| |
7 | |
8 ----------------------------------------------------------------------*/
9 
13 #include <zypp-core/fs/PathInfo.h>
14 
15 #include "metalink_p.h"
16 #include "final_p.h"
17 
18  #include <iostream>
19 #include <fstream>
20 
21 namespace zyppng {
22 
23  DlMetalinkState::DlMetalinkState(zypp::media::MediaBlockList &&blockList, std::vector<Url> &&mirrors, DownloadPrivate &parent)
24  : RangeDownloaderBaseState( std::move(mirrors), parent )
25  , _blockList( std::move(blockList) )
26  {
27  MIL << "About to enter DlMetalinkState for url " << parent._spec.url() << std::endl;
28  }
29 
31  {
32  auto &sm = stateMachine();
33  const auto &spec = sm._spec;
34 
35  _fileSize = sm._spec.expectedFileSize();
36 
37  //first we try to reuse blocks from the deltafile , if we have one
38  if ( !spec.deltaFile().empty() ) {
39  zypp::PathInfo dFileInfo ( spec.deltaFile() );
40  if ( dFileInfo.isFile() && dFileInfo.isR() ) {
41  FILE *f = fopen( spec.targetPath().asString().c_str(), "w+b" );
42  if ( !f ) {
43  setFailed( NetworkRequestErrorPrivate::customError( NetworkRequestError::InternalError, zypp::str::Format("Failed to open target file.(errno %1%)" ) % errno ) );
44  return;
45  }
46 
47  try {
48  _blockList.reuseBlocks ( f, spec.deltaFile().asString() );
49  } catch ( ... ) { }
50 
51  fclose( f );
52  } else {
53  DBG << "Delta XFER: Delta file: " << spec.deltaFile() << " does not exist or is not readable." << std::endl;
54  }
55  } else {
56  DBG << "Delta XFER: No delta file given, can not reuse blocks." << std::endl;
57  }
58 
59  // setup the base downloader
60  _error = {};
61  _ranges.clear();
62  _failedRanges.clear();
64 
65  if ( _blockList.haveFileChecksum() ) {
68  }
69 
70  const size_t fLen = _blockList.getFilesize();
71  if ( _fileSize > 0 ) {
72  // check if the file size as reported by zchunk is equal to the one we expect
73  if ( _fileSize != fLen ) {
76  zypp::str::Format("Metalink file reports a different filesize than what was expected ( Meta: %1% != Exp: %2%).") % fLen % _fileSize )
77  );
78  }
79  } else {
80  _fileSize = fLen;
81  }
82 
83  const auto maxConns = sm._requestDispatcher->maximumConcurrentConnections();
84  if ( sm._spec.preferredChunkSize() == 0 ) {
85  const auto autoBlkSize = makeBlksize( _fileSize );
86  if ( maxConns == -1 ) {
87  _preferredChunkSize = autoBlkSize;
88  } else {
89  _preferredChunkSize = _fileSize / maxConns;
90  if ( _preferredChunkSize < autoBlkSize )
91  _preferredChunkSize = autoBlkSize;
94  }
95  } else {
96  // spec chunk size overrules the automatic one
97  _preferredChunkSize = sm._spec.preferredChunkSize();
98  }
99 
100  MIL << "Downloading " << sm._spec.url() << " with " << _preferredChunkSize << " chunk size over " << maxConns << std::endl;
101 
102  // remember how many bytes we need to download
103  size_t bytesToDl = 0;
104  // do we need to pad the digest when calculating the checksum for blocks
105  const auto &chksumPad = _blockList.checksumPad ();
106  for ( size_t i = 0; i < _blockList.numBlocks(); i++ ) {
107  const auto &mediaBlock = _blockList.getBlock( i );
108  const auto &blockSum = _blockList.getChecksum ( i );
109  _ranges.push_back(
110  Block{
111  .start = mediaBlock.off,
112  .len = mediaBlock.size,
113  .chksumtype = _blockList.getChecksumType(),
114  .chksumVec = blockSum,
115  .chksumCompareLen = blockSum.size( ),
116  .chksumPad = chksumPad > 0 ? chksumPad : std::optional<size_t>()
117  } );
118 
119  bytesToDl += mediaBlock.size;
120  }
121  // substract the length of the blocks we have to download from the overall file size
122  _downloadedMultiByteCount = fLen - bytesToDl;
123 
125  }
126 
128  {
130  }
131 
133  {
134  if ( _fileChecksumType.size() && _fileChksumVec ) {
135  //TODO move this into a external application so we do not need to block on it
136  //need to check file digest
137  zypp::Digest dig;
138  dig.create( _fileChecksumType );
139 
140  std::ifstream istrm( stateMachine()._spec.targetPath().asString(), std::ios::binary);
141  if ( !istrm.is_open() ) {
142  setFailed( "Failed to verify file digest (Could not open target file)." );
143  return;
144  }
145  if ( !dig.update( istrm ) ) {
146  setFailed( "Failed to verify file digest (Could not read target file)." );
147  return;
148  }
149 
150  const auto &calculatedChksum = dig.digestVector();
151  if ( *_fileChksumVec != calculatedChksum ) {
152  setFailed( "Failed to verify file digest (Checksum did not match)." );
153  return;
154  }
155  }
157  }
158 
159  std::shared_ptr<FinishedState> DlMetalinkState::transitionToFinished()
160  {
161  return std::make_shared<FinishedState>( std::move(_error), stateMachine() );
162  }
163 
164 }
UByteArray digestVector()
get vector of unsigned char representation of the digest
Definition: Digest.cc:291
#define MIL
Definition: Logger.h:96
std::optional< std::vector< unsigned char > > _fileChksumVec
Definition: metalink_p.h:64
Compute Message Digests (MD5, SHA1 etc)
Definition: Digest.h:37
DownloadSpec _spec
Definition: base_p.h:98
DlMetalinkState(zypp::media::MediaBlockList &&blockList, std::vector< Url > &&mirrors, DownloadPrivate &parent)
Definition: metalink_p.cc:23
Store and operate with byte count.
Definition: ByteCount.h:30
void reuseBlocks(FILE *wfp, std::string filename)
void setFailed(NetworkRequestError &&err)
Definition: Arch.h:363
Convenient building of std::string with boost::format.
Definition: String.h:252
const UByteArray & getFileChecksum()
zypp::media::MediaBlockList _blockList
Definition: metalink_p.h:62
static zypp::ByteCount makeBlksize(size_t filesize)
std::string getChecksumType() const
void cancelAll(const NetworkRequestError &err)
std::string _fileChecksumType
Definition: metalink_p.h:63
The NetworkRequestError class Represents a error that occured in.
size_t numBlocks() const
return the number of blocks in the blocklist
bool create(const std::string &name)
initialize creation of a new message digest
Definition: Digest.cc:195
UByteArray getChecksum(size_t blkno) const
const MediaBlock & getBlock(size_t blkno) const
return the offset/size of a block with number blkno
static const Unit M
1024^2 Byte
Definition: ByteCount.h:48
virtual void setFinished() override
Definition: metalink_p.cc:132
Wrapper class for ::stat/::lstat.
Definition: PathInfo.h:220
std::shared_ptr< FinishedState > transitionToFinished()
Definition: metalink_p.cc:159
bool update(const char *bytes, size_t len)
feed data into digest computation algorithm
Definition: Digest.cc:309
static zyppng::NetworkRequestError customError(NetworkRequestError::Type t, std::string &&errorMsg="", std::map< std::string, boost::any > &&extraInfo={})
const Url & url() const
Definition: downloadspec.cc:50
#define DBG
Definition: Logger.h:95
std::string fileChecksumType() const