Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also .

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also .
...
  • 12 commits
  • 75 files changed
  • 0 commit comments
  • 3 contributors
Commits on Apr 07, 2016
ensure transaction states are changed only once
We want to keep track of the state of a transaction overall to base
future decisions on it, but as a pre-requirement we have to make sure
that a transaction isn't commited twice (which happened if the download
of InRelease failed and Release takes over).

It also happened to create empty commits after a transaction was already
aborted in cases in which the Release files were rejected.

This isn't effecting security at the moment, but to ensure this isn't
happening again and can never be bad a bunch of fatal error messages are
added to make regressions on this front visible.
stop handling items in doomed transactions
With the previous commit we track the state of transactions, so we can
now use our knowledge to avoid processing data for a transaction which
was already closed (via an abort in this case).

This is needed as multiple independent processes are interacting in the
process, so there isn't a simple immediate full-engine stop and it would
also be bad to teach each and every item how to check if its manager
has failed subordinate and what to do in that case.

In the pdiff case, which deals (potentially) with many items during its
lifetime e.g. a hashsum mismatch in another file can abort the
transaction the file we try to patch via pdiff belongs to. This causes
some of the items (which are already done) to be aborted with it, but
items still in the process of acquisition continue in the processing and
will later try to use all the items together failing in strange ways as
cleanup already happened.

The chosen solution is to dry up the communication channels instead by
ignoring new requests for data acquisition, canceling requests which are
not assigned to a queue and not calling Done/Failed on items anymore.
This means that e.g. already started or pending (e.g. pipelined)
downloads aren't stopped and continue as normal for now, but they remain
in partial/ and aren't processed further so the next update command will
pick them up and put them to good use while the current process fails
updating (for this transaction group) in an orderly fashion.

Closes: 817240
Thanks: Barr Detwix & Vincent Lefevre for log files
Commits on Apr 13, 2016
webserver: 416 errors aren't closing connections
Breaking here lets our handler die which a client will fix by
reconnecting… but that eats time needlessly and is simple the wrong
handling, too.

Git-Dch: Ignore
do not require non-broken systems in 'upgrade'
There is a good chance that the attempt will fail, but if a user
mentions certain packages explicitly on the commandline there is a
chance that this will consist of a broken system which is resolved
by upgrading more packages then just the mentioned.

This limitation was not effecting external resolvers.
detect compressed status files on extension again
It handy to be able to point apt at reading a compressed dpkg/status
file in debugging cases, which worked pre-1.1 but somewhere down the
line in the massive refactoring. Restoring this behavior in a central
place for all realfile index files instead of just for the status file.

(This has no effect on index files acquired from an archive – those are
handled by different classes and support compressed files just fine)
recheck Pre-Depends satisfaction in SmartConfigure
Regression introduced in commit 590f192
(2011!) causing apt to not check if Pre-Depends are satisfied before
calling --configure. This managed to hide so perfectly well for years as
Pre-Depends aren't that common, apt prefers upgrading these packages
first and checks for satisfaction is already in SmartUnpack, so there
is only a small window of oppertunity to break a pre-dependency relation
(usually with an unpack).

Verified by logchecking with two provided status files in the buglog.
I would have liked to write a test, but I wasn't able to reach the needed
complexity to get apt to fail – but the change is small and reasonable,
so what could possible go wrong™, right?

LP: #1569099
Commits on Apr 14, 2016
fix Alt-Filename handling of file method
A silly of-by-one error in the stripping of the extension to check for
the uncompressed filename broken in an attempt to support all
compressions in commit a09f6eb.

