#include <apt-pkg/strutl.h>
#include <apt-pkg/fileutl.h>
#include <apt-pkg/md5.h>
-#include <apt-pkg/sha1.h>
-#include <apt-pkg/tagfile.h>
#include <apti18n.h>
#include <unistd.h>
#include <errno.h>
#include <string>
-#include <sstream>
#include <stdio.h>
/*}}}*/
Dequeue();
return;
}
-
+
Status = StatError;
Dequeue();
}
}
/*}}}*/
-
-// 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,
- string ExpectedMD5)
- : Item(Owner), RealURI(URI), ExpectedMD5(ExpectedMD5), 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);
-
- if(!FileExists(CurrentPackagesFile) ||
- !_config->FindB("Acquire::Diffs",true)) {
- // we don't have a pkg file or we don't want to queue
- if(Debug)
- std::clog << "No index file 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<DiffInfo> 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) {
- 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);
- }
- }
- }
-
- // no information how to get the patches, bail out
- if(!found) {
- if(Debug)
- std::clog << "Can't find a patch in the index file" << std::endl;
- // Failed will queue a big package file
- Failed("", NULL);
- } else {
- // queue the diffs
- new pkgAcqIndexDiffs(Owner, RealURI, Description, Desc.ShortDesc,
- ExpectedMD5, available_patches);
- Complete = false;
- Status = StatDone;
- Dequeue();
- return true;
- }
- }
-
- 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,
- ExpectedMD5);
-
- 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,
- string ExpectedMD5, vector<DiffInfo> diffs)
- : Item(Owner), RealURI(URI), ExpectedMD5(ExpectedMD5),
- available_patches(diffs)
-{
-
- DestFile = _config->FindDir("Dir::State::lists") + "partial/";
- DestFile += URItoFileName(URI);
-
- Debug = _config->FindB("Debug::pkgAcquire::Diffs",false);
-
- Desc.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,
- ExpectedMD5);
- 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);
-
- // do the final md5sum checking
- MD5Summation sum;
- FileFd Fd(DestFile, FileFd::ReadOnly);
- sum.AddFD(Fd.Fd(), Fd.Size());
- Fd.Close();
- string MD5 = (string)sum.Result();
-
- if (!ExpectedMD5.empty() && MD5 != ExpectedMD5)
- {
- 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 << ")"<<std::endl;
-
- // remove all patches until the next matching patch is found
- // this requires the Index file to be ordered
- for(vector<DiffInfo>::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 = 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;
- 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;
- 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);
-
- // see if there is more to download
- if(available_patches.size() > 0) {
- new pkgAcqIndexDiffs(Owner, RealURI, Description, Desc.ShortDesc,
- ExpectedMD5, 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)
+ string ExpectedMD5, string comprExt) :
+ Item(Owner), RealURI(URI), ExpectedMD5(ExpectedMD5)
{
Decompression = false;
Erase = false;
if(comprExt.empty())
{
// autoselect the compression method
- if(FileExists("/usr/bin/bzip2"))
+ if(FileExists("/bin/bzip2"))
CompressionExtension = ".bz2";
else
CompressionExtension = ".gz";
void pkgAcqIndex::Failed(string Message,pkgAcquire::MethodConfig *Cnf)
{
// no .bz2 found, retry with .gz
- if(Desc.URI.substr(Desc.URI.size()-3,Desc.URI.size()-1) == "bz2") {
+ if(Desc.URI.substr(Desc.URI.size()-3) == "bz2") {
Desc.URI = Desc.URI.substr(0,Desc.URI.size()-3) + "gz";
// retry with a gzip one
else
Local = true;
- string compExt = Desc.URI.substr(Desc.URI.size()-3,Desc.URI.size()-1);
+ string compExt = Desc.URI.substr(Desc.URI.size()-3);
char *decompProg;
if(compExt == "bz2")
decompProg = "bzip2";
const vector<IndexTarget*>* IndexTargets,
indexRecords* MetaIndexParser) :
Item(Owner), RealURI(URI), MetaIndexURI(MetaIndexURI),
- MetaIndexURIDesc(MetaIndexURIDesc), MetaIndexShortDesc(MetaIndexShortDesc)
+ MetaIndexURIDesc(MetaIndexURIDesc), MetaIndexShortDesc(MetaIndexShortDesc),
+ MetaIndexParser(MetaIndexParser), IndexTargets(IndexTargets)
{
- this->MetaIndexParser = MetaIndexParser;
- this->IndexTargets = IndexTargets;
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
// 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());
- }
}
QueueURI(Desc);
/*}}}*/
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 network failures (and re-authenticated?)
+ if(FileExists(DestFile))
+ Rename(DestFile,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);
string SigFile,
const vector<struct IndexTarget*>* IndexTargets,
indexRecords* MetaIndexParser) :
- Item(Owner), RealURI(URI), SigFile(SigFile)
+ Item(Owner), RealURI(URI), SigFile(SigFile), AuthPass(false),
+ MetaIndexParser(MetaIndexParser), IndexTargets(IndexTargets), IMSHit(false)
{
- this->AuthPass = false;
- this->MetaIndexParser = MetaIndexParser;
- this->IndexTargets = IndexTargets;
DestFile = _config->FindDir("Dir::State::lists") + "partial/";
DestFile += URItoFileName(URI);
return;
}
+ // see if the download was a IMSHit
+ IMSHit = StringToBool(LookupTag(Message,"IMS-Hit"),false);
+
Complete = true;
string FinalFile = _config->FindDir("Dir::State::lists");
return;
}
- if (!VerifyVendor())
+ if (!VerifyVendor(Message))
{
return;
}
}
// Queue Packages file
- new pkgAcqDiffIndex(Owner, (*Target)->URI, (*Target)->Description,
- (*Target)->ShortDesc, ExpectedIndexMD5);
+ new pkgAcqIndex(Owner, (*Target)->URI, (*Target)->Description,
+ (*Target)->ShortDesc, ExpectedIndexMD5);
}
}
-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?
// 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();
Transformed = "experimental";
}
- string::size_type pos = Transformed.rfind('/');
+ pos = Transformed.rfind('/');
if (pos != string::npos)
{
Transformed = Transformed.substr(0, pos);
{
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
}
}
+ // "allow-unauthenticated" restores apts old fetching behaviour
+ // that means that e.g. unauthenticated file:// uris are higher
+ // priority than authenticated http:// uris
+ if (_config->FindB("APT::Get::AllowUnauthenticated",false) == true)
+ Trusted = false;
+
// Select a source
if (QueueNext() == false && _error->PendingError() == false)
_error->Error(_("I wasn't able to locate file for the %s package. "
// ---------------------------------------------------------------------
/* The file is added to the queue */
pkgAcqFile::pkgAcqFile(pkgAcquire *Owner,string URI,string MD5,
- unsigned long Size,string Dsc,string ShortDesc) :
+ unsigned long Size,string Dsc,string ShortDesc,
+ const string &DestDir, const string &DestFilename) :
Item(Owner), Md5Hash(MD5)
{
Retries = _config->FindI("Acquire::Retries",0);
- DestFile = flNotDir(URI);
-
+ if(!DestFilename.empty())
+ DestFile = DestFilename;
+ else if(!DestDir.empty())
+ DestFile = DestDir + "/" + flNotDir(URI);
+ else
+ DestFile = flNotDir(URI);
+
// Create the item
Desc.URI = URI;
Desc.Description = Dsc;
else
PartialSize = Buf.st_size;
}
-
+
QueueURI(Desc);
}
/*}}}*/