X-Git-Url: https://git.saurik.com/apt.git/blobdiff_plain/a0f9b6bee8dae6eff15873db311f5a44cbb16fb3..2b0de496a89d9ba180853484fe55b0e437ab7059:/apt-pkg/acquire-item.cc?ds=sidebyside diff --git a/apt-pkg/acquire-item.cc b/apt-pkg/acquire-item.cc index 88c25de43..ae8ff2205 100644 --- a/apt-pkg/acquire-item.cc +++ b/apt-pkg/acquire-item.cc @@ -13,9 +13,6 @@ ##################################################################### */ /*}}}*/ // Include Files /*{{{*/ -#ifdef __GNUG__ -#pragma implementation "apt-pkg/acquire-item.h" -#endif #include #include #include @@ -24,6 +21,8 @@ #include #include #include +#include +#include #include @@ -31,6 +30,7 @@ #include #include #include +#include #include /*}}}*/ @@ -95,12 +95,13 @@ void pkgAcquire::Item::Start(string /*Message*/,unsigned long Size) // Acquire::Item::Done - Item downloaded OK /*{{{*/ // --------------------------------------------------------------------- /* */ -void pkgAcquire::Item::Done(string Message,unsigned long Size,string, +void pkgAcquire::Item::Done(string Message,unsigned long Size,string Hash, pkgAcquire::MethodConfig *Cnf) { // We just downloaded something.. string FileName = LookupTag(Message,"Filename"); - if (Complete == false && FileName == DestFile) + // we only inform the Log class if it was actually not a local thing + if (Complete == false && !Local && FileName == DestFile) { if (Owner->Log != 0) Owner->Log->Fetched(Size,atoi(LookupTag(Message,"Resume-Point","0").c_str())); @@ -131,14 +132,427 @@ void pkgAcquire::Item::Rename(string From,string To) } /*}}}*/ + +// AcqDiffIndex::AcqDiffIndex - Constructor +// --------------------------------------------------------------------- +/* Get the DiffIndex file first and see if there are patches availabe + * If so, create a pkgAcqIndexDiffs fetcher that will get and apply the + * patches. If anything goes wrong in that process, it will fall back to + * the original packages file + */ +pkgAcqDiffIndex::pkgAcqDiffIndex(pkgAcquire *Owner, + string URI,string URIDesc,string ShortDesc, + HashString ExpectedHash) + : Item(Owner), RealURI(URI), ExpectedHash(ExpectedHash), + Description(URIDesc) +{ + + Debug = _config->FindB("Debug::pkgAcquire::Diffs",false); + + Desc.Description = URIDesc + "/DiffIndex"; + Desc.Owner = this; + Desc.ShortDesc = ShortDesc; + Desc.URI = URI + ".diff/Index"; + + DestFile = _config->FindDir("Dir::State::lists") + "partial/"; + DestFile += URItoFileName(URI) + string(".DiffIndex"); + + if(Debug) + std::clog << "pkgAcqDiffIndex: " << Desc.URI << std::endl; + + // look for the current package file + CurrentPackagesFile = _config->FindDir("Dir::State::lists"); + CurrentPackagesFile += URItoFileName(RealURI); + + // FIXME: this file:/ check is a hack to prevent fetching + // from local sources. this is really silly, and + // should be fixed cleanly as soon as possible + if(!FileExists(CurrentPackagesFile) || + Desc.URI.substr(0,strlen("file:/")) == "file:/") + { + // we don't have a pkg file or we don't want to queue + if(Debug) + std::clog << "No index file, local or canceld by user" << std::endl; + Failed("", NULL); + return; + } + + if(Debug) + std::clog << "pkgAcqIndexDiffs::pkgAcqIndexDiffs(): " + << CurrentPackagesFile << std::endl; + + QueueURI(Desc); + +} + +// AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/ +// --------------------------------------------------------------------- +/* The only header we use is the last-modified header. */ +string pkgAcqDiffIndex::Custom600Headers() +{ + string Final = _config->FindDir("Dir::State::lists"); + Final += URItoFileName(RealURI) + string(".IndexDiff"); + + if(Debug) + std::clog << "Custom600Header-IMS: " << Final << std::endl; + + struct stat Buf; + if (stat(Final.c_str(),&Buf) != 0) + return "\nIndex-File: true"; + + return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf.st_mtime); +} + + +bool pkgAcqDiffIndex::ParseDiffIndex(string IndexDiffFile) +{ + if(Debug) + std::clog << "pkgAcqIndexDiffs::ParseIndexDiff() " << IndexDiffFile + << std::endl; + + pkgTagSection Tags; + string ServerSha1; + vector available_patches; + + FileFd Fd(IndexDiffFile,FileFd::ReadOnly); + pkgTagFile TF(&Fd); + if (_error->PendingError() == true) + return false; + + if(TF.Step(Tags) == true) + { + string local_sha1; + bool found = false; + DiffInfo d; + string size; + + string tmp = Tags.FindS("SHA1-Current"); + std::stringstream ss(tmp); + ss >> ServerSha1; + + FileFd fd(CurrentPackagesFile, FileFd::ReadOnly); + SHA1Summation SHA1; + SHA1.AddFD(fd.Fd(), fd.Size()); + local_sha1 = string(SHA1.Result()); + + if(local_sha1 == ServerSha1) + { + // we have the same sha1 as the server + if(Debug) + std::clog << "Package file is up-to-date" << std::endl; + // set found to true, this will queue a pkgAcqIndexDiffs with + // a empty availabe_patches + found = true; + } + else + { + if(Debug) + std::clog << "SHA1-Current: " << ServerSha1 << std::endl; + + // check the historie and see what patches we need + string history = Tags.FindS("SHA1-History"); + std::stringstream hist(history); + while(hist >> d.sha1 >> size >> d.file) + { + d.size = atoi(size.c_str()); + // read until the first match is found + if(d.sha1 == local_sha1) + found=true; + // from that point on, we probably need all diffs + if(found) + { + if(Debug) + std::clog << "Need to get diff: " << d.file << std::endl; + available_patches.push_back(d); + } + } + } + + // we have something, queue the next diff + if(found) + { + // queue the diffs + string::size_type last_space = Description.rfind(" "); + if(last_space != string::npos) + Description.erase(last_space, Description.size()-last_space); + new pkgAcqIndexDiffs(Owner, RealURI, Description, Desc.ShortDesc, + ExpectedHash, available_patches); + Complete = false; + Status = StatDone; + Dequeue(); + return true; + } + } + + // Nothing found, report and return false + // Failing here is ok, if we return false later, the full + // IndexFile is queued + if(Debug) + std::clog << "Can't find a patch in the index file" << std::endl; + return false; +} + +void pkgAcqDiffIndex::Failed(string Message,pkgAcquire::MethodConfig *Cnf) +{ + if(Debug) + std::clog << "pkgAcqDiffIndex failed: " << Desc.URI << std::endl + << "Falling back to normal index file aquire" << std::endl; + + new pkgAcqIndex(Owner, RealURI, Description, Desc.ShortDesc, + ExpectedHash); + + Complete = false; + Status = StatDone; + Dequeue(); +} + +void pkgAcqDiffIndex::Done(string Message,unsigned long Size,string Md5Hash, + pkgAcquire::MethodConfig *Cnf) +{ + if(Debug) + std::clog << "pkgAcqDiffIndex::Done(): " << Desc.URI << std::endl; + + Item::Done(Message,Size,Md5Hash,Cnf); + + string FinalFile; + FinalFile = _config->FindDir("Dir::State::lists")+URItoFileName(RealURI); + + // sucess in downloading the index + // rename the index + FinalFile += string(".IndexDiff"); + if(Debug) + std::clog << "Renaming: " << DestFile << " -> " << FinalFile + << std::endl; + Rename(DestFile,FinalFile); + chmod(FinalFile.c_str(),0644); + DestFile = FinalFile; + + if(!ParseDiffIndex(DestFile)) + return Failed("", NULL); + + Complete = true; + Status = StatDone; + Dequeue(); + return; +} + + + +// AcqIndexDiffs::AcqIndexDiffs - Constructor +// --------------------------------------------------------------------- +/* The package diff is added to the queue. one object is constructed + * for each diff and the index + */ +pkgAcqIndexDiffs::pkgAcqIndexDiffs(pkgAcquire *Owner, + string URI,string URIDesc,string ShortDesc, + HashString ExpectedHash, + vector diffs) + : Item(Owner), RealURI(URI), ExpectedHash(ExpectedHash), + available_patches(diffs) +{ + + DestFile = _config->FindDir("Dir::State::lists") + "partial/"; + DestFile += URItoFileName(URI); + + Debug = _config->FindB("Debug::pkgAcquire::Diffs",false); + + Description = URIDesc; + Desc.Owner = this; + Desc.ShortDesc = ShortDesc; + + if(available_patches.size() == 0) + { + // we are done (yeah!) + Finish(true); + } + else + { + // get the next diff + State = StateFetchDiff; + QueueNextDiff(); + } +} + + +void pkgAcqIndexDiffs::Failed(string Message,pkgAcquire::MethodConfig *Cnf) +{ + if(Debug) + std::clog << "pkgAcqIndexDiffs failed: " << Desc.URI << std::endl + << "Falling back to normal index file aquire" << std::endl; + new pkgAcqIndex(Owner, RealURI, Description,Desc.ShortDesc, + ExpectedHash); + Finish(); +} + + +// helper that cleans the item out of the fetcher queue +void pkgAcqIndexDiffs::Finish(bool allDone) +{ + // we restore the original name, this is required, otherwise + // the file will be cleaned + if(allDone) + { + DestFile = _config->FindDir("Dir::State::lists"); + DestFile += URItoFileName(RealURI); + + if(!ExpectedHash.empty() && !ExpectedHash.VerifyFile(DestFile)) + { + Status = StatAuthError; + ErrorText = _("MD5Sum mismatch"); + Rename(DestFile,DestFile + ".FAILED"); + Dequeue(); + return; + } + + // this is for the "real" finish + Complete = true; + Status = StatDone; + Dequeue(); + if(Debug) + std::clog << "\n\nallDone: " << DestFile << "\n" << std::endl; + return; + } + + if(Debug) + std::clog << "Finishing: " << Desc.URI << std::endl; + Complete = false; + Status = StatDone; + Dequeue(); + return; +} + + + +bool pkgAcqIndexDiffs::QueueNextDiff() +{ + + // calc sha1 of the just patched file + string FinalFile = _config->FindDir("Dir::State::lists"); + FinalFile += URItoFileName(RealURI); + + FileFd fd(FinalFile, FileFd::ReadOnly); + SHA1Summation SHA1; + SHA1.AddFD(fd.Fd(), fd.Size()); + string local_sha1 = string(SHA1.Result()); + if(Debug) + std::clog << "QueueNextDiff: " + << FinalFile << " (" << local_sha1 << ")"<::iterator I=available_patches.begin(); + available_patches.size() > 0 && + I != available_patches.end() && + (*I).sha1 != local_sha1; + I++) + { + available_patches.erase(I); + } + + // error checking and falling back if no patch was found + if(available_patches.size() == 0) + { + Failed("", NULL); + return false; + } + + // queue the right diff + Desc.URI = string(RealURI) + ".diff/" + available_patches[0].file + ".gz"; + Desc.Description = Description + " " + available_patches[0].file + string(".pdiff"); + DestFile = _config->FindDir("Dir::State::lists") + "partial/"; + DestFile += URItoFileName(RealURI + ".diff/" + available_patches[0].file); + + if(Debug) + std::clog << "pkgAcqIndexDiffs::QueueNextDiff(): " << Desc.URI << std::endl; + + QueueURI(Desc); + + return true; +} + + + +void pkgAcqIndexDiffs::Done(string Message,unsigned long Size,string Md5Hash, + pkgAcquire::MethodConfig *Cnf) +{ + if(Debug) + std::clog << "pkgAcqIndexDiffs::Done(): " << Desc.URI << std::endl; + + Item::Done(Message,Size,Md5Hash,Cnf); + + string FinalFile; + FinalFile = _config->FindDir("Dir::State::lists")+URItoFileName(RealURI); + + // sucess in downloading a diff, enter ApplyDiff state + if(State == StateFetchDiff) + { + + if(Debug) + std::clog << "Sending to gzip method: " << FinalFile << std::endl; + + string FileName = LookupTag(Message,"Filename"); + State = StateUnzipDiff; + Local = true; + Desc.URI = "gzip:" + FileName; + DestFile += ".decomp"; + QueueURI(Desc); + Mode = "gzip"; + return; + } + + // sucess in downloading a diff, enter ApplyDiff state + if(State == StateUnzipDiff) + { + + // rred excepts the patch as $FinalFile.ed + Rename(DestFile,FinalFile+".ed"); + + if(Debug) + std::clog << "Sending to rred method: " << FinalFile << std::endl; + + State = StateApplyDiff; + Local = true; + Desc.URI = "rred:" + FinalFile; + QueueURI(Desc); + Mode = "rred"; + return; + } + + + // success in download/apply a diff, queue next (if needed) + if(State == StateApplyDiff) + { + // remove the just applied patch + available_patches.erase(available_patches.begin()); + + // move into place + if(Debug) + { + std::clog << "Moving patched file in place: " << std::endl + << DestFile << " -> " << FinalFile << std::endl; + } + Rename(DestFile,FinalFile); + chmod(FinalFile.c_str(),0644); + + // see if there is more to download + if(available_patches.size() > 0) { + new pkgAcqIndexDiffs(Owner, RealURI, Description, Desc.ShortDesc, + ExpectedHash, available_patches); + return Finish(); + } else + return Finish(true); + } +} + + // AcqIndex::AcqIndex - Constructor /*{{{*/ // --------------------------------------------------------------------- /* The package file is added to the queue and a second class is instantiated to fetch the revision file */ pkgAcqIndex::pkgAcqIndex(pkgAcquire *Owner, string URI,string URIDesc,string ShortDesc, - string ExpectedMD5, string comprExt) : - Item(Owner), RealURI(URI), ExpectedMD5(ExpectedMD5) + HashString ExpectedHash, string comprExt) + : Item(Owner), RealURI(URI), ExpectedHash(ExpectedHash) { Decompression = false; Erase = false; @@ -149,14 +563,14 @@ pkgAcqIndex::pkgAcqIndex(pkgAcquire *Owner, if(comprExt.empty()) { // autoselect the compression method - if(FileExists("/usr/bin/bzip2")) + if(FileExists("/bin/bzip2")) CompressionExtension = ".bz2"; else CompressionExtension = ".gz"; } else { - CompressionExtension = comprExt; + CompressionExtension = (comprExt == "plain" ? "" : comprExt); } - Desc.URI = URI + CompressionExtension; + Desc.URI = URI + CompressionExtension; Desc.Description = URIDesc; Desc.Owner = this; @@ -183,20 +597,37 @@ string pkgAcqIndex::Custom600Headers() void pkgAcqIndex::Failed(string Message,pkgAcquire::MethodConfig *Cnf) { + bool descChanged = false; // no .bz2 found, retry with .gz if(Desc.URI.substr(Desc.URI.size()-3) == "bz2") { - Desc.URI = Desc.URI.substr(0,Desc.URI.size()-3) + "gz"; + Desc.URI = Desc.URI.substr(0,Desc.URI.size()-3) + "gz"; + + new pkgAcqIndex(Owner, RealURI, Desc.Description,Desc.ShortDesc, + ExpectedHash, string(".gz")); + descChanged = true; + } + // no .gz found, retry with uncompressed + else if(Desc.URI.substr(Desc.URI.size()-2) == "gz") { + Desc.URI = Desc.URI.substr(0,Desc.URI.size()-2); - // retry with a gzip one - new pkgAcqIndex(Owner, RealURI, Desc.Description,Desc.ShortDesc, - ExpectedMD5, string(".gz")); + new pkgAcqIndex(Owner, RealURI, Desc.Description,Desc.ShortDesc, + ExpectedHash, string("plain")); + descChanged = true; + } + if (descChanged) { Status = StatDone; Complete = false; Dequeue(); return; } - + // on decompression failure, remove bad versions in partial/ + if(Decompression && Erase) { + string s = _config->FindDir("Dir::State::lists") + "partial/"; + s += URItoFileName(RealURI); + unlink(s.c_str()); + } + Item::Failed(Message,Cnf); } @@ -208,32 +639,23 @@ void pkgAcqIndex::Failed(string Message,pkgAcquire::MethodConfig *Cnf) to the uncompressed version of the file. If this is so the file is copied into the partial directory. In all other cases the file is decompressed with a gzip uri. */ -void pkgAcqIndex::Done(string Message,unsigned long Size,string MD5, +void pkgAcqIndex::Done(string Message,unsigned long Size,string Hash, pkgAcquire::MethodConfig *Cfg) { - Item::Done(Message,Size,MD5,Cfg); + Item::Done(Message,Size,Hash,Cfg); if (Decompression == true) { if (_config->FindB("Debug::pkgAcquire::Auth", false)) { - std::cerr << std::endl << RealURI << ": Computed MD5: " << MD5; - std::cerr << " Expected MD5: " << ExpectedMD5 << std::endl; - } - - if (MD5.empty()) - { - MD5Summation sum; - FileFd Fd(DestFile, FileFd::ReadOnly); - sum.AddFD(Fd.Fd(), Fd.Size()); - Fd.Close(); - MD5 = (string)sum.Result(); + std::cerr << std::endl << RealURI << ": Computed Hash: " << Hash; + std::cerr << " Expected Hash: " << ExpectedHash.toStr() << std::endl; } - if (!ExpectedMD5.empty() && MD5 != ExpectedMD5) + if (!ExpectedHash.empty() && ExpectedHash.toStr() != Hash) { Status = StatAuthError; - ErrorText = _("MD5Sum mismatch"); + ErrorText = _("Hash Sum mismatch"); Rename(DestFile,DestFile + ".FAILED"); return; } @@ -264,7 +686,6 @@ void pkgAcqIndex::Done(string Message,unsigned long Size,string MD5, // The files timestamp matches if (StringToBool(LookupTag(Message,"Alt-IMS-Hit"),false) == true) return; - Decompression = true; Local = true; DestFile += ".decomp"; @@ -290,12 +711,15 @@ void pkgAcqIndex::Done(string Message,unsigned long Size,string MD5, else Local = true; - string compExt = Desc.URI.substr(Desc.URI.size()-3); - char *decompProg; + string compExt = flExtension(flNotDir(URI(Desc.URI).Path)); + const char *decompProg; if(compExt == "bz2") decompProg = "bzip2"; - else if(compExt == ".gz") + else if(compExt == "gz") decompProg = "gzip"; + // flExtensions returns the full name if no extension is found + else if(compExt == flNotDir(URI(Desc.URI).Path)) + decompProg = "copy"; else { _error->Error("Unsupported extension: %s", compExt.c_str()); return; @@ -308,6 +732,35 @@ void pkgAcqIndex::Done(string Message,unsigned long Size,string MD5, Mode = decompProg; } +// AcqIndexTrans::pkgAcqIndexTrans - Constructor /*{{{*/ +// --------------------------------------------------------------------- +/* The Translation file is added to the queue */ +pkgAcqIndexTrans::pkgAcqIndexTrans(pkgAcquire *Owner, + string URI,string URIDesc,string ShortDesc) + : pkgAcqIndex(Owner, URI, URIDesc, ShortDesc, HashString(), "") +{ +} + + /*}}}*/ +// AcqIndexTrans::Failed - Silence failure messages for missing files /*{{{*/ +// --------------------------------------------------------------------- +/* */ +void pkgAcqIndexTrans::Failed(string Message,pkgAcquire::MethodConfig *Cnf) +{ + if (Cnf->LocalOnly == true || + StringToBool(LookupTag(Message,"Transient-Failure"),false) == false) + { + // Ignore this + Status = StatDone; + Complete = false; + Dequeue(); + return; + } + + Item::Failed(Message,Cnf); +} + /*}}}*/ + pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire *Owner, string URI,string URIDesc,string ShortDesc, string MetaIndexURI, string MetaIndexURIDesc, @@ -321,8 +774,9 @@ pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire *Owner, DestFile = _config->FindDir("Dir::State::lists") + "partial/"; DestFile += URItoFileName(URI); - // remove any partial downloaded sig-file. it may confuse proxies - // and is too small to warrant a partial download anyway + // remove any partial downloaded sig-file in partial/. + // it may confuse proxies and is too small to warrant a + // partial download anyway unlink(DestFile.c_str()); // Create the item @@ -330,22 +784,19 @@ pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire *Owner, Desc.Owner = this; Desc.ShortDesc = ShortDesc; Desc.URI = URI; - string Final = _config->FindDir("Dir::State::lists"); Final += URItoFileName(RealURI); struct stat Buf; if (stat(Final.c_str(),&Buf) == 0) { - // File was already in place. It needs to be re-verified - // because Release might have changed, so Move it into partial - Rename(Final,DestFile); - // unlink the file and do not try to use I-M-S and Last-Modified - // if the users proxy is broken - if(_config->FindB("Acquire::BrokenProxy", false) == true) { - std::cerr << "forcing re-get of the signature file as requested" << std::endl; - unlink(DestFile.c_str()); - } + // File was already in place. It needs to be re-downloaded/verified + // because Release might have changed, we do give it a differnt + // name than DestFile because otherwise the http method will + // send If-Range requests and there are too many broken servers + // out there that do not understand them + LastGoodSig = DestFile+".reverify"; + Rename(Final,LastGoodSig); } QueueURI(Desc); @@ -357,7 +808,7 @@ pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire *Owner, string pkgAcqMetaSig::Custom600Headers() { struct stat Buf; - if (stat(DestFile.c_str(),&Buf) != 0) + if (stat(LastGoodSig.c_str(),&Buf) != 0) return "\nIndex-File: true"; return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf.st_mtime); @@ -387,6 +838,12 @@ void pkgAcqMetaSig::Done(string Message,unsigned long Size,string MD5, Complete = true; + // put the last known good file back on i-m-s hit (it will + // be re-verified again) + // Else do nothing, we have the new file in DestFile then + if(StringToBool(LookupTag(Message,"IMS-Hit"),false) == true) + Rename(LastGoodSig, DestFile); + // queue a pkgAcqMetaIndex to be verified against the sig we just retrieved new pkgAcqMetaIndex(Owner, MetaIndexURI, MetaIndexURIDesc, MetaIndexShortDesc, DestFile, IndexTargets, MetaIndexParser); @@ -395,18 +852,24 @@ void pkgAcqMetaSig::Done(string Message,unsigned long Size,string MD5, /*}}}*/ void pkgAcqMetaSig::Failed(string Message,pkgAcquire::MethodConfig *Cnf) { - // Delete any existing sigfile, so that this source isn't - // mistakenly trusted string Final = _config->FindDir("Dir::State::lists") + URItoFileName(RealURI); - unlink(Final.c_str()); - // if we get a timeout if fail - if(LookupTag(Message,"FailReason") == "Timeout" || - LookupTag(Message,"FailReason") == "TmpResolveFailure") { + // if we get a network error we fail gracefully + if(Status == StatTransientNetworkError) + { Item::Failed(Message,Cnf); + // move the sigfile back on transient network failures + if(FileExists(DestFile)) + Rename(LastGoodSig,Final); + + // set the status back to , Item::Failed likes to reset it + Status = pkgAcquire::Item::StatTransientNetworkError; return; } + // Delete any existing sigfile when the acquire failed + unlink(Final.c_str()); + // queue a pkgAcqMetaIndex with no sigfile new pkgAcqMetaIndex(Owner, MetaIndexURI, MetaIndexURIDesc, MetaIndexShortDesc, "", IndexTargets, MetaIndexParser); @@ -429,8 +892,8 @@ pkgAcqMetaIndex::pkgAcqMetaIndex(pkgAcquire *Owner, string SigFile, const vector* IndexTargets, indexRecords* MetaIndexParser) : - Item(Owner), RealURI(URI), SigFile(SigFile), AuthPass(false), - MetaIndexParser(MetaIndexParser), IndexTargets(IndexTargets) + Item(Owner), RealURI(URI), SigFile(SigFile), IndexTargets(IndexTargets), + MetaIndexParser(MetaIndexParser), AuthPass(false), IMSHit(false) { DestFile = _config->FindDir("Dir::State::lists") + "partial/"; DestFile += URItoFileName(URI); @@ -460,10 +923,10 @@ string pkgAcqMetaIndex::Custom600Headers() return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf.st_mtime); } -void pkgAcqMetaIndex::Done(string Message,unsigned long Size,string MD5, +void pkgAcqMetaIndex::Done(string Message,unsigned long Size,string Hash, pkgAcquire::MethodConfig *Cfg) { - Item::Done(Message,Size,MD5,Cfg); + Item::Done(Message,Size,Hash,Cfg); // MetaIndexes are done in two passes: one to download the // metaindex with an appropriate method, and a second to verify it @@ -523,17 +986,21 @@ void pkgAcqMetaIndex::RetrievalDone(string Message) return; } + // see if the download was a IMSHit + IMSHit = StringToBool(LookupTag(Message,"IMS-Hit"),false); Complete = true; string FinalFile = _config->FindDir("Dir::State::lists"); FinalFile += URItoFileName(RealURI); - // The files timestamp matches - if (StringToBool(LookupTag(Message,"IMS-Hit"),false) == false) - { - // Move it into position + // If we get a IMS hit we can remove the empty file in partial + // othersie we move the file in place + if (IMSHit) + unlink(DestFile.c_str()); + else Rename(DestFile,FinalFile); - } + + chmod(FinalFile.c_str(),0644); DestFile = FinalFile; } @@ -551,7 +1018,7 @@ void pkgAcqMetaIndex::AuthDone(string Message) return; } - if (!VerifyVendor()) + if (!VerifyVendor(Message)) { return; } @@ -577,7 +1044,7 @@ void pkgAcqMetaIndex::QueueIndexes(bool verify) Target != IndexTargets->end(); Target++) { - string ExpectedIndexMD5; + HashString ExpectedIndexHash; if (verify) { const indexRecords::checkSum *Record = MetaIndexParser->Lookup((*Target)->MetaKey); @@ -588,28 +1055,33 @@ void pkgAcqMetaIndex::QueueIndexes(bool verify) + (*Target)->MetaKey + " in Meta-index file (malformed Release file?)"; return; } - ExpectedIndexMD5 = Record->MD5Hash; + ExpectedIndexHash = Record->Hash; if (_config->FindB("Debug::pkgAcquire::Auth", false)) { std::cerr << "Queueing: " << (*Target)->URI << std::endl; - std::cerr << "Expected MD5: " << ExpectedIndexMD5 << std::endl; + std::cerr << "Expected Hash: " << ExpectedIndexHash.toStr() << std::endl; } - if (ExpectedIndexMD5.empty()) + if (ExpectedIndexHash.empty()) { Status = StatAuthError; - ErrorText = "Unable to find MD5 sum for " + ErrorText = "Unable to find hash sum for " + (*Target)->MetaKey + " in Meta-index file"; return; } } - // Queue Packages file - new pkgAcqIndex(Owner, (*Target)->URI, (*Target)->Description, - (*Target)->ShortDesc, ExpectedIndexMD5); + // Queue Packages file (either diff or full packages files, depending + // on the users option) + if(_config->FindB("Acquire::PDiffs",true) == true) + new pkgAcqDiffIndex(Owner, (*Target)->URI, (*Target)->Description, + (*Target)->ShortDesc, ExpectedIndexHash); + else + new pkgAcqIndex(Owner, (*Target)->URI, (*Target)->Description, + (*Target)->ShortDesc, ExpectedIndexHash); } } -bool pkgAcqMetaIndex::VerifyVendor() +bool pkgAcqMetaIndex::VerifyVendor(string Message) { // // Maybe this should be made available from above so we don't have // // to read and parse it every time? @@ -634,6 +1106,22 @@ bool pkgAcqMetaIndex::VerifyVendor() // break; // } // } + string::size_type pos; + + // check for missing sigs (that where not fatal because otherwise we had + // bombed earlier) + string missingkeys; + string msg = _("There is no public key available for the " + "following key IDs:\n"); + pos = Message.find("NO_PUBKEY "); + if (pos != std::string::npos) + { + string::size_type start = pos+strlen("NO_PUBKEY "); + string Fingerprint = Message.substr(start, Message.find("\n")-start); + missingkeys += (Fingerprint); + } + if(!missingkeys.empty()) + _error->Warning("%s", string(msg+missingkeys).c_str()); string Transformed = MetaIndexParser->GetExpectedDist(); @@ -642,7 +1130,7 @@ bool pkgAcqMetaIndex::VerifyVendor() Transformed = "experimental"; } - string::size_type pos = Transformed.rfind('/'); + pos = Transformed.rfind('/'); if (pos != string::npos) { Transformed = Transformed.substr(0, pos); @@ -688,10 +1176,30 @@ void pkgAcqMetaIndex::Failed(string Message,pkgAcquire::MethodConfig *Cnf) { if (AuthPass == true) { - // gpgv method failed + // if we fail the authentication but got the file via a IMS-Hit + // this means that the file wasn't downloaded and that it might be + // just stale (server problem, proxy etc). we delete what we have + // queue it again without i-m-s + // alternatively we could just unlink the file and let the user try again + if (IMSHit) + { + Complete = false; + Local = false; + AuthPass = false; + unlink(DestFile.c_str()); + + DestFile = _config->FindDir("Dir::State::lists") + "partial/"; + DestFile += URItoFileName(RealURI); + Desc.URI = RealURI; + QueueURI(Desc); + return; + } + + // gpgv method failed _error->Warning("GPG error: %s: %s", Desc.Description.c_str(), LookupTag(Message,"Message").c_str()); + } // No Release file was present, or verification failed, so fall @@ -809,7 +1317,12 @@ bool pkgAcqArchive::QueueNext() return false; string PkgFile = Parse.FileName(); - MD5 = Parse.MD5Hash(); + if(Parse.SHA256Hash() != "") + ExpectedHash = HashString("SHA256", Parse.SHA256Hash()); + else if (Parse.SHA1Hash() != "") + ExpectedHash = HashString("SHA1", Parse.SHA1Hash()); + else + ExpectedHash = HashString("MD5Sum", Parse.MD5Hash()); if (PkgFile.empty() == true) return _error->Error(_("The package index files are corrupted. No Filename: " "field for package %s."), @@ -889,10 +1402,10 @@ bool pkgAcqArchive::QueueNext() // AcqArchive::Done - Finished fetching /*{{{*/ // --------------------------------------------------------------------- /* */ -void pkgAcqArchive::Done(string Message,unsigned long Size,string Md5Hash, +void pkgAcqArchive::Done(string Message,unsigned long Size,string CalcHash, pkgAcquire::MethodConfig *Cfg) { - Item::Done(Message,Size,Md5Hash,Cfg); + Item::Done(Message,Size,CalcHash,Cfg); // Check the size if (Size != Version->Size) @@ -902,17 +1415,14 @@ void pkgAcqArchive::Done(string Message,unsigned long Size,string Md5Hash, return; } - // Check the md5 - if (Md5Hash.empty() == false && MD5.empty() == false) + // Check the hash + if(ExpectedHash.toStr() != CalcHash) { - if (Md5Hash != MD5) - { - Status = StatError; - ErrorText = _("MD5Sum mismatch"); - if(FileExists(DestFile)) - Rename(DestFile,DestFile + ".FAILED"); - return; - } + Status = StatError; + ErrorText = _("Hash Sum mismatch"); + if(FileExists(DestFile)) + Rename(DestFile,DestFile + ".FAILED"); + return; } // Grab the output filename @@ -1004,10 +1514,10 @@ void pkgAcqArchive::Finished() // AcqFile::pkgAcqFile - Constructor /*{{{*/ // --------------------------------------------------------------------- /* The file is added to the queue */ -pkgAcqFile::pkgAcqFile(pkgAcquire *Owner,string URI,string MD5, +pkgAcqFile::pkgAcqFile(pkgAcquire *Owner,string URI,string Hash, unsigned long Size,string Dsc,string ShortDesc, const string &DestDir, const string &DestFilename) : - Item(Owner), Md5Hash(MD5) + Item(Owner), ExpectedHash(Hash) { Retries = _config->FindI("Acquire::Retries",0); @@ -1037,30 +1547,27 @@ pkgAcqFile::pkgAcqFile(pkgAcquire *Owner,string URI,string MD5, else PartialSize = Buf.st_size; } - + QueueURI(Desc); } /*}}}*/ // AcqFile::Done - Item downloaded OK /*{{{*/ // --------------------------------------------------------------------- /* */ -void pkgAcqFile::Done(string Message,unsigned long Size,string MD5, +void pkgAcqFile::Done(string Message,unsigned long Size,string CalcHash, pkgAcquire::MethodConfig *Cnf) { - // Check the md5 - if (Md5Hash.empty() == false && MD5.empty() == false) + Item::Done(Message,Size,CalcHash,Cnf); + + // Check the hash + if(!ExpectedHash.empty() && ExpectedHash.toStr() != CalcHash) { - if (Md5Hash != MD5) - { - Status = StatError; - ErrorText = "MD5Sum mismatch"; - Rename(DestFile,DestFile + ".FAILED"); - return; - } + Status = StatError; + ErrorText = "Hash Sum mismatch"; + Rename(DestFile,DestFile + ".FAILED"); + return; } - Item::Done(Message,Size,MD5,Cnf); - string FileName = LookupTag(Message,"Filename"); if (FileName.empty() == true) {