Fixing this highlights also mistakes in the handling of the Alt-Filename
in libapt which would cause apt to remove the file from the repository
(if root has the needed rights – aka the disk isn't readonly or similar)
allow uncompressed files to be empty in store again
With the previous fix for file applied we can again hit repositories
which contain uncompressed empty files, which since the introduction of
the central store: method wasn't accounted for anymore as we forbid
empty compressed files.
silently skip acquire of empty index files
There is just no point in taking the time to acquire empty files –
especially as it will be tiny non-empty compressed files usually.
ensure outdated files are dropped without lists-cleanup
Tested via (newly) empty index files, but effects also files dropped
from the repository or an otherwise changed repository config.
Commits on Apr 25, 2016
Showing with 612 additions and 386 deletions.
  1. +101 −21 apt-pkg/acquire-item.cc
  2. +3 −1 apt-pkg/acquire-item.h
  3. +63 −52 apt-pkg/acquire-worker.cc
  4. +1 −1 apt-pkg/indexfile.cc
  5. +2 −2 apt-pkg/packagemanager.cc
  6. +0 −8 apt-pkg/upgrade.cc
  7. +1 −1 configure.ac
  8. +19 −0 debian/changelog
  9. +1 −1 doc/apt-verbatim.ent
  10. +2 −2 doc/po/apt-doc.pot
  11. +1 −1 doc/po/de.po
  12. +1 −1 doc/po/es.po
  13. +1 −1 doc/po/fr.po
  14. +1 −1 doc/po/it.po
  15. +1 −1 doc/po/ja.po
  16. +1 −1 doc/po/nl.po
  17. +1 −1 doc/po/pl.po
  18. +1 −1 doc/po/pt.po
  19. +1 −1 doc/po/pt_BR.po
  20. +1 −1 methods/file.cc
  21. +1 −1 methods/store.cc
  22. +2 −2 po/apt-all.pot
  23. +1 −1 po/ar.po
  24. +1 −1 po/ast.po
  25. +1 −1 po/bg.po
  26. +1 −1 po/bs.po
  27. +1 −1 po/ca.po
  28. +1 −1 po/cs.po
  29. +1 −1 po/cy.po
  30. +1 −1 po/da.po
  31. +1 −1 po/de.po
  32. +1 −1 po/dz.po
  33. +1 −1 po/el.po
  34. +1 −1 po/es.po
  35. +1 −1 po/eu.po
  36. +1 −1 po/fi.po
  37. +1 −1 po/fr.po
  38. +1 −1 po/gl.po
  39. +255 −196 po/hu.po
  40. +1 −1 po/it.po
  41. +1 −1 po/ja.po
  42. +1 −1 po/km.po
  43. +1 −1 po/ko.po
  44. +1 −1 po/ku.po
  45. +1 −1 po/lt.po
  46. +1 −1 po/mr.po
  47. +1 −1 po/nb.po
  48. +1 −1 po/ne.po
  49. +1 −1 po/nl.po
  50. +1 −1 po/nn.po
  51. +1 −1 po/pl.po
  52. +1 −1 po/pt.po
  53. +1 −1 po/pt_BR.po
  54. +1 −1 po/ro.po
  55. +1 −1 po/ru.po
  56. +1 −1 po/sk.po
  57. +1 −1 po/sl.po
  58. +1 −1 po/sv.po
  59. +1 −1 po/th.po
  60. +1 −1 po/tl.po
  61. +1 −1 po/tr.po
  62. +1 −1 po/uk.po
  63. +1 −1 po/vi.po
  64. +1 −1 po/zh_CN.po
  65. +1 −1 po/zh_TW.po
  66. +6 −0 test/integration/framework
  67. +2 −1 test/integration/test-apt-acquire-additional-files
  68. +1 −0 test/integration/test-apt-get-build-dep-file
  69. +47 −0 test/integration/test-apt-update-empty-files
  70. +3 −1 test/integration/test-apt-update-file
  71. +15 −35 test/integration/test-bug-595691-empty-and-broken-archive-files
  72. +1 −4 test/integration/test-compressed-indexes
  73. +2 −3 test/integration/test-handle-redirect-as-used-mirror-change
  74. +31 −1 test/integration/test-pdiff-usage
  75. +1 −1 test/interactive-helper/aptwebserver.cc
View
@@ -281,6 +281,12 @@ bool pkgAcquire::Item::QueueURI(pkgAcquire::ItemDesc &Item)
for a hashsum mismatch to happen which helps nobody) */
bool pkgAcqTransactionItem::QueueURI(pkgAcquire::ItemDesc &Item)
{
+ if (TransactionManager->State != TransactionStarted)
+ {
+ if (_config->FindB("Debug::Acquire::Transaction", false))
+ std::clog << "Skip " << Target.URI << " as transaction was already dealt with!" << std::endl;
+ return false;
+ }
std::string const FinalFile = GetFinalFilename();
if (TransactionManager != NULL && TransactionManager->IMSHit == true &&
FileExists(FinalFile) == true)
@@ -362,6 +368,7 @@ bool pkgAcqTransactionItem::TransactionState(TransactionStates const state)
bool const Debug = _config->FindB("Debug::Acquire::Transaction", false);
switch(state)
{
+ case TransactionStarted: _error->Fatal("Item %s changed to invalid transaction start state!", Target.URI.c_str()); break;
case TransactionAbort:
if(Debug == true)
std::clog << " Cancel: " << DestFile << std::endl;
@@ -430,7 +437,7 @@ bool pkgAcqTransactionItem::TransactionState(TransactionStates const state)
} else {
if(Debug == true)
std::clog << "rm " << DestFile << " # " << DescURI() << std::endl;
- if (RemoveFile("TransactionCommit", DestFile) == false)
+ if (RemoveFile("TransItem::TransactionCommit", DestFile) == false)
return false;
}
break;
@@ -451,6 +458,7 @@ bool pkgAcqIndex::TransactionState(TransactionStates const state)
switch (state)
{
+ case TransactionStarted: _error->Fatal("AcqIndex %s changed to invalid transaction start state!", Target.URI.c_str()); break;
case TransactionAbort:
if (Stage == STAGE_DECOMPRESS_AND_VERIFY)
{
@@ -462,7 +470,7 @@ bool pkgAcqIndex::TransactionState(TransactionStates const state)
break;
case TransactionCommit:
if (EraseFileName.empty() == false)
- RemoveFile("TransactionCommit", EraseFileName);
+ RemoveFile("AcqIndex::TransactionCommit", EraseFileName);
break;
}
return true;
@@ -474,6 +482,7 @@ bool pkgAcqDiffIndex::TransactionState(TransactionStates const state)
switch (state)
{
+ case TransactionStarted: _error->Fatal("Item %s changed to invalid transaction start state!", Target.URI.c_str()); break;
case TransactionCommit:
break;
case TransactionAbort:
@@ -510,6 +519,41 @@ class APT_HIDDEN NoActionItem : public pkgAcquire::Item /*{{{*/
}
};
/*}}}*/
+class APT_HIDDEN CleanupItem : public pkgAcqTransactionItem /*{{{*/
+/* This class ensures that a file which was configured but isn't downloaded
+ for various reasons isn't kept in an old version in the lists directory.
+ In a way its the reverse of NoActionItem as it helps with removing files
+ even if the lists-cleanup is deactivated. */
+{
+ public:
+ virtual std::string DescURI() const APT_OVERRIDE {return Target.URI;};
+ virtual HashStringList GetExpectedHashes() const APT_OVERRIDE {return HashStringList();};
+
+ CleanupItem(pkgAcquire * const Owner, pkgAcqMetaClearSig * const TransactionManager, IndexTarget const &Target) :
+ pkgAcqTransactionItem(Owner, TransactionManager, Target)
+ {
+ Status = StatDone;
+ DestFile = GetFinalFileNameFromURI(Target.URI);
+ }
+ bool TransactionState(TransactionStates const state) APT_OVERRIDE
+ {
+ switch (state)
+ {
+ case TransactionStarted:
+ break;
+ case TransactionAbort:
+ break;
+ case TransactionCommit:
+ if (_config->FindB("Debug::Acquire::Transaction", false) == true)
+ std::clog << "rm " << DestFile << " # " << DescURI() << std::endl;
+ if (RemoveFile("TransItem::TransactionCommit", DestFile) == false)
+ return false;
+ break;
+ }
+ return true;
+ }
+};
+ /*}}}*/
// Acquire::Item::Item - Constructor /*{{{*/
APT_IGNORE_DEPRECATED_PUSH
@@ -835,7 +879,7 @@ pkgAcqMetaBase::pkgAcqMetaBase(pkgAcquire * const Owner,
IndexTarget const &DataTarget)
: pkgAcqTransactionItem(Owner, TransactionManager, DataTarget), d(NULL),
IndexTargets(IndexTargets),
- AuthPass(false), IMSHit(false)
+ AuthPass(false), IMSHit(false), State(TransactionStarted)
{
}
/*}}}*/
@@ -851,10 +895,20 @@ void pkgAcqMetaBase::AbortTransaction()
if(_config->FindB("Debug::Acquire::Transaction", false) == true)
std::clog << "AbortTransaction: " << TransactionManager << std::endl;
+ switch (TransactionManager->State)
+ {
+ case TransactionStarted: break;
+ case TransactionAbort: _error->Fatal("Transaction %s was already aborted and is aborted again", TransactionManager->Target.URI.c_str()); return;
+ case TransactionCommit: _error->Fatal("Transaction %s was already aborted and is now commited", TransactionManager->Target.URI.c_str()); return;
+ }
+ TransactionManager->State = TransactionAbort;
+
// ensure the toplevel is in error state too
for (std::vector<pkgAcqTransactionItem*>::iterator I = Transaction.begin();
I != Transaction.end(); ++I)
{
+ if ((*I)->Status != pkgAcquire::Item::StatFetching)
+ Owner->Dequeue(*I);
(*I)->TransactionState(TransactionAbort);
}
Transaction.clear();
@@ -884,6 +938,14 @@ void pkgAcqMetaBase::CommitTransaction()
if(_config->FindB("Debug::Acquire::Transaction", false) == true)
std::clog << "CommitTransaction: " << this << std::endl;
+ switch (TransactionManager->State)
+ {
+ case TransactionStarted: break;
+ case TransactionAbort: _error->Fatal("Transaction %s was already commited and is now aborted", TransactionManager->Target.URI.c_str()); return;
+ case TransactionCommit: _error->Fatal("Transaction %s was already commited and is again commited", TransactionManager->Target.URI.c_str()); return;
+ }
+ TransactionManager->State = TransactionCommit;
+
// move new files into place *and* remove files that are not
// part of the transaction but are still on disk
for (std::vector<pkgAcqTransactionItem*>::iterator I = Transaction.begin();
@@ -1086,10 +1148,12 @@ void pkgAcqMetaBase::QueueIndexes(bool const verify) /*{{{*/
// than invent an entirely new flag we would need to carry for all of eternity.
if (Target->Option(IndexTarget::ARCHITECTURE) == "all")
{
- if (TransactionManager->MetaIndexParser->IsArchitectureSupported("all") == false)
- continue;
- if (TransactionManager->MetaIndexParser->IsArchitectureAllSupportedFor(*Target) == false)
+ if (TransactionManager->MetaIndexParser->IsArchitectureSupported("all") == false ||
+ TransactionManager->MetaIndexParser->IsArchitectureAllSupportedFor(*Target) == false)
+ {
+ new CleanupItem(Owner, TransactionManager, *Target);
continue;
+ }
}
bool trypdiff = Target->OptionBool(IndexTarget::PDIFFS);
@@ -1099,13 +1163,17 @@ void pkgAcqMetaBase::QueueIndexes(bool const verify) /*{{{*/
{
// optional targets that we do not have in the Release file are skipped
if (Target->IsOptional)
+ {
+ new CleanupItem(Owner, TransactionManager, *Target);
continue;
+ }
std::string const &arch = Target->Option(IndexTarget::ARCHITECTURE);
if (arch.empty() == false)
{
if (TransactionManager->MetaIndexParser->IsArchitectureSupported(arch) == false)
{
+ new CleanupItem(Owner, TransactionManager, *Target);
_error->Notice(_("Skipping acquire of configured file '%s' as repository '%s' doesn't support architecture '%s'"),
Target->MetaKey.c_str(), TransactionManager->Target.Description.c_str(), arch.c_str());
continue;
@@ -1114,7 +1182,10 @@ void pkgAcqMetaBase::QueueIndexes(bool const verify) /*{{{*/
// ignore silently as this is pretty much the same as just shipping an empty file.
// if we don't know which architectures are supported, we do NOT ignore it to notify user about this
if (TransactionManager->MetaIndexParser->IsArchitectureSupported("*undefined*") == false)
+ {
+ new CleanupItem(Owner, TransactionManager, *Target);
continue;
+ }
}
Status = StatAuthError;
@@ -1124,11 +1195,21 @@ void pkgAcqMetaBase::QueueIndexes(bool const verify) /*{{{*/
else
{
auto const hashes = GetExpectedHashesFor(Target->MetaKey);
- if (hashes.usable() == false && hashes.empty() == false)
+ if (hashes.empty() == false)
{
- _error->Warning(_("Skipping acquire of configured file '%s' as repository '%s' provides only weak security information for it"),
+ if (hashes.usable() == false)
+ {
+ new CleanupItem(Owner, TransactionManager, *Target);
+ _error->Warning(_("Skipping acquire of configured file '%s' as repository '%s' provides only weak security information for it"),
Target->MetaKey.c_str(), TransactionManager->Target.Description.c_str());
- continue;
+ continue;
+ }
+ // empty files are skipped as acquiring the very small compressed files is a waste of time
+ else if (hashes.FileSize() == 0)
+ {
+ new CleanupItem(Owner, TransactionManager, *Target);
+ continue;
+ }
}
}
@@ -1350,6 +1431,15 @@ string pkgAcqMetaClearSig::Custom600Headers() const
return Header;
}
/*}}}*/
+void pkgAcqMetaClearSig::Finished() /*{{{*/
+{
+ if(_config->FindB("Debug::Acquire::Transaction", false) == true)
+ std::clog << "Finished: " << DestFile <<std::endl;
+ if(TransactionManager != NULL && TransactionManager->State == TransactionStarted &&
+ TransactionManager->TransactionHasError() == false)
+ TransactionManager->CommitTransaction();
+}
+ /*}}}*/
bool pkgAcqMetaClearSig::VerifyDone(std::string const &Message, /*{{{*/
pkgAcquire::MethodConfig const * const Cnf)
{
@@ -1509,15 +1599,6 @@ void pkgAcqMetaIndex::Failed(string const &Message,
}
}
/*}}}*/
-void pkgAcqMetaIndex::Finished() /*{{{*/
-{
- if(_config->FindB("Debug::Acquire::Transaction", false) == true)
- std::clog << "Finished: " << DestFile <<std::endl;
- if(TransactionManager != NULL &&
- TransactionManager->TransactionHasError() == false)
- TransactionManager->CommitTransaction();
-}
- /*}}}*/
std::string pkgAcqMetaIndex::DescURI() const /*{{{*/
{
return Target.URI;
@@ -2721,9 +2802,8 @@ void pkgAcqIndex::StageDownloadDone(string const &Message)
// methods like file:// give us an alternative (uncompressed) file
else if (Target.KeepCompressed == false && AltFilename.empty() == false)
{
- if (CurrentCompressionExtension != "uncompressed")
- DestFile.erase(DestFile.length() - (CurrentCompressionExtension.length() + 1));
Filename = AltFilename;
+ EraseFileName.clear();
}
// Methods like e.g. "file:" will give us a (compressed) FileName that is
// not the "DestFile" we set, in this case we uncompress from the local file
@@ -2753,7 +2833,7 @@ void pkgAcqIndex::StageDownloadDone(string const &Message)
DestFile = "/dev/null";
}
- if (EraseFileName.empty())
+ if (EraseFileName.empty() && Filename != AltFilename)
EraseFileName = Filename;
// queue uri for the next stage
View
@@ -381,6 +381,7 @@ class APT_HIDDEN pkgAcqTransactionItem: public pkgAcquire::Item /*{{{*/
pkgAcqMetaClearSig * const TransactionManager;
enum TransactionStates {
+ TransactionStarted,
TransactionCommit,
TransactionAbort,
};
@@ -467,6 +468,7 @@ class APT_HIDDEN pkgAcqMetaBase : public pkgAcqTransactionItem /*{{{*/
public:
// This refers more to the Transaction-Manager than the actual file
bool IMSHit;
+ TransactionStates State;
virtual bool QueueURI(pkgAcquire::ItemDesc &Item) APT_OVERRIDE;
virtual HashStringList GetExpectedHashes() const APT_OVERRIDE;
@@ -522,7 +524,6 @@ class APT_HIDDEN pkgAcqMetaIndex : public pkgAcqMetaBase
virtual void Failed(std::string const &Message,pkgAcquire::MethodConfig const * const Cnf) APT_OVERRIDE;
virtual void Done(std::string const &Message, HashStringList const &Hashes,
pkgAcquire::MethodConfig const * const Cnf) APT_OVERRIDE;
- virtual void Finished() APT_OVERRIDE;
/** \brief Create a new pkgAcqMetaIndex. */
pkgAcqMetaIndex(pkgAcquire * const Owner, pkgAcqMetaClearSig * const TransactionManager,
@@ -588,6 +589,7 @@ class APT_HIDDEN pkgAcqMetaClearSig : public pkgAcqMetaIndex
virtual bool VerifyDone(std::string const &Message, pkgAcquire::MethodConfig const * const Cnf) APT_OVERRIDE;
virtual void Done(std::string const &Message, HashStringList const &Hashes,
pkgAcquire::MethodConfig const * const Cnf) APT_OVERRIDE;
+ virtual void Finished() APT_OVERRIDE;
/** \brief Create a new pkgAcqMetaClearSig. */
pkgAcqMetaClearSig(pkgAcquire * const Owner,
Oops, something went wrong.

No commit comments for this range