00001
00002
00003
00004
00005
00006
00007
00008
00013 #include "zypp/source/yum/YUMSourceImpl.h"
00014 #include "zypp/source/yum/YUMAtomImpl.h"
00015 #include "zypp/source/yum/YUMPackageImpl.h"
00016 #include "zypp/source/yum/YUMScriptImpl.h"
00017 #include "zypp/source/yum/YUMMessageImpl.h"
00018 #include "zypp/source/yum/YUMPatchImpl.h"
00019 #include "zypp/source/yum/YUMProductImpl.h"
00020 #include "zypp/source/yum/YUMGroupImpl.h"
00021 #include "zypp/source/yum/YUMPatternImpl.h"
00022
00023 #include "zypp/NVRA.h"
00024 #include "zypp/PathInfo.h"
00025 #include "zypp/base/Logger.h"
00026 #include "zypp/base/Exception.h"
00027 #include "zypp/CapFactory.h"
00028 #include "zypp/Digest.h"
00029 #include "zypp/ExternalProgram.h"
00030 #include "zypp/TmpPath.h"
00031 #include "zypp/ZYppFactory.h"
00032 #include "zypp/KeyRing.h"
00033
00034 #include "zypp/parser/yum/YUMParser.h"
00035 #include "zypp/SourceFactory.h"
00036 #include "zypp/ZYppCallbacks.h"
00037 #include "zypp/SilentCallbacks.h"
00038
00039 #include "zypp/base/GzStream.h"
00040 #include "zypp/base/Gettext.h"
00041 #include "zypp/PathInfo.h"
00042
00043 #include <fstream>
00044
00045 using namespace std;
00046 using namespace zypp::detail;
00047 using namespace zypp::parser::yum;
00048
00050 namespace zypp
00051 {
00052
00053 namespace source
00054 {
00055 namespace yum
00056 {
00058
00059
00060
00062
00063 YUMSourceImpl::YUMSourceImpl()
00064 {}
00065
00066 Date YUMSourceImpl::timestamp() const
00067 {
00068 return PathInfo(repomdFile()).mtime();
00069 }
00070
00071 bool YUMSourceImpl::cacheExists()
00072 {
00073 bool exists = PathInfo(repomdFile()).isExist();
00074 if (exists)
00075 MIL << "YUM cache found at " << _cache_dir << std::endl;
00076 else
00077 MIL << "YUM cache not found" << std::endl;
00078
00079 return exists;
00080 }
00081
00082 const Pathname YUMSourceImpl::metadataRoot() const
00083 {
00084 return _cache_dir.empty() ? _tmp_metadata_dir : _cache_dir;
00085 }
00086
00087 const Pathname YUMSourceImpl::repomdFile() const
00088 {
00089 return metadataRoot() + "/repodata/repomd.xml";
00090 }
00091
00092 const Pathname YUMSourceImpl::repomdFileSignature() const
00093 {
00094 return metadataRoot() + "/repodata/repomd.xml.asc";
00095 }
00096
00097 const Pathname YUMSourceImpl::repomdFileKey() const
00098 {
00099 return metadataRoot() + "/repodata/repomd.xml.key";
00100 }
00101
00102 const TmpDir YUMSourceImpl::downloadMetadata()
00103 {
00104 TmpDir tmpdir;
00105 int copy_result;
00106 MIL << "Downloading metadata to " << tmpdir.path() << std::endl;
00107
00108 Pathname local_dir = tmpdir.path();
00109 if (0 != assert_dir(local_dir + "/repodata" , 0755))
00110 ZYPP_THROW(Exception("Cannot create /repodata in download directory"));
00111
00112 MIL << "Storing data to tmp dir " << local_dir << endl;
00113
00114
00115 Pathname remote_repomd;
00116 try
00117 {
00118 remote_repomd = provideFile(_path + "/repodata/repomd.xml");
00119 }
00120 catch(Exception &e)
00121 {
00122 ZYPP_THROW(Exception("Can't provide " + _path.asString() + "/repodata/repomd.xml from " + url().asString() ));
00123 }
00124
00125
00126 Pathname remote_repomd_key;
00127 Pathname remote_repomd_signature;
00128 try {
00129 remote_repomd_key = tryToProvideFile( _path + "/repodata/repomd.xml.key");
00130 }
00131 catch( const Exception &e ) {
00132 WAR << "Repository does not contain repomd signing key" << std::endl;
00133 }
00134
00135 try {
00136 remote_repomd_signature = tryToProvideFile( _path + "/repodata/repomd.xml.asc");
00137 }
00138 catch( const Exception &e ) {
00139 WAR << "Repository does not contain repomd signinature" << std::endl;
00140 }
00141
00142 copy_result = filesystem::copy( remote_repomd, local_dir + "/repodata/repomd.xml");
00143 if ( copy_result != 0 )
00144 ZYPP_THROW(Exception("Can't copy " + remote_repomd.asString() + " to " + local_dir.asString() + "/repodata/repomd.xml"));
00145
00146 if (PathInfo(remote_repomd_key).isExist())
00147 {
00148 copy_result = filesystem::copy( remote_repomd_key, local_dir + "/repodata/repomd.xml.key");
00149 if ( copy_result != 0 )
00150 ZYPP_THROW(Exception("Can't copy " + remote_repomd_key.asString() + " to " + local_dir.asString() + "/repodata/repomd.xml.key"));
00151 getZYpp()->keyRing()->importKey(local_dir + "/repodata/repomd.xml.key" , false);
00152 }
00153
00154 if (PathInfo(remote_repomd_signature).isExist())
00155 {
00156 copy_result = filesystem::copy( remote_repomd_signature, local_dir + "/repodata/repomd.xml.asc");
00157 if ( copy_result != 0 )
00158 ZYPP_THROW(Exception("Can't copy " + remote_repomd_signature.asString() + " to " + local_dir.asString() + "/repodata/repomd.xml.asc"));
00159 }
00160
00161 DBG << "Reading file " << remote_repomd << endl;
00162 ifstream repo_st(remote_repomd.asString().c_str());
00163 YUMRepomdParser repomd(repo_st, "");
00164
00165 for(; ! repomd.atEnd(); ++repomd)
00166 {
00167 if ((*repomd)->type == "other")
00168 continue;
00169
00170 Pathname src;
00171 try
00172 {
00173 src = provideFile(_path + (*repomd)->location);
00174 }
00175 catch (const Exception &e)
00176 {
00177 ZYPP_THROW(Exception("Can't provide " + _path.asString() + (*repomd)->location + " from " + url().asString() ));
00178 }
00179
00180 Pathname dst = local_dir + (*repomd)->location;
00181
00182
00183
00184
00185 if ( filesystem::copy(src, dst) != 0 )
00186 ZYPP_THROW(Exception("Can't copy " + src.asString() + " to " + dst.asString()));
00187
00188 if (! checkCheckSum( dst, (*repomd)->checksumType, (*repomd)->checksum))
00189 ZYPP_THROW(Exception( (*repomd)->location + " " + N_(" fails checksum verification.") ));
00190
00191
00192
00193 if ((*repomd)->type == "patches")
00194 {
00195
00196 Pathname patches_list = dst;
00197 MIL << "Reading patches file " << patches_list << std::endl;
00198 ifgzstream st ( patches_list.asString().c_str() );
00199 YUMPatchesParser patch(st, "");
00200 for (; !patch.atEnd(); ++patch)
00201 {
00202 string filename = (*patch)->location;
00203 Pathname patch_src;
00204 Pathname patch_dst;
00205 try
00206 {
00207 patch_src = provideFile(_path + filename);
00208 }
00209 catch (const Exception &e)
00210 {
00211 ZYPP_CAUGHT(e);
00212 ZYPP_THROW(Exception("Can't provide patch " + _path.asString() + (*repomd)->location + " from " + url().asString()));
00213 }
00214
00215 patch_dst = local_dir + filename;
00216
00217 if ( filesystem::copy(patch_src, patch_dst) != 0 )
00218 ZYPP_THROW(Exception("Can't copy patch file " + patch_src.asString() + " to " + patch_dst.asString()));
00219
00220
00221 if (! checkCheckSum( patch_dst, (*patch)->checksumType, (*patch)->checksum))
00222 ZYPP_THROW(Exception( (*repomd)->location + " " + N_(" fails checksum verification.") ));
00223 }
00224 }
00225 }
00226
00227
00228 MIL << "Checking [" << (local_dir + "/repodata/repomd.xml") << "] signature" << endl;
00229 if (! getZYpp()->keyRing()->verifyFileSignatureWorkflow(local_dir + "/repodata/repomd.xml", (_path + "/repodata/repomd.xml").asString()+ " (" + url().asString() + ")", local_dir + "/repodata/repomd.xml.asc"))
00230 ZYPP_THROW(Exception(N_("Signed repomd.xml file fails signature check")));
00231
00232
00233 return tmpdir;
00234 }
00235
00236 void YUMSourceImpl::factoryInit()
00237 {
00238 try
00239 {
00240 media::MediaManager media_mgr;
00241 MIL << "Adding no media verifier" << endl;
00242
00243
00244 media::MediaAccessId _media = _media_set->getMediaAccessId(1, true);
00245 media_mgr.delVerifier(_media);
00246 media_mgr.addVerifier(_media, media::MediaVerifierRef(new media::NoVerifier()));
00247 }
00248 catch (const Exception & excpt_r)
00249 {
00250 #warning FIXME: If media data is not set, verifier is not set. Should the media be refused instead?
00251 ZYPP_CAUGHT(excpt_r);
00252 WAR << "Verifier not found" << endl;
00253 }
00254
00255 bool cache = cacheExists();
00256 if ( cache )
00257 {
00258 DBG << "Cached metadata found in [" << _cache_dir << "]." << endl;
00259 }
00260 else
00261 {
00262 if ( _cache_dir.empty() || !PathInfo(_cache_dir).isExist() )
00263 {
00264 DBG << "Cache dir not set. Downloading to temp dir: " << _tmp_metadata_dir << std::endl;
00265
00266
00267 saveMetadataTo(_tmp_metadata_dir);
00268 }
00269 else
00270 {
00271 DBG << "Cached metadata not found in [" << _cache_dir << "]. Will download." << std::endl;
00272 saveMetadataTo(_cache_dir);
00273 }
00274 }
00275
00276 MIL << "YUM source initialized." << std::endl;
00277 MIL << " Url : " << url() << std::endl;
00278 MIL << " Path : " << path() << std::endl;
00279 MIL << " Metadata : " << metadataRoot() << (_cache_dir.empty() ? " [TMP]" : " [CACHE]") << std::endl;
00280 }
00281
00282 void YUMSourceImpl::checkMetadataChecksums() const
00283 {
00284 DBG << "Reading file " << repomdFile() << " to check integrity of metadata." << endl;
00285 ifstream repo_st(repomdFile().asString().c_str());
00286 YUMRepomdParser repomd(repo_st, "");
00287
00288 for(; ! repomd.atEnd(); ++repomd)
00289 {
00290 if ((*repomd)->type == "other")
00291 {
00292 continue;
00293 }
00294 else
00295 {
00296 Pathname file_to_check = metadataRoot() + _path + (*repomd)->location;
00297 if (! checkCheckSum( file_to_check, (*repomd)->checksumType, (*repomd)->checksum))
00298 {
00299 ZYPP_THROW(Exception( (*repomd)->location + " " + N_("fails checksum verification.") ));
00300 }
00301
00302
00303
00304 if ((*repomd)->type == "patches")
00305 {
00306 Pathname patch_index = file_to_check;
00307 DBG << "reading patches from file " << patch_index << endl;
00308 ifgzstream st ( patch_index.asString().c_str() );
00309 YUMPatchesParser patch(st, "");
00310 for (; !patch.atEnd(); ++patch)
00311 {
00312 Pathname patch_filename = metadataRoot() + _path + (*patch)->location;
00313 if (! checkCheckSum(patch_filename, (*patch)->checksumType, (*patch)->checksum))
00314 {
00315 ZYPP_THROW(Exception( (*patch)->location + " " + N_("fails checksum verification.") ));
00316 }
00317 }
00318 }
00319 }
00320 }
00321 }
00322
00323 bool YUMSourceImpl::downloadNeeded(const Pathname & localdir)
00324 {
00325
00326 if ( cacheExists() && PathInfo( repomdFileSignature() ).isExist() )
00327 {
00328 Pathname remote_repomd;
00329 try
00330 {
00331 remote_repomd = provideFile(_path + "/repodata/repomd.xml");
00332 }
00333 catch(Exception &e)
00334 {
00335 ZYPP_THROW(Exception("Can't provide " + _path.asString() + "/repodata/repomd.xml from " + url().asString() ));
00336 }
00337
00338 CheckSum old_repomd_checksum( "SHA1", filesystem::sha1sum(localdir + "/repodata/repomd.xml"));
00339 CheckSum new_repomd_checksum( "SHA1", filesystem::sha1sum(remote_repomd));
00340 if ( (new_repomd_checksum == old_repomd_checksum) && (!new_repomd_checksum.empty()) && (! old_repomd_checksum.empty()))
00341 {
00342 return false;
00343 }
00344 }
00345 return true;
00346 }
00347
00348 void YUMSourceImpl::storeMetadata(const Pathname & cache_dir_r)
00349 {
00350 if ( !_cache_dir.empty() )
00351 {
00352 saveMetadataTo(cache_dir_r);
00353 }
00354 else
00355 {
00356
00357 copyLocalMetadata(_tmp_metadata_dir.path(), cache_dir_r);
00358 }
00359
00360 MIL << "Metadata saved in " << cache_dir_r << ". Setting as cache." << std::endl;
00361 _cache_dir = cache_dir_r;
00362 }
00363
00364 void YUMSourceImpl::saveMetadataTo(const Pathname & dir_r)
00365 {
00366 TmpDir download_tmp_dir;
00367
00368 bool need_to_refresh = true;
00369 try
00370 {
00371 need_to_refresh = downloadNeeded(dir_r);
00372 }
00373 catch(Exception &e)
00374 {
00375 ZYPP_THROW(Exception("Can't check if source has changed or not. Aborting refresh."));
00376 }
00377
00378 if ( need_to_refresh )
00379 {
00380 MIL << "YUM source " << alias() << "has changed since last download. Re-reading metadata into " << dir_r << endl;
00381 }
00382 else
00383 {
00384 MIL << "YUM source " << alias() << "has not changed. Refresh completed. SHA1 of repomd.xml file is the same." << std::endl;
00385 return;
00386 }
00387
00388 try
00389 {
00390 download_tmp_dir = downloadMetadata();
00391 }
00392 catch(Exception &e)
00393 {
00394 ZYPP_THROW(Exception("Downloading metadata failed (is YUM source?) or user did not accept remote source. Aborting refresh."));
00395 }
00396
00397 copyLocalMetadata(download_tmp_dir, dir_r);
00398
00399
00400 }
00401
00402 void YUMSourceImpl::createResolvables(Source_Ref source_r)
00403 {
00404 std::list<YUMRepomdData_Ptr> repo_primary;
00405 std::list<YUMRepomdData_Ptr> repo_files;
00406
00407 std::list<YUMRepomdData_Ptr> repo_group;
00408 std::list<YUMRepomdData_Ptr> repo_pattern;
00409 std::list<YUMRepomdData_Ptr> repo_product;
00410 std::list<YUMRepomdData_Ptr> repo_patches;
00411
00412 callback::SendReport<CreateSourceReport> report;
00413
00414 report->startData( url() );
00415
00416
00417
00418
00419 try
00420 {
00421 DBG << "Reading ifgz file " << repomdFile() << endl;
00422 ifgzstream repo_st(repomdFile().asString().c_str());
00423 YUMRepomdParser repomd(repo_st, "");
00424 for(; ! repomd.atEnd(); ++repomd)
00425 {
00426
00427 if ((*repomd)->type == "primary")
00428 repo_primary.push_back(*repomd);
00429 else if ((*repomd)->type == "filelists")
00430 repo_files.push_back(*repomd);
00431 else if ((*repomd)->type == "group")
00432 repo_group.push_back(*repomd);
00433 else if ((*repomd)->type == "pattern")
00434 repo_pattern.push_back(*repomd);
00435 else if ((*repomd)->type == "product")
00436 repo_product.push_back(*repomd);
00437 else if ((*repomd)->type == "patches")
00438 repo_patches.push_back(*repomd);
00439 else if ((*repomd)->type != "other")
00440 ERR << "Unknown type of repo file: " << (*repomd)->type << endl;
00441 }
00442 }
00443 catch( const Exception & excpt_r )
00444 {
00445 ZYPP_CAUGHT( excpt_r );
00446 ZYPP_THROW( Exception("Cannot read repomd file, cannot initialize source") );
00447 }
00448
00449
00450
00451
00452 try
00453 {
00454
00455 map<NVRA, YUMFileListData_Ptr> files_data;
00456 map<NVRA, YUMOtherData_Ptr> other_data;
00457 for (std::list<YUMRepomdData_Ptr>::const_iterator it
00458 = repo_files.begin();
00459 it != repo_files.end();
00460 it++)
00461 {
00462 Pathname filename = metadataRoot() + (*it)->location;
00463 DBG << "Reading ifgz file " << filename << endl;
00464 ifgzstream st( filename.asString().c_str() );
00465
00466 YUMFileListParser filelist ( st, "" );
00467 for (; ! filelist.atEnd(); ++filelist)
00468 {
00469 if (*filelist == NULL) continue;
00470 NVRA nvra( (*filelist)->name,
00471 Edition( (*filelist)->ver, (*filelist)->rel, str::strtonum<int>( (*filelist)->epoch ) ),
00472 Arch ( (*filelist)->arch ) );
00473 files_data[nvra] = *filelist;
00474 }
00475 if (filelist.errorStatus())
00476 ZYPP_THROW(Exception(filelist.errorStatus()->msg()));
00477 }
00478
00479 #if 0 // don't parse 'other.xml' (#159316)
00480
00481 for (std::list<YUMRepomdData_Ptr>::const_iterator it
00482 = repo_other.begin();
00483 it != repo_other.end();
00484 it++)
00485 {
00486 Pathname filename = cacheExists()
00487 ? _cache_dir + (*it)->location
00488 : provideFile(_path + (*it)->location);
00489 if (!cacheExists())
00490 {
00491 if (! checkCheckSum(filename, (*it)->checksumType, (*it)->checksum))
00492 {
00493 ZYPP_THROW(Exception(N_("Failed check for the metadata file check sum")));
00494 }
00495 }
00496 _metadata_files.push_back((*it)->location);
00497 DBG << "Reading file " << filename << endl;
00498
00499 ifgzstream st ( filename.asString().c_str() );
00500 YUMOtherParser other(st, "");
00501 for (;
00502 ! other.atEnd();
00503 ++other)
00504 {
00505 if (*other == NULL) continue;
00506 Arch arch;
00507 if (!(*other)->arch.empty())
00508 arch = Arch((*other)->arch);
00509
00510 NVRA nvra( (*other)->name,
00511 Edition( (*other)->ver, (*other)->rel, str::strtonum<int>( (*other)->epoch ) ),
00512 arch );
00513 other_data[nvra] = *other;
00514 }
00515 if (other.errorStatus())
00516 throw *other.errorStatus();
00517 }
00518 #endif
00519
00520
00521 for (std::list<YUMRepomdData_Ptr>::const_iterator it = repo_primary.begin(); it != repo_primary.end(); it++)
00522 {
00523 Pathname filename = metadataRoot() + (*it)->location;
00524 DBG << "Reading file " << filename << endl;
00525 ifgzstream st ( filename.asString().c_str() );
00526 YUMPrimaryParser prim(st, "");
00527 for (; !prim.atEnd(); ++prim)
00528 {
00529 if (*prim == NULL) continue;
00530
00531 Arch arch;
00532 if (!(*prim)->arch.empty())
00533 arch = Arch((*prim)->arch);
00534
00535 NVRA nvra( (*prim)->name,
00536 Edition( (*prim)->ver, (*prim)->rel, str::strtonum<int>( (*prim)->epoch ) ),
00537 arch );
00538 map<NVRA, YUMOtherData_Ptr>::iterator found_other = other_data.find( nvra );
00539 map<NVRA, YUMFileListData_Ptr>::iterator found_files = files_data.find( nvra );
00540
00541 YUMFileListData filelist_empty;
00542 YUMOtherData other_empty;
00543 ResImplTraits<YUMPackageImpl>::Ptr impl;
00544 Package::Ptr p = createPackage( source_r, **prim, found_files != files_data.end()
00545 ? *(found_files->second)
00546 : filelist_empty,
00547 found_other != other_data.end()
00548 ? *(found_other->second)
00549 : other_empty,
00550 impl
00551 );
00552 ImplAndPackage iap = { impl, p };
00553 _package_impl[nvra] = iap;
00554
00555 _store.insert (p);
00556 }
00557 if (prim.errorStatus())
00558 ZYPP_THROW(Exception(prim.errorStatus()->msg()));
00559 }
00560 }
00561 catch (...)
00562 {
00563 ERR << "Cannot read package information" << endl;
00564 }
00565
00566
00567
00568 try
00569 {
00570 for (std::list<YUMRepomdData_Ptr>::const_iterator it = repo_group.begin();
00571 it != repo_group.end();
00572 it++)
00573 {
00574 Pathname filename = metadataRoot() + (*it)->location;
00575 DBG << "Reading file " << filename << endl;
00576 ifgzstream st ( filename.asString().c_str() );
00577 YUMGroupParser group(st, "");
00578 for (; !group.atEnd(); ++group)
00579 {
00580 Selection::Ptr p = createGroup( source_r, **group );
00581 _store.insert (p);
00582 }
00583 if (group.errorStatus())
00584 ZYPP_THROW(Exception(group.errorStatus()->msg()));
00585 }
00586 }
00587 catch (...)
00588 {
00589 ERR << "Cannot read package groups information" << endl;
00590 }
00591
00592
00593
00594
00595 try
00596 {
00597 for (std::list<YUMRepomdData_Ptr>::const_iterator it = repo_pattern.begin();
00598 it != repo_pattern.end(); it++)
00599 {
00600 Pathname filename = metadataRoot() + (*it)->location;
00601
00602 DBG << "Reading file " << filename << endl;
00603 ifgzstream st ( filename.asString().c_str() );
00604 YUMPatternParser pattern(st, "");
00605 for (; !pattern.atEnd(); ++pattern)
00606 {
00607 Pattern::Ptr p = createPattern( source_r, **pattern );
00608 _store.insert (p);
00609 }
00610 if (pattern.errorStatus())
00611 ZYPP_THROW(Exception(pattern.errorStatus()->msg()));
00612 }
00613 }
00614 catch (...) {
00615 ERR << "Cannot read installation patterns information" << endl;
00616 }
00617
00618
00619
00620 try
00621 {
00622 for (std::list<YUMRepomdData_Ptr>::const_iterator it = repo_product.begin();
00623 it != repo_product.end();
00624 it++)
00625 {
00626 Pathname filename = metadataRoot() + (*it)->location;
00627 ifgzstream st ( filename.asString().c_str() );
00628 YUMProductParser product(st, "");
00629 for (; !product.atEnd(); ++product)
00630 {
00631 Product::Ptr p = createProduct( source_r, **product );
00632 _store.insert (p);
00633 }
00634 if (product.errorStatus())
00635 ZYPP_THROW(Exception(product.errorStatus()->msg()));
00636 }
00637 }
00638 catch (...) {
00639 ERR << "Cannot read products information" << endl;
00640 }
00641
00642
00643
00644 try
00645 {
00646 std::list<std::string> patch_files;
00647 for (std::list<YUMRepomdData_Ptr>::const_iterator it = repo_patches.begin();
00648 it != repo_patches.end();
00649 it++)
00650 {
00651 Pathname filename = metadataRoot() + (*it)->location;
00652
00653 DBG << "Reading file " << filename << endl;
00654 ifgzstream st ( filename.asString().c_str() );
00655 YUMPatchesParser patch(st, "");
00656
00657 for (; !patch.atEnd(); ++patch)
00658 {
00659 string filename = (*patch)->location;
00660 patch_files.push_back(filename);
00661 }
00662
00663 if (patch.errorStatus())
00664 ZYPP_THROW(Exception(patch.errorStatus()->msg()));
00665 }
00666
00667
00668
00669
00670 for (std::list<std::string>::const_iterator it = patch_files.begin();
00671 it != patch_files.end();
00672 it++)
00673 {
00674 Pathname filename = metadataRoot() + *it;
00675 DBG << "Reading file " << filename << endl;
00676 ifgzstream st ( filename.asString().c_str() );
00677 YUMPatchParser ptch(st, "");
00678 for(;
00679 !ptch.atEnd();
00680 ++ptch)
00681 {
00682 Patch::Ptr p = createPatch(
00683 source_r,
00684 **ptch
00685 );
00686 _store.insert (p);
00687 Patch::AtomList atoms = p->atoms();
00688 for (Patch::AtomList::iterator at = atoms.begin();
00689 at != atoms.end();
00690 at++)
00691 {
00692 _store.insert (*at);
00693 }
00694 }
00695 if (ptch.errorStatus())
00696 ZYPP_THROW(Exception(ptch.errorStatus()->msg()));
00697 }
00698 }
00699 catch (...)
00700 {
00701 ERR << "Cannot read patch metadata" << endl;
00702 }
00703
00704 report->finishData( url(), CreateSourceReport::NO_ERROR, "" );
00705 }
00706
00707
00708 Package::Ptr YUMSourceImpl::createPackage(
00709 Source_Ref source_r,
00710 const zypp::parser::yum::YUMPrimaryData & parsed,
00711 const zypp::parser::yum::YUMFileListData & filelist,
00712 const zypp::parser::yum::YUMOtherData & other,
00713 ResImplTraits<YUMPackageImpl>::Ptr & impl
00714 )
00715 {
00716 try
00717 {
00718 impl = new YUMPackageImpl( source_r, parsed, filelist, other );
00719
00720 Dependencies deps( createDependencies( parsed, ResTraits<Package>::kind ) );
00721
00722 CapFactory f;
00723
00724 for (std::list<FileData>::const_iterator it = filelist.files.begin();
00725 it != filelist.files.end();
00726 it++)
00727 {
00728 deps[Dep::PROVIDES].insert( f.parse( ResTraits<Package>::kind, it->name ) );
00729 }
00730
00731 Arch arch;
00732 if (!parsed.arch.empty())
00733 arch = Arch(parsed.arch);
00734
00735
00736 NVRAD dataCollect( parsed.name,
00737 Edition( parsed.ver, parsed.rel, parsed.epoch ),
00738 arch,
00739 deps
00740 );
00741 Package::Ptr package = detail::makeResolvableFromImpl(
00742 dataCollect, impl
00743 );
00744 return package;
00745 }
00746 catch (const Exception & excpt_r)
00747 {
00748 ZYPP_CAUGHT(excpt_r);
00749 ZYPP_THROW(Exception("Cannot create package object"));
00750 }
00751 return 0L;
00752 }
00753
00754 Atom::Ptr YUMSourceImpl::augmentPackage(
00755 Source_Ref source_r,
00756 const zypp::parser::yum::YUMPatchPackage & parsed
00757 )
00758 {
00759 try
00760 {
00761 Arch arch;
00762 if (!parsed.arch.empty())
00763 arch = Arch( parsed.arch );
00764
00765 Edition edition( parsed.ver, parsed.rel, parsed.epoch );
00766 NVRA nvra( parsed.name,
00767 edition,
00768 arch );
00769
00770 DBG << "augmentPackage(" << nvra << ")" << endl;
00771
00772
00773 CapFactory f;
00774 Dependencies deps = createDependencies( parsed, ResTraits<Package>::kind );
00775
00776 NVRAD atomdata( nvra, deps );
00777 ResImplTraits<YUMAtomImpl>::Ptr atomimpl = new YUMAtomImpl( source_r );
00778 Atom::Ptr atom = detail::makeResolvableFromImpl( atomdata, atomimpl );
00779
00780
00781 PackageImplMapT::const_iterator it = _package_impl.find( nvra );
00782 if (it == _package_impl.end()) {
00783 WAR << "Patch augments non-existant package " << nvra << endl;
00784 }
00785 else
00786 {
00787 ResImplTraits<YUMPackageImpl>::Ptr impl = it->second.impl;
00788
00789 if (!parsed.location.empty()) {
00790 impl->_location = parsed.location;
00791 impl->_mediaNumber = str::strtonum<unsigned>( parsed.media );
00792 impl->_checksum = CheckSum(parsed.checksumType, parsed.checksum);
00793 }
00794 impl->_install_only = parsed.installOnly;
00795
00796
00797 impl->_patch_rpms = std::list<PatchRpm>();
00798 for (std::list<YUMPatchRpm>::const_iterator it = parsed.patchRpms.begin();
00799 it != parsed.patchRpms.end(); ++it)
00800 {
00801 std::list<BaseVersion> bv_list;
00802 for (std::list<YUMBaseVersion>::const_iterator bvit = it->baseVersions.begin();
00803 bvit != it->baseVersions.end(); ++bvit)
00804 {
00805 BaseVersion bv(
00806 Edition (bvit->ver, bvit->rel, bvit->epoch),
00807 CheckSum("md5", bvit->md5sum),
00808 strtol(bvit->buildtime.c_str(), 0, 10)
00809 );
00810 bv_list.push_back(bv);
00811 }
00812 PatchRpm patch_rpm(
00813 Arch(it->arch),
00814 Pathname(it->location),
00815 strtol(it->downloadsize.c_str(), 0, 10),
00816 CheckSum (it->checksumType, it->checksum),
00817 strtol(it->buildtime.c_str(), 0, 10),
00818 bv_list,
00819 strtol(it->media.c_str(), 0, 10)
00820 );
00821 impl->_patch_rpms.push_back(patch_rpm);
00822 }
00823
00824
00825
00826 impl->_delta_rpms = std::list<DeltaRpm>();
00827 for (std::list<YUMDeltaRpm>::const_iterator it = parsed.deltaRpms.begin();
00828 it != parsed.deltaRpms.end(); ++it)
00829 {
00830 DeltaRpm delta_rpm(
00831 Arch(it->arch),
00832 Pathname(it->location),
00833 strtol(it->downloadsize.c_str(), 0, 10),
00834 CheckSum (it->checksumType, it->checksum),
00835 strtol(it->buildtime.c_str(), 0, 10),
00836 BaseVersion(
00837 Edition (it->baseVersion.ver, it->baseVersion.rel, it->baseVersion.epoch),
00838 CheckSum("md5", it->baseVersion.md5sum),
00839 strtol(it->baseVersion.buildtime.c_str(), 0, 10)
00840 ),
00841 strtol(it->media.c_str(), 0, 10)
00842 );
00843 impl->_delta_rpms.push_back(delta_rpm);
00844 }
00845 }
00846 return atom;
00847 }
00848 catch (const Exception & excpt_r)
00849 {
00850 ZYPP_CAUGHT(excpt_r);
00851 ZYPP_THROW(Exception("Cannot create augmented package object"));
00852 }
00853 return 0L;
00854 }
00855
00856 Selection::Ptr YUMSourceImpl::createGroup(
00857 Source_Ref source_r,
00858 const zypp::parser::yum::YUMGroupData & parsed
00859 )
00860 {
00861 try
00862 {
00863 ResImplTraits<YUMGroupImpl>::Ptr impl(new YUMGroupImpl(source_r, parsed));
00864
00865 NVRAD dataCollect( parsed.groupId,
00866 Edition::noedition,
00867 Arch_noarch,
00868 createGroupDependencies(parsed));
00869 Selection::Ptr group = detail::makeResolvableFromImpl(
00870 dataCollect, impl
00871 );
00872 return group;
00873 }
00874 catch (const Exception & excpt_r)
00875 {
00876 ZYPP_CAUGHT(excpt_r);
00877 ZYPP_THROW(Exception("Cannot create package group object"));
00878 }
00879 return 0L;
00880 }
00881
00882 Pattern::Ptr YUMSourceImpl::createPattern(
00883 Source_Ref source_r,
00884 const zypp::parser::yum::YUMPatternData & parsed
00885 )
00886 {
00887 try
00888 {
00889 ResImplTraits<YUMPatternImpl>::Ptr impl(new YUMPatternImpl(source_r, parsed));
00890
00891 Arch arch;
00892 if (!parsed.arch.empty())
00893 arch = Arch(parsed.arch);
00894
00895 NVRAD dataCollect( parsed.name,
00896 Edition( parsed.ver, parsed.rel, parsed.epoch ),
00897 arch,
00898 createDependencies(parsed, ResTraits<Pattern>::kind));
00899 Pattern::Ptr pattern = detail::makeResolvableFromImpl(
00900 dataCollect, impl
00901 );
00902 return pattern;
00903 }
00904 catch (const Exception & excpt_r)
00905 {
00906 ZYPP_CAUGHT(excpt_r);
00907 ZYPP_THROW(Exception("Cannot create installation pattern object"));
00908 }
00909 return 0L;
00910 }
00911
00912 Message::Ptr YUMSourceImpl::createMessage(
00913 Source_Ref source_r,
00914 const zypp::parser::yum::YUMPatchMessage & parsed,
00915 Patch::constPtr patch
00916 )
00917 {
00918 try
00919 {
00920 ResImplTraits<YUMMessageImpl>::Ptr impl(new YUMMessageImpl(source_r, parsed, patch));
00921 Arch arch;
00922 if (!parsed.arch.empty())
00923 arch = Arch(parsed.arch);
00924
00925 NVRAD dataCollect( parsed.name,
00926 Edition( parsed.ver, parsed.rel, parsed.epoch ),
00927 arch,
00928 createDependencies(parsed,
00929 ResTraits<Message>::kind)
00930 );
00931 Message::Ptr message = detail::makeResolvableFromImpl(
00932 dataCollect, impl
00933 );
00934 return message;
00935 }
00936 catch (const Exception & excpt_r)
00937 {
00938 ZYPP_CAUGHT(excpt_r);
00939 ZYPP_THROW(Exception("Cannot create message object"));
00940 }
00941 return 0L;
00942 }
00943
00944 Script::Ptr YUMSourceImpl::createScript(
00945 Source_Ref source_r,
00946 const zypp::parser::yum::YUMPatchScript & parsed
00947 )
00948 {
00949 try
00950 {
00951 ResImplTraits<YUMScriptImpl>::Ptr impl(new YUMScriptImpl(source_r, parsed));
00952 Arch arch;
00953 if (!parsed.arch.empty())
00954 arch = Arch(parsed.arch);
00955
00956 NVRAD dataCollect( parsed.name,
00957 Edition( parsed.ver, parsed.rel, parsed.epoch ),
00958 arch,
00959 createDependencies(parsed,
00960 ResTraits<Script>::kind)
00961 );
00962 Script::Ptr script = detail::makeResolvableFromImpl(
00963 dataCollect, impl
00964 );
00965 return script;
00966 }
00967 catch (const Exception & excpt_r)
00968 {
00969 ZYPP_CAUGHT(excpt_r);
00970 ZYPP_THROW(Exception("Cannot create script object"));
00971 }
00972 return 0L;
00973 }
00974
00975 Product::Ptr YUMSourceImpl::createProduct(
00976 Source_Ref source_r,
00977 const zypp::parser::yum::YUMProductData & parsed
00978 )
00979 {
00980 try
00981 {
00982 ResImplTraits<YUMProductImpl>::Ptr impl(new YUMProductImpl(source_r, parsed));
00983
00984
00985 Arch arch;
00986 if (!parsed.arch.empty())
00987 arch = Arch(parsed.arch);
00988 NVRAD dataCollect( parsed.name,
00989 Edition( parsed.ver, parsed.rel, parsed.epoch ),
00990 arch,
00991 createDependencies(parsed,
00992 ResTraits<Product>::kind)
00993 );
00994 Product::Ptr product = detail::makeResolvableFromImpl(
00995 dataCollect, impl
00996 );
00997 return product;
00998 }
00999 catch (const Exception & excpt_r)
01000 {
01001 ZYPP_CAUGHT(excpt_r);
01002 ZYPP_THROW(Exception("Cannot create product object"));
01003 }
01004 return 0L;
01005 }
01006
01007 Patch::Ptr YUMSourceImpl::createPatch(
01008 Source_Ref source_r,
01009 const zypp::parser::yum::YUMPatchData & parsed
01010 )
01011 {
01012 try
01013 {
01014 ResImplTraits<YUMPatchImpl>::Ptr impl(new YUMPatchImpl(source_r, parsed, *this));
01015
01016 Arch arch;
01017 if (!parsed.arch.empty())
01018 arch = Arch(parsed.arch);
01019
01020
01021 NVRAD dataCollect( parsed.name,
01022 Edition( parsed.ver, parsed.rel, parsed.epoch ),
01023 arch,
01024 createDependencies( parsed,
01025 ResTraits<Patch>::kind)
01026 );
01027 Patch::Ptr patch = detail::makeResolvableFromImpl(
01028 dataCollect, impl
01029 );
01030
01031 CapFactory _f;
01032 Capability cap( _f.parse(
01033 Patch::TraitsType::kind,
01034 parsed.name,
01035 Rel::EQ,
01036 Edition(parsed.ver, parsed.rel, parsed.epoch)
01037 ));
01038
01039
01040 typedef std::map<std::string, shared_ptr<YUMPatchPackage> > PkgAtomsMap;
01041 PkgAtomsMap pkg_atoms;
01042
01043 for (std::list<shared_ptr<YUMPatchAtom> >::const_iterator it
01044 = parsed.atoms.begin();
01045 it != parsed.atoms.end();
01046 it++)
01047 {
01048 switch ((*it)->atomType())
01049 {
01050
01051
01052
01053
01054
01055 case YUMPatchAtom::Package: {
01056 shared_ptr<YUMPatchPackage> package_data
01057 = dynamic_pointer_cast<YUMPatchPackage>(*it);
01058 string atomkey( package_data->name + "-" + package_data->epoch + ":" + package_data->ver + "-" + package_data->rel );
01059
01060
01061 PkgAtomsMap::iterator pa_pos = pkg_atoms.find( atomkey );
01062 if (pa_pos != pkg_atoms.end()) {
01063 try {
01064 Arch oldarch, newarch;
01065 if (!(pa_pos->second->arch.empty())) oldarch = Arch( pa_pos->second->arch );
01066 if (!(package_data->arch.empty())) newarch = Arch( package_data->arch );
01067 if (newarch.compatibleWith( getZYpp()->architecture() ) ) {
01068
01069 if (!oldarch.compatibleWith( getZYpp()->architecture() )
01070 || oldarch.compare( newarch ) < 0)
01071 {
01072 pa_pos->second = package_data;
01073 }
01074 }
01075 }
01076 catch( const Exception & excpt_r ) {
01077 ZYPP_CAUGHT( excpt_r );
01078 ERR << "Package " << package_data->name << " in patch's atomlist has bad architecture '" << package_data->arch << "'" << endl;
01079 }
01080 }
01081 else {
01082 pkg_atoms[atomkey] = package_data;
01083 }
01084 break;
01085 }
01086 case YUMPatchAtom::Message: {
01087 shared_ptr<YUMPatchMessage> message_data
01088 = dynamic_pointer_cast<YUMPatchMessage>(*it);
01089 Message::Ptr message = createMessage(source_r, *message_data, patch);
01090 impl->_atoms.push_back(message);
01091 break;
01092 }
01093 case YUMPatchAtom::Script: {
01094 shared_ptr<YUMPatchScript> script_data
01095 = dynamic_pointer_cast<YUMPatchScript>(*it);
01096 Script::Ptr script = createScript(source_r, *script_data);
01097 impl->_atoms.push_back(script);
01098 break;
01099 }
01100 default:
01101 ERR << "Unknown type of atom" << endl;
01102 }
01103 #if 0 // atoms require their patch, why ?
01104 for (Patch::AtomList::iterator it = impl->_atoms.begin();
01105 it != impl->_atoms.end();
01106 it++)
01107 {
01108 (*it)->injectRequires(cap);
01109 }
01110 #endif
01111 }
01112
01113 for (PkgAtomsMap::const_iterator pa_pos = pkg_atoms.begin(); pa_pos != pkg_atoms.end(); ++pa_pos) {
01114 Atom::Ptr atom = augmentPackage( source_r, *(pa_pos->second) );
01115 impl->_atoms.push_back(atom);
01116 }
01117
01118 return patch;
01119 }
01120 catch (const Exception & excpt_r)
01121 {
01122 ZYPP_CAUGHT(excpt_r);
01123 ZYPP_THROW(Exception("Cannot create patch object"));
01124 }
01125 return 0L;
01126 }
01127
01128 Dependencies YUMSourceImpl::createDependencies(
01129 const zypp::parser::yum::YUMObjectData & parsed,
01130 const Resolvable::Kind my_kind
01131 )
01132 {
01133 Dependencies _deps;
01134 for (std::list<YUMDependency>::const_iterator it = parsed.provides.begin();
01135 it != parsed.provides.end();
01136 it++)
01137 {
01138 _deps[Dep::PROVIDES].insert(createCapability(*it, my_kind));
01139 }
01140
01141 for (std::list<YUMDependency>::const_iterator it = parsed.conflicts.begin();
01142 it != parsed.conflicts.end();
01143 it++)
01144 {
01145 _deps[Dep::CONFLICTS].insert(createCapability(*it, my_kind));
01146 }
01147
01148 for (std::list<YUMDependency>::const_iterator it = parsed.obsoletes.begin();
01149 it != parsed.obsoletes.end();
01150 it++)
01151 {
01152 _deps[Dep::OBSOLETES].insert(createCapability(*it, my_kind));
01153 }
01154
01155 for (std::list<YUMDependency>::const_iterator it = parsed.freshens.begin();
01156 it != parsed.freshens.end();
01157 it++)
01158 {
01159 _deps[Dep::FRESHENS].insert(createCapability(*it, my_kind));
01160 }
01161
01162 for (std::list<YUMDependency>::const_iterator it = parsed.recommends.begin();
01163 it != parsed.recommends.end();
01164 it++)
01165 {
01166 _deps[Dep::RECOMMENDS].insert(createCapability(*it, my_kind));
01167 }
01168
01169 for (std::list<YUMDependency>::const_iterator it = parsed.suggests.begin();
01170 it != parsed.suggests.end();
01171 it++)
01172 {
01173 _deps[Dep::SUGGESTS].insert(createCapability(*it, my_kind));
01174 }
01175
01176 for (std::list<YUMDependency>::const_iterator it = parsed.supplements.begin();
01177 it != parsed.supplements.end();
01178 it++)
01179 {
01180 _deps[Dep::SUPPLEMENTS].insert(createCapability(*it, my_kind));
01181 }
01182
01183 for (std::list<YUMDependency>::const_iterator it = parsed.enhances.begin();
01184 it != parsed.enhances.end();
01185 it++)
01186 {
01187 _deps[Dep::ENHANCES].insert(createCapability(*it, my_kind));
01188 }
01189
01190 for (std::list<YUMDependency>::const_iterator it = parsed.prerequires.begin();
01191 it != parsed.prerequires.end();
01192 it++)
01193 {
01194 _deps[Dep::PREREQUIRES].insert(createCapability(*it, my_kind));
01195 }
01196
01197 for (std::list<YUMDependency>::const_iterator it = parsed.requires.begin();
01198 it != parsed.requires.end();
01199 it++)
01200 {
01201 if (it->pre == "1")
01202 _deps[Dep::PREREQUIRES].insert(createCapability(*it, my_kind));
01203 else
01204 _deps[Dep::REQUIRES].insert(createCapability(*it, my_kind));
01205 }
01206
01207 return _deps;
01208 }
01209
01210 Dependencies YUMSourceImpl::createGroupDependencies(
01211 const zypp::parser::yum::YUMGroupData & parsed
01212 )
01213 {
01214 Dependencies _deps;
01215
01216 for (std::list<PackageReq>::const_iterator it = parsed.packageList.begin();
01217 it != parsed.packageList.end();
01218 it++)
01219 {
01220 Dep _dep_kind = Dep::REQUIRES;
01221 if (it->type == "mandatory" || it->type == "")
01222 {
01223 _dep_kind = Dep::REQUIRES;
01224 }
01225 else if (it->type == "default")
01226 {
01227 _dep_kind = Dep::RECOMMENDS;
01228 }
01229 else if (it->type == "optional")
01230 {
01231 _dep_kind = Dep::SUGGESTS;
01232 }
01233 _deps[_dep_kind].insert(createCapability(YUMDependency(
01234 "",
01235 it->name,
01236 "EQ",
01237 it->epoch,
01238 it->ver,
01239 it->rel,
01240 ""
01241 ),
01242 ResTraits<Package>::kind));
01243 }
01244 for (std::list<MetaPkg>::const_iterator it = parsed.grouplist.begin();
01245 it != parsed.grouplist.end();
01246 it++)
01247 {
01248 Dep _dep_kind = Dep::REQUIRES;
01249 if (it->type == "mandatory" || it->type == "")
01250 {
01251 _dep_kind = Dep::REQUIRES;
01252 }
01253 else if (it->type == "default")
01254 {
01255 _dep_kind = Dep::RECOMMENDS;
01256 }
01257 else if (it->type == "optional")
01258 {
01259 _dep_kind = Dep::SUGGESTS;
01260 }
01261 _deps[_dep_kind].insert(createCapability(YUMDependency(
01262 "",
01263 it->name,
01264 "",
01265 "",
01266 "",
01267 "",
01268 ""
01269 ),
01270 ResTraits<Selection>::kind));
01271 }
01272 return _deps;
01273 }
01274
01275 Capability YUMSourceImpl::createCapability(const YUMDependency & dep,
01276 const Resolvable::Kind & my_kind)
01277 {
01278 CapFactory _f;
01279 Resolvable::Kind _kind = dep.kind == "" ? my_kind : Resolvable::Kind(dep.kind);
01280 Capability cap;
01281 if ( ! dep.isEncoded() )
01282 {
01283 cap = _f.parse(
01284 _kind,
01285 dep.name,
01286 Rel(dep.flags),
01287 Edition(dep.ver, dep.rel, dep.epoch)
01288 );
01289 }
01290 else
01291 {
01292 cap = _f.parse( _kind, dep.encoded );
01293 }
01294 return cap;
01295 }
01296
01297
01298
01299
01300 bool YUMSourceImpl::checkCheckSum (const Pathname & filename, std::string csum_type, const std::string & csum)
01301 {
01302 MIL << "Checking checksum for " << filename << " as type: " << csum_type << "; value: " << csum << endl;
01303 if (str::toLower(csum_type) == "sha")
01304 {
01305 if (csum.size() == 40)
01306 csum_type = "sha1";
01307 else if (csum.size() == 64)
01308 csum_type = "sha256";
01309 DBG << "Checksum size is " << csum.size() << ", checksum type set to " << csum_type << endl;
01310 }
01311 ifstream st(filename.asString().c_str());
01312 std::string dig = Digest::digest (csum_type, st, 4096);
01313 if (dig == "")
01314 {
01315 ERR << "Cannot compute the checksum" << endl;
01316 return false;
01317 }
01318 dig = str::toLower (dig);
01319 bool ret = (dig == str::toLower(csum));
01320 if (ret)
01321 {
01322 MIL << "Checksums are the same" << endl;
01323 return true;
01324 }
01325 else
01326 {
01327 WAR << "Checksum missmatch: metadata: " << csum << "; real: " << dig << endl;
01328 return false;
01329 }
01330 return false;
01331 }
01332
01333 }
01335 }
01338 }