/*}}}*/
// Acquire::Item::Item - Constructor /*{{{*/
-pkgAcquire::Item::Item(pkgAcquire *Owner, HashStringList const &ExpectedHashes) :
- Owner(Owner), FileSize(0), PartialSize(0), Mode(0), ID(0), Complete(false),
- Local(false), QueueCounter(0), ExpectedAdditionalItems(0),
- ExpectedHashes(ExpectedHashes)
+pkgAcquire::Item::Item(pkgAcquire *Owner,
+ HashStringList const &ExpectedHashes,
+ unsigned long TransactionID)
+ : Owner(Owner), FileSize(0), PartialSize(0), Mode(0), ID(0), Complete(false),
+ Local(false), QueueCounter(0), TransactionID(TransactionID),
+ ExpectedAdditionalItems(0), ExpectedHashes(ExpectedHashes)
{
Owner->Add(this);
Status = StatIdle;
void pkgAcquire::Item::Failed(string Message,pkgAcquire::MethodConfig *Cnf)
{
Status = StatIdle;
- ErrorText = LookupTag(Message,"Message");
+ if(ErrorText == "")
+ ErrorText = LookupTag(Message,"Message");
UsedMirror = LookupTag(Message,"UsedMirror");
if (QueueCounter <= 1)
{
{
// We just downloaded something..
string FileName = LookupTag(Message,"Filename");
- UsedMirror = LookupTag(Message,"UsedMirror");
+ UsedMirror = LookupTag(Message,"UsedMirror");
if (Complete == false && !Local && FileName == DestFile)
{
if (Owner->Log != 0)
// ---------------------------------------------------------------------
/* Get a sub-index file based on checksums from a 'master' file and
possibly query additional files */
-pkgAcqSubIndex::pkgAcqSubIndex(pkgAcquire *Owner, string const &URI,
- string const &URIDesc, string const &ShortDesc,
- HashStringList const &ExpectedHashes)
- : Item(Owner, ExpectedHashes)
+pkgAcqSubIndex::pkgAcqSubIndex(pkgAcquire *Owner,
+ unsigned long TransactionID,
+ string const &URI,
+ string const &URIDesc, string const &ShortDesc,
+ HashStringList const &ExpectedHashes)
+ : Item(Owner, ExpectedHashes, TransactionID)
{
/* XXX: Beware: Currently this class does nothing (of value) anymore ! */
Debug = _config->FindB("Debug::pkgAcquire::SubIndex",false);
* the original packages file
*/
pkgAcqDiffIndex::pkgAcqDiffIndex(pkgAcquire *Owner,
+ unsigned long TransactionID,
IndexTarget const * const Target,
HashStringList const &ExpectedHashes,
indexRecords *MetaIndexParser)
- : pkgAcqBaseIndex(Owner, Target, ExpectedHashes, MetaIndexParser)
+ : pkgAcqBaseIndex(Owner, TransactionID, Target, ExpectedHashes,
+ MetaIndexParser)
{
Debug = _config->FindB("Debug::pkgAcquire::Diffs",false);
std::clog << "Package file is up-to-date" << std::endl;
// list cleanup needs to know that this file as well as the already
// present index is ours, so we create an empty diff to save it for us
- new pkgAcqIndexDiffs(Owner, Target, ExpectedHashes, MetaIndexParser,
+ new pkgAcqIndexDiffs(Owner, TransactionID, Target,
+ ExpectedHashes, MetaIndexParser,
ServerSha1, available_patches);
return true;
}
if (pdiff_merge == false)
{
- new pkgAcqIndexDiffs(Owner, Target, ExpectedHashes, MetaIndexParser,
+ new pkgAcqIndexDiffs(Owner, TransactionID, Target, ExpectedHashes,
+ MetaIndexParser,
ServerSha1, available_patches);
}
else
{
std::vector<pkgAcqIndexMergeDiffs*> *diffs = new std::vector<pkgAcqIndexMergeDiffs*>(available_patches.size());
for(size_t i = 0; i < available_patches.size(); ++i)
- (*diffs)[i] = new pkgAcqIndexMergeDiffs(Owner, Target,
+ (*diffs)[i] = new pkgAcqIndexMergeDiffs(Owner,
+ TransactionID,
+ Target,
ExpectedHashes,
MetaIndexParser,
available_patches[i],
std::clog << "pkgAcqDiffIndex failed: " << Desc.URI << " with " << Message << std::endl
<< "Falling back to normal index file acquire" << std::endl;
- new pkgAcqIndex(Owner, Target, ExpectedHashes, MetaIndexParser);
+ new pkgAcqIndex(Owner, TransactionID, Target, ExpectedHashes, MetaIndexParser);
Complete = false;
Status = StatDone;
* for each diff and the index
*/
pkgAcqIndexDiffs::pkgAcqIndexDiffs(pkgAcquire *Owner,
+ unsigned long TransactionID,
struct IndexTarget const * const Target,
HashStringList const &ExpectedHashes,
indexRecords *MetaIndexParser,
string ServerSha1,
vector<DiffInfo> diffs)
- : pkgAcqBaseIndex(Owner, Target, ExpectedHashes, MetaIndexParser),
+ : pkgAcqBaseIndex(Owner, TransactionID, Target, ExpectedHashes, MetaIndexParser),
available_patches(diffs), ServerSha1(ServerSha1)
{
if(Debug)
std::clog << "pkgAcqIndexDiffs failed: " << Desc.URI << " with " << Message << std::endl
<< "Falling back to normal index file acquire" << std::endl;
- new pkgAcqIndex(Owner, Target, ExpectedHashes, MetaIndexParser);
+ new pkgAcqIndex(Owner, TransactionID, Target, ExpectedHashes, MetaIndexParser);
Finish();
}
/*}}}*/
// Finish - helper that cleans the item out of the fetcher queue /*{{{*/
void pkgAcqIndexDiffs::Finish(bool allDone)
{
+ if(Debug)
+ std::clog << "pkgAcqIndexDiffs::Finish(): "
+ << allDone << " "
+ << Desc.URI << std::endl;
+
// 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);
+
+ // FIXME: we want the rred stuff to use the real transactional update
+ // this is just a workaround
+ PartialFile = DestFile;
if(HashSums().usable() && !HashSums().VerifyFile(DestFile))
{
// see if there is more to download
if(available_patches.empty() == false) {
- new pkgAcqIndexDiffs(Owner, Target,
+ new pkgAcqIndexDiffs(Owner, TransactionID, Target,
ExpectedHashes, MetaIndexParser,
ServerSha1, available_patches);
return Finish();
/*}}}*/
// AcqIndexMergeDiffs::AcqIndexMergeDiffs - Constructor /*{{{*/
pkgAcqIndexMergeDiffs::pkgAcqIndexMergeDiffs(pkgAcquire *Owner,
+ unsigned long TransactionID,
struct IndexTarget const * const Target,
HashStringList const &ExpectedHashes,
indexRecords *MetaIndexParser,
DiffInfo const &patch,
std::vector<pkgAcqIndexMergeDiffs*> const * const allPatches)
- : pkgAcqBaseIndex(Owner, Target, ExpectedHashes, MetaIndexParser),
+ : pkgAcqBaseIndex(Owner, TransactionID, Target, ExpectedHashes, MetaIndexParser),
patch(patch), allPatches(allPatches), State(StateFetchDiff)
{
// first failure means we should fallback
State = StateErrorDiff;
std::clog << "Falling back to normal index file acquire" << std::endl;
- new pkgAcqIndex(Owner, Target, ExpectedHashes, MetaIndexParser);
+ new pkgAcqIndex(Owner, TransactionID, Target, ExpectedHashes, MetaIndexParser);
}
/*}}}*/
void pkgAcqIndexMergeDiffs::Done(string Message,unsigned long long Size,HashStringList const &Hashes, /*{{{*/
// otherwise lists cleanup will eat the file
DestFile = FinalFile;
+ // FIXME: make the merged rred code really transactional
+ PartialFile = FinalFile;
// ensure the ed's are gone regardless of list-cleanup
for (std::vector<pkgAcqIndexMergeDiffs *>::const_iterator I = allPatches->begin();
pkgAcqIndex::pkgAcqIndex(pkgAcquire *Owner,
string URI,string URIDesc,string ShortDesc,
HashStringList const &ExpectedHash, string comprExt)
- : pkgAcqBaseIndex(Owner, NULL, ExpectedHash, NULL), RealURI(URI)
+ : pkgAcqBaseIndex(Owner, 0, NULL, ExpectedHash, NULL), RealURI(URI)
{
- if(comprExt.empty() == true)
- {
- // autoselect the compression method
- std::vector<std::string> types = APT::Configuration::getCompressionTypes();
- for (std::vector<std::string>::const_iterator t = types.begin(); t != types.end(); ++t)
- comprExt.append(*t).append(" ");
- if (comprExt.empty() == false)
- comprExt.erase(comprExt.end()-1);
- }
- CompressionExtension = comprExt;
-
+ AutoSelectCompression();
Init(URI, URIDesc, ShortDesc);
+
+ if(_config->FindB("Debug::Acquire::Transaction", false) == true)
+ std::clog << "New pkgIndex with TransactionID "
+ << TransactionID << std::endl;
}
-pkgAcqIndex::pkgAcqIndex(pkgAcquire *Owner, IndexTarget const *Target,
+ /*}}}*/
+// AcqIndex::AcqIndex - Constructor /*{{{*/
+// ---------------------------------------------------------------------
+pkgAcqIndex::pkgAcqIndex(pkgAcquire *Owner,
+ unsigned long TransactionID,
+ IndexTarget const *Target,
HashStringList const &ExpectedHash,
indexRecords *MetaIndexParser)
- : pkgAcqBaseIndex(Owner, Target, ExpectedHash, MetaIndexParser),
- RealURI(Target->URI)
+ : pkgAcqBaseIndex(Owner, TransactionID, Target, ExpectedHash,
+ MetaIndexParser), RealURI(Target->URI)
{
// autoselect the compression method
+ AutoSelectCompression();
+ Init(Target->URI, Target->Description, Target->ShortDesc);
+
+ if(_config->FindB("Debug::Acquire::Transaction", false) == true)
+ std::clog << "New pkgIndex with TransactionID "
+ << TransactionID << std::endl;
+}
+ /*}}}*/
+// AcqIndex::AutoSelectCompression - Select compression /*{{{*/
+// ---------------------------------------------------------------------
+void pkgAcqIndex::AutoSelectCompression()
+{
std::vector<std::string> types = APT::Configuration::getCompressionTypes();
CompressionExtension = "";
if (ExpectedHashes.usable())
}
if (CompressionExtension.empty() == false)
CompressionExtension.erase(CompressionExtension.end()-1);
-
- Init(Target->URI, Target->Description, Target->ShortDesc);
}
- /*}}}*/
// AcqIndex::Init - defered Constructor /*{{{*/
void pkgAcqIndex::Init(string const &URI, string const &URIDesc, string const &ShortDesc) {
Decompression = false;
DestFile += URItoFileName(URI);
std::string const comprExt = CompressionExtension.substr(0, CompressionExtension.find(' '));
- std::string MetaKey;
if (comprExt == "uncompressed")
{
Desc.URI = URI;
return msg;
}
/*}}}*/
+// pkgAcqIndex::Failed - getting the indexfile failed /*{{{*/
+// ---------------------------------------------------------------------
+/* */
void pkgAcqIndex::Failed(string Message,pkgAcquire::MethodConfig *Cnf) /*{{{*/
{
size_t const nextExt = CompressionExtension.find(' ');
}
Item::Failed(Message,Cnf);
+
+ /// cancel the entire transaction
+ Owner->AbortTransaction(TransactionID);
}
/*}}}*/
+// pkgAcqIndex::GetFinalFilename - Return the full final file path /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+std::string pkgAcqIndex::GetFinalFilename(std::string const &URI,
+ std::string const &compExt)
+{
+ std::string FinalFile = _config->FindDir("Dir::State::lists");
+ FinalFile += URItoFileName(URI);
+ if (_config->FindB("Acquire::GzipIndexes",false) && compExt == "gz")
+ FinalFile += ".gz";
+ return FinalFile;
+}
+ /*}}}*/
+// AcqIndex::ReverifyAfterIMS - Reverify index after an ims-hit /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+void pkgAcqIndex::ReverifyAfterIMS(std::string const &FileName)
+{
+ std::string const compExt = CompressionExtension.substr(0, CompressionExtension.find(' '));
+ if (_config->FindB("Acquire::GzipIndexes",false) && compExt == "gz")
+ DestFile += ".gz";
+
+ // copy FinalFile into partial/ so that we check the hash again
+ string FinalFile = GetFinalFilename(RealURI, compExt);
+ Decompression = true;
+ Desc.URI = "copy:" + FinalFile;
+ QueueURI(Desc);
+}
+ /*}}}*/
// AcqIndex::Done - Finished a fetch /*{{{*/
// ---------------------------------------------------------------------
/* This goes through a number of states.. On the initial fetch the
method could possibly return an alternate filename which points
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. */
+ is decompressed with a compressed uri. */
void pkgAcqIndex::Done(string Message,unsigned long long Size,HashStringList const &Hashes,
pkgAcquire::MethodConfig *Cfg)
{
Item::Done(Message,Size,Hashes,Cfg);
+ std::string const compExt = CompressionExtension.substr(0, CompressionExtension.find(' '));
if (Decompression == true)
{
{
RenameOnError(HashSumMismatch);
printHashSumComparision(RealURI, ExpectedHashes, Hashes);
+ Failed(Message, Cfg);
return;
}
/* Always verify the index file for correctness (all indexes must
* have a Package field) (LP: #346386) (Closes: #627642)
*/
- FileFd fd(DestFile, FileFd::ReadOnly);
- // Only test for correctness if the file is not empty (empty is ok)
- if (fd.FileSize() > 0)
+ FileFd fd(DestFile, FileFd::ReadOnly, FileFd::Extension);
+ // Only test for correctness if the content of the file is not empty
+ // (empty is ok)
+ if (fd.Size() > 0)
{
pkgTagSection sec;
pkgTagFile tag(&fd);
if (_error->PendingError() == true || tag.Step(sec) == false || sec.Exists("Package") == false)
{
RenameOnError(InvalidFormat);
+ Failed(Message, Cfg);
return;
}
}
- // Done, move it into position
- string FinalFile = _config->FindDir("Dir::State::lists");
- FinalFile += URItoFileName(RealURI);
- Rename(DestFile,FinalFile);
- chmod(FinalFile.c_str(),0644);
-
- /* We restore the original name to DestFile so that the clean operation
- will work OK */
- DestFile = _config->FindDir("Dir::State::lists") + "partial/";
- DestFile += URItoFileName(RealURI);
-
+ // FIXME: can we void the "Erase" bool here as its very non-local?
+ std::string CompressedFile = _config->FindDir("Dir::State::lists") + "partial/";
+ CompressedFile += URItoFileName(RealURI);
// Remove the compressed version.
if (Erase == true)
- unlink(DestFile.c_str());
+ unlink(CompressedFile.c_str());
+
+ // Done, queue for rename on transaction finished
+ PartialFile = DestFile;
+ DestFile = GetFinalFilename(RealURI, compExt);
return;
}
+
+ // FIXME: use the same method to find
+ // check the compressed hash too
+ if(MetaKey != "" && Hashes.size() > 0)
+ {
+ indexRecords::checkSum *Record = MetaIndexParser->Lookup(MetaKey);
+ if(Record && Record->Hashes.usable() && Hashes != Record->Hashes)
+ {
+ RenameOnError(HashSumMismatch);
+ printHashSumComparision(RealURI, Record->Hashes, Hashes);
+ Failed(Message, Cfg);
+ return;
+ }
+ }
Erase = false;
Complete = true;
{
// The files timestamp matches
if (StringToBool(LookupTag(Message,"Alt-IMS-Hit"),false) == true)
+ {
+ ReverifyAfterIMS(FileName);
return;
+ }
Decompression = true;
Local = true;
DestFile += ".decomp";
ErrorText = "Method gave a blank filename";
}
- std::string const compExt = CompressionExtension.substr(0, CompressionExtension.find(' '));
-
// The files timestamp matches
- if (StringToBool(LookupTag(Message,"IMS-Hit"),false) == true) {
- if (_config->FindB("Acquire::GzipIndexes",false) && compExt == "gz")
- // Update DestFile for .gz suffix so that the clean operation keeps it
- DestFile += ".gz";
+ if (StringToBool(LookupTag(Message,"IMS-Hit"),false) == true)
+ {
+ ReverifyAfterIMS(FileName);
return;
}
// If we enable compressed indexes and already have gzip, keep it
if (_config->FindB("Acquire::GzipIndexes",false) && compExt == "gz" && !Local) {
- string FinalFile = _config->FindDir("Dir::State::lists");
- FinalFile += URItoFileName(RealURI) + ".gz";
- Rename(DestFile,FinalFile);
- chmod(FinalFile.c_str(),0644);
-
- // Update DestFile for .gz suffix so that the clean operation keeps it
- DestFile = _config->FindDir("Dir::State::lists") + "partial/";
- DestFile += URItoFileName(RealURI) + ".gz";
+ // Done, queue for rename on transaction finished
+ PartialFile = DestFile;
+ DestFile = GetFinalFilename(RealURI, compExt);
return;
}
: pkgAcqIndex(Owner, URI, URIDesc, ShortDesc, HashStringList(), "")
{
}
-pkgAcqIndexTrans::pkgAcqIndexTrans(pkgAcquire *Owner, IndexTarget const * const Target,
- HashStringList const &ExpectedHashes, indexRecords *MetaIndexParser)
- : pkgAcqIndex(Owner, Target, ExpectedHashes, MetaIndexParser)
+ /*}}}*/
+pkgAcqIndexTrans::pkgAcqIndexTrans(pkgAcquire *Owner,
+ unsigned long TransactionID,
+ IndexTarget const * const Target,
+ HashStringList const &ExpectedHashes,
+ indexRecords *MetaIndexParser)
+ : pkgAcqIndex(Owner, TransactionID, Target, ExpectedHashes, MetaIndexParser)
{
// load the filesize
indexRecords::checkSum *Record = MetaIndexParser->Lookup(string(Target->MetaKey));
return;
}
+ // FIXME: this is used often (e.g. in pkgAcqIndexTrans) so refactor
if (Cnf->LocalOnly == true ||
StringToBool(LookupTag(Message,"Transient-Failure"),false) == false)
{
Item::Failed(Message,Cnf);
}
/*}}}*/
-pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire *Owner, /*{{{*/
+
+pkgAcqMetaSigBase::pkgAcqMetaSigBase(pkgAcquire *Owner,
+ HashStringList const &ExpectedHashes,
+ unsigned long TransactionID)
+ : Item(Owner, ExpectedHashes, TransactionID)
+{
+}
+ /*{{{*/
+bool pkgAcqMetaSigBase::GenerateAuthWarning(const std::string &RealURI,
+ const std::string &Message)
+{
+ string Final = _config->FindDir("Dir::State::lists") + URItoFileName(RealURI);
+
+ if(FileExists(Final))
+ {
+ Status = StatTransientNetworkError;
+ _error->Warning(_("An error occurred during the signature "
+ "verification. The repository is not updated "
+ "and the previous index files will be used. "
+ "GPG error: %s: %s\n"),
+ Desc.Description.c_str(),
+ LookupTag(Message,"Message").c_str());
+ RunScripts("APT::Update::Auth-Failure");
+ return true;
+ } else if (LookupTag(Message,"Message").find("NODATA") != string::npos) {
+ /* Invalid signature file, reject (LP: #346386) (Closes: #627642) */
+ _error->Error(_("GPG error: %s: %s"),
+ Desc.Description.c_str(),
+ LookupTag(Message,"Message").c_str());
+ Status = StatError;
+ return true;
+ } else {
+ _error->Warning(_("GPG error: %s: %s"),
+ Desc.Description.c_str(),
+ LookupTag(Message,"Message").c_str());
+ }
+ // gpgv method failed
+ ReportMirrorFailure("GPGFailure");
+ return false;
+}
+ /*}}}*/
+
+
+pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire *Owner, /*{{{*/
+ unsigned long TransactionID,
string URI,string URIDesc,string ShortDesc,
- string MetaIndexURI, string MetaIndexURIDesc,
- string MetaIndexShortDesc,
+ string MetaIndexFile,
const vector<IndexTarget*>* IndexTargets,
indexRecords* MetaIndexParser) :
- Item(Owner, HashStringList()), RealURI(URI), MetaIndexURI(MetaIndexURI),
- MetaIndexURIDesc(MetaIndexURIDesc), MetaIndexShortDesc(MetaIndexShortDesc),
- MetaIndexParser(MetaIndexParser), IndexTargets(IndexTargets)
+ pkgAcqMetaSigBase(Owner, HashStringList(), TransactionID), RealURI(URI),
+ MetaIndexParser(MetaIndexParser), MetaIndexFile(MetaIndexFile),
+ IndexTargets(IndexTargets), AuthPass(false), IMSHit(false)
{
DestFile = _config->FindDir("Dir::State::lists") + "partial/";
DestFile += URItoFileName(URI);
// partial download anyway
unlink(DestFile.c_str());
+ // set the TransactionID
+ if(_config->FindB("Debug::Acquire::Transaction", false) == true)
+ std::clog << "New pkgAcqMetaSig with TransactionID "
+ << TransactionID << std::endl;
+
// Create the item
Desc.Description = URIDesc;
Desc.Owner = this;
Desc.ShortDesc = ShortDesc;
Desc.URI = URI;
-
- string Final = _config->FindDir("Dir::State::lists");
- Final += URItoFileName(RealURI);
- if (RealFileExists(Final) == true)
- {
- // File was already in place. It needs to be re-downloaded/verified
- // because Release might have changed, we do give it a different
- // 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);
- }
-
- // we expect the indextargets + one additional Release file
- ExpectedAdditionalItems = IndexTargets->size() + 1;
QueueURI(Desc);
}
/*}}}*/
pkgAcqMetaSig::~pkgAcqMetaSig() /*{{{*/
{
- // if the file was never queued undo file-changes done in the constructor
- if (QueueCounter == 1 && Status == StatIdle && FileSize == 0 && Complete == false &&
- LastGoodSig.empty() == false)
- {
- string const Final = _config->FindDir("Dir::State::lists") + URItoFileName(RealURI);
- if (RealFileExists(Final) == false && RealFileExists(LastGoodSig) == true)
- Rename(LastGoodSig, Final);
- }
-
}
/*}}}*/
// pkgAcqMetaSig::Custom600Headers - Insert custom request headers /*{{{*/
/* The only header we use is the last-modified header. */
string pkgAcqMetaSig::Custom600Headers() const
{
+ string FinalFile = _config->FindDir("Dir::State::lists");
+ FinalFile += URItoFileName(RealURI);
+
struct stat Buf;
- if (stat(LastGoodSig.c_str(),&Buf) != 0)
+ if (stat(FinalFile.c_str(),&Buf) != 0)
return "\nIndex-File: true";
return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf.st_mtime);
return;
}
- Complete = true;
+ if(StringToBool(LookupTag(Message,"IMS-Hit"),false) == true)
+ IMSHit = true;
- // at this point pkgAcqMetaIndex takes over
- ExpectedAdditionalItems = 0;
+ // adjust paths if its a ims-hit
+ if(IMSHit)
+ {
+ string FinalFile = _config->FindDir("Dir::State::lists");
+ FinalFile += URItoFileName(RealURI);
+
+ DestFile = PartialFile = FinalFile;
+ }
- // 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 for verify
+ if(AuthPass == false)
+ {
+ AuthPass = true;
+ Desc.URI = "gpgv:" + DestFile;
+ DestFile = MetaIndexFile;
+ QueueURI(Desc);
+ return;
+ }
+
+ // queue to copy the file in place if it was not a ims hit, on ims
+ // hit the file is already at the right place
+ if(IMSHit == false)
+ {
+ PartialFile = _config->FindDir("Dir::State::lists") + "partial/";
+ PartialFile += URItoFileName(RealURI);
+
+ DestFile = _config->FindDir("Dir::State::lists");
+ DestFile += URItoFileName(RealURI);
+ }
- // queue a pkgAcqMetaIndex to be verified against the sig we just retrieved
- new pkgAcqMetaIndex(Owner, MetaIndexURI, MetaIndexURIDesc,
- MetaIndexShortDesc, DestFile, IndexTargets,
- MetaIndexParser);
+ Complete = true;
}
/*}}}*/
{
string Final = _config->FindDir("Dir::State::lists") + URItoFileName(RealURI);
- // at this point pkgAcqMetaIndex takes over
- ExpectedAdditionalItems = 0;
+ // this ensures that any file in the lists/ dir is removed by the
+ // transaction
+ DestFile = _config->FindDir("Dir::State::lists") + "partial/";
+ DestFile += URItoFileName(RealURI);
+ PartialFile = "";
- // if we get a network error we fail gracefully
- if(Status == StatTransientNetworkError)
+ // FIXME: duplicated code from pkgAcqMetaIndex
+ if (AuthPass == true)
{
- Item::Failed(Message,Cnf);
- // move the sigfile back on transient network failures
- if(FileExists(LastGoodSig))
- Rename(LastGoodSig,Final);
-
- // set the status back to , Item::Failed likes to reset it
- Status = pkgAcquire::Item::StatTransientNetworkError;
- return;
+ bool Stop = GenerateAuthWarning(RealURI, Message);
+ if(Stop)
+ 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);
-
+ // FIXME: this is used often (e.g. in pkgAcqIndexTrans) so refactor
if (Cnf->LocalOnly == true ||
StringToBool(LookupTag(Message,"Transient-Failure"),false) == false)
{
Dequeue();
return;
}
-
Item::Failed(Message,Cnf);
}
/*}}}*/
pkgAcqMetaIndex::pkgAcqMetaIndex(pkgAcquire *Owner, /*{{{*/
+ unsigned long TransactionID,
string URI,string URIDesc,string ShortDesc,
- string SigFile,
+ string MetaIndexSigURI,string MetaIndexSigURIDesc, string MetaIndexSigShortDesc,
const vector<IndexTarget*>* IndexTargets,
indexRecords* MetaIndexParser) :
- Item(Owner, HashStringList()), RealURI(URI), SigFile(SigFile), IndexTargets(IndexTargets),
- MetaIndexParser(MetaIndexParser), AuthPass(false), IMSHit(false)
+ pkgAcqMetaSigBase(Owner, HashStringList(), TransactionID), RealURI(URI), IndexTargets(IndexTargets),
+ MetaIndexParser(MetaIndexParser), AuthPass(false), IMSHit(false),
+ MetaIndexSigURI(MetaIndexSigURI), MetaIndexSigURIDesc(MetaIndexSigURIDesc),
+ MetaIndexSigShortDesc(MetaIndexSigShortDesc)
+{
+ if(TransactionID == 0)
+ this->TransactionID = (unsigned long)this;
+
+ if(_config->FindB("Debug::Acquire::Transaction", false) == true)
+ std::clog << "New pkgAcqMetaIndex with TransactionID "
+ << TransactionID << std::endl;
+
+ Init(URIDesc, ShortDesc);
+}
+ /*}}}*/
+// pkgAcqMetaIndex::Init - Delayed constructor /*{{{*/
+void pkgAcqMetaIndex::Init(std::string URIDesc, std::string ShortDesc)
{
DestFile = _config->FindDir("Dir::State::lists") + "partial/";
- DestFile += URItoFileName(URI);
+ DestFile += URItoFileName(RealURI);
// Create the item
Desc.Description = URIDesc;
Desc.Owner = this;
Desc.ShortDesc = ShortDesc;
- Desc.URI = URI;
+ Desc.URI = RealURI;
// we expect more item
ExpectedAdditionalItems = IndexTargets->size();
-
QueueURI(Desc);
}
- /*}}}*/
// pkgAcqMetaIndex::Custom600Headers - Insert custom request headers /*{{{*/
// ---------------------------------------------------------------------
/* The only header we use is the last-modified header. */
if (SigFile == "")
{
- // There was no signature file, so we are finished. Download
- // the indexes and do only hashsum verification if possible
+ // load indexes, the signature will downloaded afterwards
MetaIndexParser->Load(DestFile);
- QueueIndexes(false);
+ QueueIndexes(true);
}
else
{
- // FIXME: move this into pkgAcqMetaClearSig::Done on the next
- // ABI break
-
- // if we expect a ClearTextSignature (InRelase), ensure that
- // this is what we get and if not fail to queue a
- // Release/Release.gpg, see #346386
- if (SigFile == DestFile && !StartsWithGPGClearTextSignature(DestFile))
- {
- Failed(Message, Cfg);
- return;
- }
-
// There was a signature file, so pass it to gpgv for
// verification
if (_config->FindB("Debug::pkgAcquire::Auth", false))
FinalFile += URItoFileName(RealURI);
if (SigFile == DestFile)
SigFile = FinalFile;
- Rename(DestFile,FinalFile);
- chmod(FinalFile.c_str(),0644);
+ // queue for copy in place
+ PartialFile = DestFile;
DestFile = FinalFile;
}
}
if (SigFile == DestFile)
{
SigFile = FinalFile;
+#if 0
// constructor of pkgAcqMetaClearSig moved it out of the way,
// now move it back in on IMS hit for the 'old' file
string const OldClearSig = DestFile + ".reverify";
if (RealFileExists(OldClearSig) == true)
Rename(OldClearSig, FinalFile);
+#endif
}
DestFile = FinalFile;
}
+
+ // queue a signature
+ if(SigFile != DestFile)
+ new pkgAcqMetaSig(Owner, TransactionID,
+ MetaIndexSigURI, MetaIndexSigURIDesc,
+ MetaIndexSigShortDesc, DestFile, IndexTargets,
+ MetaIndexParser);
+
Complete = true;
}
/*}}}*/
// Download further indexes with verification
QueueIndexes(true);
+#if 0
// is it a clearsigned MetaIndex file?
if (DestFile == SigFile)
return;
URItoFileName(RealURI) + ".gpg";
Rename(SigFile,VerifiedSigFile);
chmod(VerifiedSigFile.c_str(),0644);
+#endif
}
/*}}}*/
void pkgAcqMetaIndex::QueueIndexes(bool verify) /*{{{*/
{
-#if 0
- /* Reject invalid, existing Release files (LP: #346386) (Closes: #627642)
- * FIXME: Disabled; it breaks unsigned repositories without hashes */
- if (!verify && FileExists(DestFile) && !MetaIndexParser->Load(DestFile))
- {
- Status = StatError;
- ErrorText = MetaIndexParser->ErrorText;
- return;
- }
-#endif
bool transInRelease = false;
{
std::vector<std::string> const keys = MetaIndexParser->MetaKeys();
if ((*Target)->IsOptional() == true)
{
if ((*Target)->IsSubIndex() == true)
- new pkgAcqSubIndex(Owner, (*Target)->URI, (*Target)->Description,
+ new pkgAcqSubIndex(Owner, TransactionID,
+ (*Target)->URI, (*Target)->Description,
(*Target)->ShortDesc, ExpectedIndexHashes);
else if (transInRelease == false || Record != NULL || compressedAvailable == true)
{
if (_config->FindB("Acquire::PDiffs",true) == true && transInRelease == true &&
MetaIndexParser->Exists((*Target)->MetaKey + ".diff/Index") == true)
- new pkgAcqDiffIndex(Owner, *Target, ExpectedIndexHashes, MetaIndexParser);
+ new pkgAcqDiffIndex(Owner, TransactionID, *Target, ExpectedIndexHashes, MetaIndexParser);
else
- new pkgAcqIndexTrans(Owner, *Target, ExpectedIndexHashes, MetaIndexParser);
+ new pkgAcqIndexTrans(Owner, TransactionID, *Target, ExpectedIndexHashes, MetaIndexParser);
}
continue;
}
instead, but passing the required info to it is to much hassle */
if(_config->FindB("Acquire::PDiffs",true) == true && (verify == false ||
MetaIndexParser->Exists((*Target)->MetaKey + ".diff/Index") == true))
- new pkgAcqDiffIndex(Owner, *Target, ExpectedIndexHashes, MetaIndexParser);
+ new pkgAcqDiffIndex(Owner, TransactionID, *Target, ExpectedIndexHashes, MetaIndexParser);
else
- new pkgAcqIndex(Owner, *Target, ExpectedIndexHashes, MetaIndexParser);
+ new pkgAcqIndex(Owner, TransactionID, *Target, ExpectedIndexHashes, MetaIndexParser);
}
}
/*}}}*/
// pkgAcqMetaIndex::Failed - no Release file present or no signature file present /*{{{*/
// ---------------------------------------------------------------------
/* */
-void pkgAcqMetaIndex::Failed(string Message,pkgAcquire::MethodConfig * /*Cnf*/)
+void pkgAcqMetaIndex::Failed(string Message,
+ pkgAcquire::MethodConfig * /*Cnf*/)
{
+ string Final = _config->FindDir("Dir::State::lists") + URItoFileName(RealURI);
+
if (AuthPass == true)
{
- // gpgv method failed, if we have a good signature
- string LastGoodSigFile = _config->FindDir("Dir::State::lists").append("partial/").append(URItoFileName(RealURI));
- if (DestFile != SigFile)
- LastGoodSigFile.append(".gpg");
- LastGoodSigFile.append(".reverify");
-
- if(FileExists(LastGoodSigFile))
- {
- string VerifiedSigFile = _config->FindDir("Dir::State::lists") + URItoFileName(RealURI);
- if (DestFile != SigFile)
- VerifiedSigFile.append(".gpg");
- Rename(LastGoodSigFile, VerifiedSigFile);
- Status = StatTransientNetworkError;
- _error->Warning(_("An error occurred during the signature "
- "verification. The repository is not updated "
- "and the previous index files will be used. "
- "GPG error: %s: %s\n"),
- Desc.Description.c_str(),
- LookupTag(Message,"Message").c_str());
- RunScripts("APT::Update::Auth-Failure");
- return;
- } else if (LookupTag(Message,"Message").find("NODATA") != string::npos) {
- /* Invalid signature file, reject (LP: #346386) (Closes: #627642) */
- _error->Error(_("GPG error: %s: %s"),
- Desc.Description.c_str(),
- LookupTag(Message,"Message").c_str());
- return;
- } else {
- _error->Warning(_("GPG error: %s: %s"),
- Desc.Description.c_str(),
- LookupTag(Message,"Message").c_str());
- }
- // gpgv method failed
- ReportMirrorFailure("GPGFailure");
+ bool Stop = GenerateAuthWarning(RealURI, Message);
+ if(Stop)
+ return;
}
/* Always move the meta index, even if gpgv failed. This ensures
"Release");
SigFile = FinalFile;
}
- Rename(DestFile,FinalFile);
- chmod(FinalFile.c_str(),0644);
+ // Done, queue for rename on transaction finished
+ PartialFile = DestFile;
DestFile = FinalFile;
}
QueueIndexes(false);
}
/*}}}*/
+
+void pkgAcqMetaIndex::Finished()
+{
+ if(_config->FindB("Debug::Acquire::Transaction", false) == true)
+ std::clog << "Finished: " << DestFile <<std::endl;
+ if(Owner->TransactionHasError(TransactionID) == false &&
+ TransactionID > 0)
+ Owner->CommitTransaction(TransactionID);
+}
+
+
pkgAcqMetaClearSig::pkgAcqMetaClearSig(pkgAcquire *Owner, /*{{{*/
string const &URI, string const &URIDesc, string const &ShortDesc,
string const &MetaIndexURI, string const &MetaIndexURIDesc, string const &MetaIndexShortDesc,
string const &MetaSigURI, string const &MetaSigURIDesc, string const &MetaSigShortDesc,
const vector<IndexTarget*>* IndexTargets,
indexRecords* MetaIndexParser) :
- pkgAcqMetaIndex(Owner, URI, URIDesc, ShortDesc, "", IndexTargets, MetaIndexParser),
- MetaIndexURI(MetaIndexURI), MetaIndexURIDesc(MetaIndexURIDesc), MetaIndexShortDesc(MetaIndexShortDesc),
- MetaSigURI(MetaSigURI), MetaSigURIDesc(MetaSigURIDesc), MetaSigShortDesc(MetaSigShortDesc)
+ pkgAcqMetaIndex(Owner, (unsigned long)this, URI, URIDesc, ShortDesc, MetaSigURI, MetaSigURIDesc,MetaSigShortDesc, IndexTargets, MetaIndexParser),
+ MetaIndexURI(MetaIndexURI), MetaIndexURIDesc(MetaIndexURIDesc), MetaIndexShortDesc(MetaIndexShortDesc),
+ MetaSigURI(MetaSigURI), MetaSigURIDesc(MetaSigURIDesc), MetaSigShortDesc(MetaSigShortDesc)
{
SigFile = DestFile;
// index targets + (worst case:) Release/Release.gpg
ExpectedAdditionalItems = IndexTargets->size() + 2;
-
+#if 0
// keep the old InRelease around in case of transistent network errors
string const Final = _config->FindDir("Dir::State::lists") + URItoFileName(RealURI);
if (RealFileExists(Final) == true)
string const LastGoodSig = DestFile + ".reverify";
Rename(Final,LastGoodSig);
}
+#endif
}
/*}}}*/
pkgAcqMetaClearSig::~pkgAcqMetaClearSig() /*{{{*/
{
+#if 0
// if the file was never queued undo file-changes done in the constructor
if (QueueCounter == 1 && Status == StatIdle && FileSize == 0 && Complete == false)
{
if (RealFileExists(Final) == false && RealFileExists(LastGoodSig) == true)
Rename(LastGoodSig, Final);
}
+#endif
}
/*}}}*/
// pkgAcqMetaClearSig::Custom600Headers - Insert custom request headers /*{{{*/
struct stat Buf;
if (stat(Final.c_str(),&Buf) != 0)
{
- Final = DestFile + ".reverify";
if (stat(Final.c_str(),&Buf) != 0)
return "\nIndex-File: true\nFail-Ignore: true\n";
}
return "\nIndex-File: true\nFail-Ignore: true\nLast-Modified: " + TimeRFC1123(Buf.st_mtime);
}
/*}}}*/
+// pkgAcqMetaClearSig::Done - We got a file /*{{{*/
+// ---------------------------------------------------------------------
+void pkgAcqMetaClearSig::Done(std::string Message,unsigned long long Size,
+ HashStringList const &Hashes,
+ pkgAcquire::MethodConfig *Cnf)
+{
+ // if we expect a ClearTextSignature (InRelase), ensure that
+ // this is what we get and if not fail to queue a
+ // Release/Release.gpg, see #346386
+ if (FileExists(DestFile) && !StartsWithGPGClearTextSignature(DestFile))
+ {
+ pkgAcquire::Item::Failed(Message, Cnf);
+ ErrorText = _("Does not start with a cleartext signature");
+ return;
+ }
+ pkgAcqMetaIndex::Done(Message, Size, Hashes, Cnf);
+}
+ /*}}}*/
void pkgAcqMetaClearSig::Failed(string Message,pkgAcquire::MethodConfig *Cnf) /*{{{*/
{
// we failed, we will not get additional items from this method
if (AuthPass == false)
{
- // Remove the 'old' InRelease file if we try Release.gpg now as otherwise
- // the file will stay around and gives a false-auth impression (CVE-2012-0214)
+ // Queue the 'old' InRelease file for removal if we try Release.gpg
+ // as otherwise the file will stay around and gives a false-auth
+ // impression (CVE-2012-0214)
string FinalFile = _config->FindDir("Dir::State::lists");
FinalFile.append(URItoFileName(RealURI));
- if (FileExists(FinalFile))
- unlink(FinalFile.c_str());
+ PartialFile = "";
+ DestFile = FinalFile;
- new pkgAcqMetaSig(Owner,
- MetaSigURI, MetaSigURIDesc, MetaSigShortDesc,
+ new pkgAcqMetaIndex(Owner, TransactionID,
MetaIndexURI, MetaIndexURIDesc, MetaIndexShortDesc,
+ MetaSigURI, MetaSigURIDesc, MetaSigShortDesc,
IndexTargets, MetaIndexParser);
if (Cnf->LocalOnly == true ||
StringToBool(LookupTag(Message, "Transient-Failure"), false) == false)