diff options
author | Michael Vogt <michael.vogt@ubuntu.com> | 2007-06-14 11:59:13 +0200 |
---|---|---|
committer | Michael Vogt <michael.vogt@ubuntu.com> | 2007-06-14 11:59:13 +0200 |
commit | 702c84fb16a65ce0850bb99676edfbeefd656193 (patch) | |
tree | 2fcd13af56764d344124db49061d0dc970424179 /apt-pkg | |
parent | 8d4b705ab0ef3a0de13a9ff9f1aa47f09112f374 (diff) | |
parent | 47026cdea6ba7d145922ce21d5ec478598126b8d (diff) |
* apt-pkg/deb/dpkgpm.cc:
- apport integration added, this means that a apport
report is written on dpkg failures
* merged from debian/unstable, remaining changes:
- maintainer field changed
* merged the debian/experimental changes back
into the debian/sid branch
* merged from Christian Perrier:
* mr.po: New Marathi translation Closes: #416806
* zh_CN.po: Updated by Eric Pareja Closes: #416822
* tl.po: Updated by Eric Pareja Closes: #416638
* gl.po: Updated by Jacobo Tarrio
* da.po: Updated by Claus Hindsgaul
* fr.po: Remove a non-breakable space for usability
* ru.po: Updated Russian translation. Closes: #405476
* *.po: Unfuzzy after upstream typo corrections
* buildlib/archtable:
- added support for sh3/sh4 (closes: #424870)
- added support for m32r (closes: #394096)
* buildlib/systemtable:
- added support for lpia
* configure.in:
- check systemtable for architecture mapping too
* fix error in AutocleanInterval, closes: #319339
(thanks to Israel G. Lugo for the patch)
* add "purge" commandline argument, closes: #133421)
(thanks to Julien Danjou for the patch)
* add "purge" commandline argument, closes: #133421)
(thanks to Julien Danjou for the patch)
* fix FTBFS with gcc 4.3, closes: #417090
(thanks to Martin Michlmayr for the patch)
* add --dsc-only option, thanks to K. Richard Pixley
* Removed the more leftover #pragma interface/implementation
closes: #306937 (thanks to Andreas Henriksson for the patch)
* ABI library name change because its build against
new glibc
* implement SourceVer() in pkgRecords
(thanks to Daniel Burrows for the patch!)
* apt-pkg/algorithm.cc:
- use clog for all debugging
- only increase the score of installed applications if they
are not obsolete
- fix resolver bug on removal triggered by weak-dependencies
with or-groups
* methods/http.cc:
- send apt version in User-Agent
* apt-pkg/deb/debrecords.cc:
- fix SHA1Hash() return value
* apt-pkg/cdrom.cc:
- only unmount if APT::CDROM::NoMount is false
* methods/cdrom.cc:
- only umount if it was mounted by the method before
- if decompression of a index fails, delete the index
* vi.po: Updated to 515t. Closes: #426976
* eu.po: Updated to 515t. Closes: #423766
* pt.po: 515t. Closes: #423111
* fr.po: Updated by Christian Perrier
* Update all PO and the POT. Gives 513t2f for formerly
complete translations
* Package that contains tall the new features
* Removed all #pragma interface/implementation
* Branch that contains tall the new features:
* translated package descriptions
* task install support
* automatic dependency removal (thanks to Daniel Burrows)
* merged support for the new dpkg "Breaks" field
(thanks to Ian Jackson)
* handle network failures more gracefully on "update"
* support for unattended-upgrades (via unattended-upgrades
package)
* added apt-transport-https method
- ca.po: Updated to 514t
- be.po: Updated to 514t
- it.po: Updated to 514t
- hu.po: Updated to 514t
- zh_TW.po: Updated to 514t
- ar.po: Updated to 293t221u.
- ru.po: Updated to 514t. Closes: #392466
- nb.po: Updated to 514t. Closes: #392466
- pt.po: Updated to 514t. Closes: #393199
- fr.po: One spelling error corrected: s/accèder/accéder
- km.po: Updated to 514t.
- ko.po: Updated to 514t.
- bg.po: Updated to 514t.
- de.po: Updated to 514t.
- en_GB.po: Updated to 514t.
* debian/control:
- depend on debian-archive-keyring to offer clean upgrade path
(closes: #386800)
* merged "install-recommends" branch (ABI break):
- new "--install-recommends"
- install new recommends on "upgrade" if --install-recommends is
given
- new "--fix-policy" option to install all packages with unmet
important dependencies (usefull with --install-recommends to
see what not-installed recommends are on the system)
- fix of recommended packages display (only show CandidateVersion
fix or-group handling)
* merged "install-task" branch (use with "apt-get install taskname^")
* Applied patch from Daniel Schepler to make apt bin-NMU able.
* apt-pkg/acquire-item.cc:
- fix reversed logic of the "Acquire::PDiffs" option
* apt-pkg/contrib/sha256.cc:
- applied patch to fix unaligned access problem. Closes: #367417
(thanks to David Mosberger)
* apt-pkg/contrib/sha256.{cc,h},hashes.{cc,h}: support for sha256
(thanks to Anthony Towns)
* ftparchive/cachedb.{cc,h},writer.{cc,h}: optimizations
(thanks to Anthony Towns)
* apt pdiff support from experimental merged
* apt-pkg/deb/dpkgpm.cc: wording fixes (thanks to Matt Zimmerman)
- fix error in dpkg interaction (closes: #364513, thanks to Martin Dickopp)
Diffstat (limited to 'apt-pkg')
-rw-r--r-- | apt-pkg/acquire-item.cc | 442 | ||||
-rw-r--r-- | apt-pkg/acquire-item.h | 727 | ||||
-rw-r--r-- | apt-pkg/acquire-method.h | 9 | ||||
-rw-r--r-- | apt-pkg/acquire-worker.h | 259 | ||||
-rw-r--r-- | apt-pkg/acquire.h | 545 | ||||
-rw-r--r-- | apt-pkg/algorithms.cc | 2 | ||||
-rw-r--r-- | apt-pkg/cdrom.cc | 5 | ||||
-rw-r--r-- | apt-pkg/contrib/fileutl.cc | 1 | ||||
-rw-r--r-- | apt-pkg/contrib/strutl.cc | 1 | ||||
-rw-r--r-- | apt-pkg/deb/debrecords.cc | 28 | ||||
-rw-r--r-- | apt-pkg/deb/debrecords.h | 1 | ||||
-rw-r--r-- | apt-pkg/deb/debsrcrecords.cc | 2 | ||||
-rw-r--r-- | apt-pkg/deb/debsrcrecords.h | 2 | ||||
-rw-r--r-- | apt-pkg/depcache.cc | 41 | ||||
-rw-r--r-- | apt-pkg/indexfile.cc | 4 | ||||
-rw-r--r-- | apt-pkg/init.cc | 5 | ||||
-rw-r--r-- | apt-pkg/init.h | 4 | ||||
-rw-r--r-- | apt-pkg/makefile | 2 | ||||
-rw-r--r-- | apt-pkg/pkgrecords.h | 1 |
19 files changed, 1969 insertions, 112 deletions
diff --git a/apt-pkg/acquire-item.cc b/apt-pkg/acquire-item.cc index c42c8af24..b7b16b9a2 100644 --- a/apt-pkg/acquire-item.cc +++ b/apt-pkg/acquire-item.cc @@ -21,6 +21,8 @@ #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> @@ -28,6 +30,7 @@ #include <unistd.h> #include <errno.h> #include <string> +#include <sstream> #include <stdio.h> /*}}}*/ @@ -106,7 +109,7 @@ void pkgAcquire::Item::Done(string Message,unsigned long Size,string, // We just downloaded something.. string FileName = LookupTag(Message,"Filename"); UsedMirror = LookupTag(Message,"UsedMirror"); - if (Complete == false && FileName == DestFile) + if (Complete == false && !Local && FileName == DestFile) { if (Owner->Log != 0) Owner->Log->Fetched(Size,atoi(LookupTag(Message,"Resume-Point","0").c_str())); @@ -179,14 +182,432 @@ void pkgAcquire::Item::ReportMirrorFailure(string FailCode) } + +// 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); + + // 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<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) + { + // 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 + int last_space = Description.rfind(" "); + if(last_space != string::npos) + Description.erase(last_space, Description.size()-last_space); + new pkgAcqIndexDiffs(Owner, RealURI, Description, Desc.ShortDesc, + ExpectedMD5, 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, + 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); + + 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 = 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, + 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; @@ -230,7 +651,6 @@ string pkgAcqIndex::Custom600Headers() void pkgAcqIndex::Failed(string Message,pkgAcquire::MethodConfig *Cnf) { - // 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"; @@ -480,7 +900,7 @@ void pkgAcqMetaSig::Failed(string Message,pkgAcquire::MethodConfig *Cnf) if(Status == StatTransientNetworkError) { Item::Failed(Message,Cnf); - // move the sigfile back on network failures (and re-authenticated?) + // move the sigfile back on transient network failures if(FileExists(DestFile)) Rename(DestFile,Final); @@ -622,6 +1042,7 @@ void pkgAcqMetaIndex::RetrievalDone(string Message) // Move it into position Rename(DestFile,FinalFile); } + chmod(FinalFile.c_str(),0644); DestFile = FinalFile; } @@ -691,9 +1112,14 @@ void pkgAcqMetaIndex::QueueIndexes(bool verify) } } - // 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",false) == true) + new pkgAcqDiffIndex(Owner, (*Target)->URI, (*Target)->Description, + (*Target)->ShortDesc, ExpectedIndexMD5); + else + new pkgAcqIndex(Owner, (*Target)->URI, (*Target)->Description, + (*Target)->ShortDesc, ExpectedIndexMD5); } } diff --git a/apt-pkg/acquire-item.h b/apt-pkg/acquire-item.h index 1885f7beb..233cbdda9 100644 --- a/apt-pkg/acquire-item.h +++ b/apt-pkg/acquire-item.h @@ -28,72 +28,503 @@ #include <apt-pkg/indexrecords.h> -// Item to acquire +/** \addtogroup acquire + * @{ + * + * \file acquire-item.h + */ + +/** \brief Represents the process by which a pkgAcquire object should + * retrieve a file or a collection of files. + * + * By convention, Item subclasses should insert themselves into the + * acquire queue when they are created by calling QueueURI(), and + * remove themselves by calling Dequeue() when either Done() or + * Failed() is invoked. Item objects are also responsible for + * notifying the download progress indicator (accessible via + * #Owner->Log) of their status. + * + * \see pkgAcquire + */ class pkgAcquire::Item { protected: - // Some private helper methods for registering URIs + /** \brief The acquire object with which this item is associated. */ pkgAcquire *Owner; + + /** \brief Insert this item into its owner's queue. + * + * \param ItemDesc Metadata about this item (its URI and + * description). + */ inline void QueueURI(ItemDesc &Item) {Owner->Enqueue(Item);}; + + /** \brief Remove this item from its owner's queue. */ inline void Dequeue() {Owner->Dequeue(this);}; - // Safe rename function with timestamp preservation + /** \brief Rename a file without modifying its timestamp. + * + * Many item methods call this as their final action. + * + * \param From The file to be renamed. + * + * \param To The new name of #From. If #To exists it will be + * overwritten. + */ void Rename(string From,string To); public: - // State of the item - enum {StatIdle, StatFetching, StatDone, StatError, - StatAuthError, StatTransientNetworkError} Status; + /** \brief The current status of this item. */ + enum ItemState + { + /** \brief The item is waiting to be downloaded. */ + StatIdle, + + /** \brief The item is currently being downloaded. */ + StatFetching, + + /** \brief The item has been successfully downloaded. */ + StatDone, + + /** \brief An error was encountered while downloading this + * item. + */ + StatError, + + /** \brief The item was downloaded but its authenticity could + * not be verified. + */ + StatAuthError, + + /** \brief The item was could not be downloaded because of + * a transient network error (e.g. network down) + */ + StatTransientNetworkError + } Status; + + /** \brief Contains a textual description of the error encountered + * if #Status is #StatError or #StatAuthError. + */ string ErrorText; + + /** \brief The size of the object to fetch. */ unsigned long FileSize; - unsigned long PartialSize; + + /** \brief How much of the object was already fetched. */ + unsigned long PartialSize; + + /** \brief If not \b NULL, contains the name of a subprocess that + * is operating on this object (for instance, "gzip" or "gpgv"). + */ const char *Mode; + + /** \brief A client-supplied unique identifier. + * + * This field is initalized to 0; it is meant to be filled in by + * clients that wish to use it to uniquely identify items. + * + * \todo it's unused in apt itself + */ unsigned long ID; + + /** \brief If \b true, the entire object has been successfully fetched. + * + * Subclasses should set this to \b true when appropriate. + */ bool Complete; + + /** \brief If \b true, the URI of this object is "local". + * + * The only effect of this field is to exclude the object from the + * download progress indicator's overall statistics. + */ bool Local; string UsedMirror; - // Number of queues we are inserted into + /** \brief The number of fetch queues into which this item has been + * inserted. + * + * There is one queue for each source from which an item could be + * downloaded. + * + * \sa pkgAcquire + */ unsigned int QueueCounter; - // File to write the fetch into + /** \brief The name of the file into which the retrieved object + * will be written. + */ string DestFile; - // Action members invoked by the worker + /** \brief Invoked by the acquire worker when the object couldn't + * be fetched. + * + * This is a branch of the continuation of the fetch process. + * + * \param Message An RFC822-formatted message from the acquire + * method describing what went wrong. Use LookupTag() to parse + * it. + * + * \param Cnf The method via which the worker tried to fetch this object. + * + * \sa pkgAcqMethod + */ virtual void Failed(string Message,pkgAcquire::MethodConfig *Cnf); + + /** \brief Invoked by the acquire worker when the object was + * fetched successfully. + * + * Note that the object might \e not have been written to + * DestFile; check for the presence of an Alt-Filename entry in + * Message to find the file to which it was really written. + * + * Done is often used to switch from one stage of the processing + * to the next (e.g. fetching, unpacking, copying). It is one + * branch of the continuation of the fetch process. + * + * \param Message Data from the acquire method. Use LookupTag() + * to parse it. + * \param Size The size of the object that was fetched. + * \param Md5Hash The MD5Sum of the object that was fetched. + * \param Cnf The method via which the object was fetched. + * + * \sa pkgAcqMethod + */ virtual void Done(string Message,unsigned long Size,string Md5Hash, pkgAcquire::MethodConfig *Cnf); + + /** \brief Invoked when the worker starts to fetch this object. + * + * \param Message RFC822-formatted data from the worker process. + * Use LookupTag() to parse it. + * + * \param Size The size of the object being fetched. + * + * \sa pkgAcqMethod + */ virtual void Start(string Message,unsigned long Size); + + /** \brief Custom headers to be sent to the fetch process. + * + * \return a string containing RFC822-style headers that are to be + * inserted into the 600 URI Acquire message sent to the fetch + * subprocess. The headers are inserted after a newline-less + * line, so they should (if nonempty) have a leading newline and + * no trailing newline. + */ virtual string Custom600Headers() {return string();}; + + /** \brief A "descriptive" URI-like string. + * + * \return a URI that should be used to describe what is being fetched. + */ virtual string DescURI() = 0; + /** \brief Short item description. + * + * \return a brief description of the object being fetched. + */ virtual string ShortDesc() {return DescURI();} + + /** \brief Invoked by the worker when the download is completely done. */ virtual void Finished() {}; - // Inquire functions + /** \brief MD5Sum. + * + * \return the MD5Sum of this object, if applicable; otherwise, an + * empty string. + */ virtual string MD5Sum() {return string();}; + + /** \return the acquire process with which this item is associated. */ pkgAcquire *GetOwner() {return Owner;}; + + /** \return \b true if this object is being fetched from a trusted source. */ virtual bool IsTrusted() {return false;}; // report mirror problems + /** \brief Report mirror problem + * + * This allows reporting mirror failures back to a centralized + * server. The apt-report-mirror-failure script is called for this + * + * \param FailCode A short failure string that is send + */ void ReportMirrorFailure(string FailCode); + + /** \brief Initialize an item. + * + * Adds the item to the list of items known to the acquire + * process, but does not place it into any fetch queues (you must + * manually invoke QueueURI() to do so). + * + * Initializes all fields of the item other than Owner to 0, + * false, or the empty string. + * + * \param Owner The new owner of this item. + */ Item(pkgAcquire *Owner); + + /** \brief Remove this item from its owner's queue by invoking + * pkgAcquire::Remove. + */ virtual ~Item(); }; -// Item class for index files -class pkgAcqIndex : public pkgAcquire::Item +/** \brief Information about an index patch (aka diff). */ +struct DiffInfo { + /** The filename of the diff. */ + string file; + + /** The sha1 hash of the diff. */ + string sha1; + + /** The size of the diff. */ + unsigned long size; +}; + +/** \brief An item that is responsible for fetching an index file of + * package list diffs and starting the package list's download. + * + * This item downloads the Index file and parses it, then enqueues + * additional downloads of either the individual patches (using + * pkgAcqIndexDiffs) or the entire Packages file (using pkgAcqIndex). + * + * \sa pkgAcqIndexDiffs, pkgAcqIndex + */ +class pkgAcqDiffIndex : public pkgAcquire::Item +{ + protected: + /** \brief If \b true, debugging information will be written to std::clog. */ + bool Debug; + + /** \brief The item that is currently being downloaded. */ + pkgAcquire::ItemDesc Desc; + + /** \brief The URI of the index file to recreate at our end (either + * by downloading it or by applying partial patches). + */ + string RealURI; + + /** \brief The MD5Sum that the real index file should have after + * all patches have been applied. + */ + string ExpectedMD5; + + /** \brief The index file which will be patched to generate the new + * file. + */ + string CurrentPackagesFile; + + /** \brief A description of the Packages file (stored in + * pkgAcquire::ItemDesc::Description). + */ + string Description; + + public: + // Specialized action members + virtual void Failed(string Message,pkgAcquire::MethodConfig *Cnf); + virtual void Done(string Message,unsigned long Size,string Md5Hash, + pkgAcquire::MethodConfig *Cnf); + virtual string DescURI() {return RealURI + "Index";}; + virtual string Custom600Headers(); + + /** \brief Parse the Index file for a set of Packages diffs. + * + * Parses the Index file and creates additional download items as + * necessary. + * + * \param IndexDiffFile The name of the Index file. + * + * \return \b true if the Index file was successfully parsed, \b + * false otherwise. + */ + bool ParseDiffIndex(string IndexDiffFile); + + + /** \brief Create a new pkgAcqDiffIndex. + * + * \param Owner The Acquire object that owns this item. + * + * \param URI The URI of the list file to download. + * + * \param URIDesc A long description of the list file to download. + * + * \param ShortDesc A short description of the list file to download. + * + * \param ExpectedMD5 The list file's MD5 signature. + */ + pkgAcqDiffIndex(pkgAcquire *Owner,string URI,string URIDesc, + string ShortDesc, string ExpectedMD5); +}; + +/** \brief An item that is responsible for fetching all the patches + * that need to be applied to a given package index file. + * + * After downloading and applying a single patch, this item will + * enqueue a new pkgAcqIndexDiffs to download and apply the remaining + * patches. If no patch can be found that applies to an intermediate + * file or if one of the patches cannot be downloaded, falls back to + * downloading the entire package index file using pkgAcqIndex. + * + * \sa pkgAcqDiffIndex, pkgAcqIndex + */ +class pkgAcqIndexDiffs : public pkgAcquire::Item { + private: + + /** \brief Queue up the next diff download. + * + * Search for the next available diff that applies to the file + * that currently exists on disk, and enqueue it by calling + * QueueURI(). + * + * \return \b true if an applicable diff was found, \b false + * otherwise. + */ + bool QueueNextDiff(); + + /** \brief Handle tasks that must be performed after the item + * finishes downloading. + * + * Dequeues the item and checks the resulting file's md5sum + * against ExpectedMD5 after the last patch was applied. + * There is no need to check the md5/sha1 after a "normal" + * patch because QueueNextDiff() will check the sha1 later. + * + * \param allDone If \b true, the file was entirely reconstructed, + * and its md5sum is verified. + */ + void Finish(bool allDone=false); + protected: + + /** \brief If \b true, debugging output will be written to + * std::clog. + */ + bool Debug; + + /** \brief A description of the item that is currently being + * downloaded. + */ + pkgAcquire::ItemDesc Desc; + + /** \brief The URI of the package index file that is being + * reconstructed. + */ + string RealURI; + + /** \brief The MD5Sum of the package index file that is being + * reconstructed. + */ + string ExpectedMD5; + + /** A description of the file being downloaded. */ + string Description; + + /** The patches that remain to be downloaded, including the patch + * being downloaded right now. This list should be ordered so + * that each diff appears before any diff that depends on it. + * + * \todo These are indexed by sha1sum; why not use some sort of + * dictionary instead of relying on ordering and stripping them + * off the front? + */ + vector<DiffInfo> available_patches; + /** The current status of this patch. */ + enum DiffState + { + /** \brief The diff is in an unknown state. */ + StateFetchUnkown, + + /** \brief The diff is currently being fetched. */ + StateFetchDiff, + + /** \brief The diff is currently being uncompressed. */ + StateUnzipDiff, + + /** \brief The diff is currently being applied. */ + StateApplyDiff + } State; + + public: + /** \brief Called when the patch file failed to be downloaded. + * + * This method will fall back to downloading the whole index file + * outright; its arguments are ignored. + */ + virtual void Failed(string Message,pkgAcquire::MethodConfig *Cnf); + + virtual void Done(string Message,unsigned long Size,string Md5Hash, + pkgAcquire::MethodConfig *Cnf); + virtual string DescURI() {return RealURI + "Index";}; + + /** \brief Create an index diff item. + * + * After filling in its basic fields, this invokes Finish(true) if + * #diffs is empty, or QueueNextDiff() otherwise. + * + * \param Owner The pkgAcquire object that owns this item. + * + * \param URI The URI of the package index file being + * reconstructed. + * + * \param URIDesc A long description of this item. + * + * \param ShortDesc A brief description of this item. + * + * \param ExpectedMD5 The expected md5sum of the completely + * reconstructed package index file; the index file will be tested + * against this value when it is entirely reconstructed. + * + * \param diffs The remaining diffs from the index of diffs. They + * should be ordered so that each diff appears before any diff + * that depends on it. + */ + pkgAcqIndexDiffs(pkgAcquire *Owner,string URI,string URIDesc, + string ShortDesc, string ExpectedMD5, + vector<DiffInfo> diffs=vector<DiffInfo>()); +}; + +/** \brief An acquire item that is responsible for fetching an index + * file (e.g., Packages or Sources). + * + * \sa pkgAcqDiffIndex, pkgAcqIndexDiffs, pkgAcqIndexTrans + * + * \todo Why does pkgAcqIndex have protected members? + */ +class pkgAcqIndex : public pkgAcquire::Item +{ + protected: + + /** \brief If \b true, the index file has been decompressed. */ bool Decompression; + + /** \brief If \b true, the partially downloaded file will be + * removed when the download completes. + */ bool Erase; + + /** \brief The download request that is currently being + * processed. + */ pkgAcquire::ItemDesc Desc; + + /** \brief The object that is actually being fetched (minus any + * compression-related extensions). + */ string RealURI; + + /** \brief The expected md5sum of the decompressed index file. */ string ExpectedMD5; + + /** \brief The compression-related file extension that is being + * added to the downloaded file (e.g., ".gz" or ".bz2"). + */ string CompressionExtension; public: @@ -105,36 +536,120 @@ class pkgAcqIndex : public pkgAcquire::Item virtual string Custom600Headers(); virtual string DescURI() {return RealURI + CompressionExtension;}; + /** \brief Create a pkgAcqIndex. + * + * \param Owner The pkgAcquire object with which this item is + * associated. + * + * \param URI The URI of the index file that is to be downloaded. + * + * \param URIDesc A "URI-style" description of this index file. + * + * \param ShortDesc A brief description of this index file. + * + * \param ExpectedMD5 The expected md5sum of this index file. + * + * \param compressExt The compression-related extension with which + * this index file should be downloaded, or "" to autodetect + * (".bz2" is used if bzip2 is installed, ".gz" otherwise). + */ pkgAcqIndex(pkgAcquire *Owner,string URI,string URIDesc, string ShortDesct, string ExpectedMD5, string compressExt=""); }; -// Item class for translated package index files +/** \brief An acquire item that is responsible for fetching a + * translated index file. + * + * The only difference from pkgAcqIndex is that transient failures + * are suppressed: no error occurs if the translated index file is + * missing. + */ class pkgAcqIndexTrans : public pkgAcqIndex { public: virtual void Failed(string Message,pkgAcquire::MethodConfig *Cnf); + + /** \brief Create a pkgAcqIndexTrans. + * + * \param Owner The pkgAcquire object with which this item is + * associated. + * + * \param URI The URI of the index file that is to be downloaded. + * + * \param URIDesc A "URI-style" description of this index file. + * + * \param ShortDesc A brief description of this index file. + * + * \param ExpectedMD5 The expected md5sum of this index file. + * + * \param compressExt The compression-related extension with which + * this index file should be downloaded, or "" to autodetect + * (".bz2" is used if bzip2 is installed, ".gz" otherwise). + */ pkgAcqIndexTrans(pkgAcquire *Owner,string URI,string URIDesc, - string ShortDesct); + string ShortDesc); }; +/** \brief Information about an index file. */ struct IndexTarget { + /** \brief A URI from which the index file can be downloaded. */ string URI; + + /** \brief A description of the index file. */ string Description; + + /** \brief A shorter description of the index file. */ string ShortDesc; + + /** \brief The key by which this index file should be + * looked up within the meta signature file. + */ string MetaKey; }; -// Item class for index signatures +/** \brief An acquire item that downloads the detached signature + * of a meta-index (Release) file, then queues up the release + * file itself. + * + * \todo Why protected members? + * + * \sa pkgAcqMetaIndex + */ class pkgAcqMetaSig : public pkgAcquire::Item { protected: - + /** \brief The fetch request that is currently being processed. */ pkgAcquire::ItemDesc Desc; - string RealURI,MetaIndexURI,MetaIndexURIDesc,MetaIndexShortDesc; + + /** \brief The URI of the signature file. Unlike Desc.URI, this is + * never modified; it is used to determine the file that is being + * downloaded. + */ + string RealURI; + + /** \brief The URI of the meta-index file to be fetched after the signature. */ + string MetaIndexURI; + + /** \brief A "URI-style" description of the meta-index file to be + * fetched after the signature. + */ + string MetaIndexURIDesc; + + /** \brief A brief description of the meta-index file to be fetched + * after the signature. + */ + string MetaIndexShortDesc; + + /** \brief A package-system-specific parser for the meta-index file. */ indexRecords* MetaIndexParser; + + /** \brief The index files which should be looked up in the meta-index + * and then downloaded. + * + * \todo Why a list of pointers instead of a list of structs? + */ const vector<struct IndexTarget*>* IndexTargets; public: @@ -146,29 +661,90 @@ class pkgAcqMetaSig : public pkgAcquire::Item virtual string Custom600Headers(); virtual string DescURI() {return RealURI; }; + /** \brief Create a new pkgAcqMetaSig. */ pkgAcqMetaSig(pkgAcquire *Owner,string URI,string URIDesc, string ShortDesc, string MetaIndexURI, string MetaIndexURIDesc, string MetaIndexShortDesc, const vector<struct IndexTarget*>* IndexTargets, indexRecords* MetaIndexParser); }; -// Item class for index signatures +/** \brief An item that is responsible for downloading the meta-index + * file (i.e., Release) itself and verifying its signature. + * + * Once the download and verification are complete, the downloads of + * the individual index files are queued up using pkgAcqDiffIndex. + * If the meta-index file had a valid signature, the expected md5sums + * of the index files will be the md5sums listed in the meta-index; + * otherwise, the expected md5sums will be "" (causing the + * authentication of the index files to be bypassed). + */ class pkgAcqMetaIndex : public pkgAcquire::Item { protected: - + /** \brief The fetch command that is currently being processed. */ pkgAcquire::ItemDesc Desc; - string RealURI; // FIXME: is this redundant w/ Desc.URI? + + /** \brief The URI that is actually being downloaded; never + * modified by pkgAcqMetaIndex. + */ + string RealURI; + + /** \brief The file in which the signature for this index was stored. + * + * If empty, the signature and the md5sums of the individual + * indices will not be checked. + */ string SigFile; + + /** \brief The index files to download. */ const vector<struct IndexTarget*>* IndexTargets; + + /** \brief The parser for the meta-index file. */ indexRecords* MetaIndexParser; + + /** \brief If \b true, the index's signature is currently being verified. + */ bool AuthPass; // required to deal gracefully with problems caused by incorrect ims hits bool IMSHit; + /** \brief Check that the release file is a release file for the + * correct distribution. + * + * \return \b true if no fatal errors were encountered. + */ bool VerifyVendor(string Message); + + /** \brief Called when a file is finished being retrieved. + * + * If the file was not downloaded to DestFile, a copy process is + * set up to copy it to DestFile; otherwise, Complete is set to \b + * true and the file is moved to its final location. + * + * \param Message The message block received from the fetch + * subprocess. + */ void RetrievalDone(string Message); + + /** \brief Called when authentication succeeded. + * + * Sanity-checks the authenticated file, queues up the individual + * index files for download, and saves the signature in the lists + * directory next to the authenticated list file. + * + * \param Message The message block received from the fetch + * subprocess. + */ void AuthDone(string Message); + + /** \brief Starts downloading the individual index files. + * + * \param verify If \b true, only indices whose expected md5sum + * can be determined from the meta-index will be downloaded, and + * the md5sums of indices will be checked (reporting + * #StatAuthError if there is a mismatch). If verify is \b false, + * no md5sum checking will be performed. + */ void QueueIndexes(bool verify); public: @@ -180,6 +756,7 @@ class pkgAcqMetaIndex : public pkgAcquire::Item virtual string Custom600Headers(); virtual string DescURI() {return RealURI; }; + /** \brief Create a new pkgAcqMetaIndex. */ pkgAcqMetaIndex(pkgAcquire *Owner, string URI,string URIDesc, string ShortDesc, string SigFile, @@ -187,28 +764,58 @@ class pkgAcqMetaIndex : public pkgAcquire::Item indexRecords* MetaIndexParser); }; -// Item class for archive files +/** \brief An item that is responsible for fetching a package file. + * + * If the package file already exists in the cache, nothing will be + * done. + */ class pkgAcqArchive : public pkgAcquire::Item { protected: - - // State information for the retry mechanism + /** \brief The package version being fetched. */ pkgCache::VerIterator Version; + + /** \brief The fetch command that is currently being processed. */ pkgAcquire::ItemDesc Desc; + + /** \brief The list of sources from which to pick archives to + * download this package from. + */ pkgSourceList *Sources; + + /** \brief A package records object, used to look up the file + * corresponding to each version of the package. + */ pkgRecords *Recs; + + /** \brief The md5sum of this package. */ string MD5; + + /** \brief A location in which the actual filename of the package + * should be stored. + */ string &StoreFilename; + + /** \brief The next file for this version to try to download. */ pkgCache::VerFileIterator Vf; + + /** \brief How many (more) times to try to find a new source from + * which to download this package version if it fails. + * + * Set from Acquire::Retries. + */ unsigned int Retries; + + /** \brief \b true if this version file is being downloaded from a + * trusted source. + */ bool Trusted; - // Queue the next available file for download. + /** \brief Queue up the next available file for this version. */ bool QueueNext(); public: - // Specialized action members virtual void Failed(string Message,pkgAcquire::MethodConfig *Cnf); virtual void Done(string Message,unsigned long Size,string Md5Hash, pkgAcquire::MethodConfig *Cnf); @@ -216,18 +823,49 @@ class pkgAcqArchive : public pkgAcquire::Item virtual string DescURI() {return Desc.URI;}; virtual string ShortDesc() {return Desc.ShortDesc;}; virtual void Finished(); + virtual bool IsTrusted(); + /** \brief Create a new pkgAcqArchive. + * + * \param Owner The pkgAcquire object with which this item is + * associated. + * + * \param Sources The sources from which to download version + * files. + * + * \param Recs A package records object, used to look up the file + * corresponding to each version of the package. + * + * \param Version The package version to download. + * + * \param StoreFilename A location in which the actual filename of + * the package should be stored. It will be set to a guessed + * basename in the constructor, and filled in with a fully + * qualified filename once the download finishes. + */ pkgAcqArchive(pkgAcquire *Owner,pkgSourceList *Sources, pkgRecords *Recs,pkgCache::VerIterator const &Version, string &StoreFilename); }; -// Fetch a generic file to the current directory +/** \brief Retrieve an arbitrary file to the current directory. + * + * The file is retrieved even if it is accessed via a URL type that + * normally is a NOP, such as "file". If the download fails, the + * partial file is renamed to get a ".FAILED" extension. + */ class pkgAcqFile : public pkgAcquire::Item { + /** \brief The currently active download process. */ pkgAcquire::ItemDesc Desc; + + /** \brief The md5sum of the file to download, if it is known. */ string Md5Hash; + + /** \brief How many times to retry the download, set from + * Acquire::Retries. + */ unsigned int Retries; public: @@ -239,13 +877,40 @@ class pkgAcqFile : public pkgAcquire::Item virtual string MD5Sum() {return Md5Hash;}; virtual string DescURI() {return Desc.URI;}; - // If DestFilename is empty, download to DestDir/<basename> if - // DestDir is non-empty, $CWD/<basename> otherwise. If - // DestFilename is NOT empty, DestDir is ignored and DestFilename - // is the absolute name to which the file should be downloaded. + /** \brief Create a new pkgAcqFile object. + * + * \param Owner The pkgAcquire object with which this object is + * associated. + * + * \param URI The URI to download. + * + * \param MD5 The md5sum of the file to download, if it is known; + * otherwise "". + * + * \param Size The size of the file to download, if it is known; + * otherwise 0. + * + * \param Desc A description of the file being downloaded. + * + * \param ShortDesc A brief description of the file being + * downloaded. + * + * \param DestDir The directory the file should be downloaded into. + * + * \param DestFilename The filename+path the file is downloaded to. + * + * + * If DestFilename is empty, download to DestDir/<basename> if + * DestDir is non-empty, $CWD/<basename> otherwise. If + * DestFilename is NOT empty, DestDir is ignored and DestFilename + * is the absolute name to which the file should be downloaded. + */ + pkgAcqFile(pkgAcquire *Owner, string URI, string MD5, unsigned long Size, string Desc, string ShortDesc, const string &DestDir="", const string &DestFilename=""); }; +/** @} */ + #endif diff --git a/apt-pkg/acquire-method.h b/apt-pkg/acquire-method.h index 4e72d7094..89eb2e77f 100644 --- a/apt-pkg/acquire-method.h +++ b/apt-pkg/acquire-method.h @@ -10,6 +10,13 @@ ##################################################################### */ /*}}}*/ + +/** \addtogroup acquire + * @{ + * + * \file acquire-method.h + */ + #ifndef PKGLIB_ACQUIRE_METHOD_H #define PKGLIB_ACQUIRE_METHOD_H @@ -86,4 +93,6 @@ class pkgAcqMethod virtual ~pkgAcqMethod() {}; }; +/** @} */ + #endif diff --git a/apt-pkg/acquire-worker.h b/apt-pkg/acquire-worker.h index d5f8c63d2..2942df69f 100644 --- a/apt-pkg/acquire-worker.h +++ b/apt-pkg/acquire-worker.h @@ -9,13 +9,38 @@ ##################################################################### */ /*}}}*/ + +/** \addtogroup acquire + * @{ + * + * \file acquire-worker.h + */ + #ifndef PKGLIB_ACQUIRE_WORKER_H #define PKGLIB_ACQUIRE_WORKER_H #include <apt-pkg/acquire.h> -// Interfacing to the method process +/** \brief A fetch subprocess. + * + * A worker process is responsible for one stage of the fetch. This + * class encapsulates the communications protocol between the master + * process and the worker, from the master end. + * + * Each worker is intrinsically placed on two linked lists. The + * Queue list (maintained in the #NextQueue variable) is maintained + * by the pkgAcquire::Queue class; it represents the set of workers + * assigned to a particular queue. The Acquire list (maintained in + * the #NextAcquire variable) is maintained by the pkgAcquire class; + * it represents the set of active workers for a particular + * pkgAcquire object. + * + * \todo Like everything else in the Acquire system, this has way too + * many protected items. + * + * \sa pkgAcqMethod, pkgAcquire::Item, pkgAcquire + */ class pkgAcquire::Worker { friend class pkgAcquire; @@ -23,64 +48,274 @@ class pkgAcquire::Worker protected: friend class Queue; - /* Linked list starting at a Queue and a linked list starting - at Acquire */ + /** \brief The next link on the Queue list. + * + * \todo This is always NULL; is it just for future use? + */ Worker *NextQueue; + + /** \brief The next link on the Acquire list. */ Worker *NextAcquire; - // The access association + /** \brief The Queue with which this worker is associated. */ Queue *OwnerQ; + + /** \brief The download progress indicator to which progress + * messages should be sent. + */ pkgAcquireStatus *Log; + + /** \brief The configuration of this method. On startup, the + * target of this pointer is filled in with basic data about the + * method, as reported by the worker. + */ MethodConfig *Config; + + /** \brief The access method to be used by this worker. + * + * \todo Doesn't this duplicate Config->Access? + */ string Access; - // This is the subprocess IPC setup + /** \brief The PID of the subprocess. */ pid_t Process; + + /** \brief A file descriptor connected to the standard output of + * the subprocess. + * + * Used to read messages and data from the subprocess. + */ int InFd; + + /** \brief A file descriptor connected to the standard input of the + * subprocess. + * + * Used to send commands and configuration data to the subprocess. + */ int OutFd; + + /** \brief Set to \b true if the worker is in a state in which it + * might generate data or command responses. + * + * \todo Is this right? It's a guess. + */ bool InReady; + + /** \brief Set to \b true if the worker is in a state in which it + * is legal to send commands to it. + * + * \todo Is this right? + */ bool OutReady; - // Various internal things + /** If \b true, debugging output will be sent to std::clog. */ bool Debug; + + /** \brief The raw text values of messages received from the + * worker, in sequence. + */ vector<string> MessageQueue; + + /** \brief Buffers pending writes to the subprocess. + * + * \todo Wouldn't a std::dequeue be more appropriate? + */ string OutQueue; - // Private constructor helper + /** \brief Common code for the constructor. + * + * Initializes NextQueue and NextAcquire to NULL; Process, InFd, + * and OutFd to -1, OutReady and InReady to \b false, and Debug + * from _config. + */ void Construct(); - // Message handling things + /** \brief Retrieve any available messages from the subprocess. + * + * The messages are retrieved as in ::ReadMessages(), and + * MessageFailure() is invoked if an error occurs; in particular, + * if the pipe to the subprocess dies unexpectedly while a message + * is being read. + * + * \return \b true if the messages were successfully read, \b + * false otherwise. + */ bool ReadMessages(); + + /** \brief Parse and dispatch pending messages. + * + * This dispatches the message in a manner appropriate for its + * type. + * + * \todo Several message types lack separate handlers. + * + * \sa Capabilities(), SendConfiguration(), MediaChange() + */ bool RunMessages(); + + /** \brief Read and dispatch any pending messages from the + * subprocess. + * + * \return \b false if the subprocess died unexpectedly while a + * message was being transmitted. + */ bool InFdReady(); + + /** \brief Send any pending commands to the subprocess. + * + * This method will fail if there is no pending output. + * + * \return \b true if all commands were succeeded, \b false if an + * error occurred (in which case MethodFailure() will be invoked). + */ bool OutFdReady(); - // The message handlers + /** \brief Handle a 100 Capabilities response from the subprocess. + * + * \param Message the raw text of the message from the subprocess. + * + * The message will be parsed and its contents used to fill + * #Config. If #Config is NULL, this routine is a NOP. + * + * \return \b true. + */ bool Capabilities(string Message); + + /** \brief Send a 601 Configuration message (containing the APT + * configuration) to the subprocess. + * + * The APT configuration will be send to the subprocess in a + * message of the following form: + * + * <pre> + * 601 Configuration + * Config-Item: Fully-Qualified-Item=Val + * Config-Item: Fully-Qualified-Item=Val + * ... + * </pre> + * + * \return \b true if the command was successfully sent, \b false + * otherwise. + */ bool SendConfiguration(); + + /** \brief Handle a 403 Media Change message. + * + * \param Message the raw text of the message; the Media field + * indicates what type of media should be changed, and the Drive + * field indicates where the media is located. + * + * Invokes pkgAcquireStatus::MediaChange(Media, Drive) to ask the + * user to swap disks; informs the subprocess of the result (via + * 603 Media Changed, with the Failed field set to \b true if the + * user cancelled the media change). + */ bool MediaChange(string Message); + /** \brief Invoked when the worked process dies unexpectedly. + * + * Waits for the subprocess to terminate and generates an error if + * it terminated abnormally, then closes and blanks out all file + * descriptors. Discards all pending messages from the + * subprocess. + * + * \return \b false. + */ bool MethodFailure(); + + /** \brief Invoked when a fetch job is completed, either + * successfully or unsuccessfully. + * + * Resets the status information for the worker process. + */ void ItemDone(); public: - // The curent method state + /** \brief The queue entry that is currently being downloaded. */ pkgAcquire::Queue::QItem *CurrentItem; + + /** \brief The most recent status string received from the + * subprocess. + */ string Status; + + /** \brief How many bytes of the file have been downloaded. Zero + * if the current progress of the file cannot be determined. + */ unsigned long CurrentSize; + + /** \brief The total number of bytes to be downloaded. Zero if the + * total size of the final is unknown. + */ unsigned long TotalSize; + + /** \brief How much of the file was already downloaded prior to + * starting this worker. + */ unsigned long ResumePoint; - // Load the method and do the startup + /** \brief Tell the subprocess to download the given item. + * + * \param Item the item to queue up. + * \return \b true if the item was successfully enqueued. + * + * Queues up a 600 URI Acquire message for the given item to be + * sent at the next possible moment. Does \e not flush the output + * queue. + */ bool QueueItem(pkgAcquire::Queue::QItem *Item); + + /** \brief Start up the worker and fill in #Config. + * + * Reads the first message from the worker, which is assumed to be + * a 100 Capabilities message. + * + * \return \b true if all operations completed successfully. + */ bool Start(); + + /** \brief Update the worker statistics (CurrentSize, TotalSize, + * etc). + */ void Pulse(); + + /** \return The fetch method configuration. */ inline const MethodConfig *GetConf() const {return Config;}; - + + /** \brief Create a new Worker to download files. + * + * \param OwnerQ The queue into which this worker should be + * placed. + * + * \param Config A location in which to store information about + * the fetch method. + * + * \param Log The download progress indicator that should be used + * to report the progress of this worker. + */ Worker(Queue *OwnerQ,MethodConfig *Config,pkgAcquireStatus *Log); + + /** \brief Create a new Worker that should just retrieve + * information about the fetch method. + * + * Nothing in particular forces you to refrain from actually + * downloading stuff, but the various status callbacks won't be + * invoked. + * + * \param Config A location in which to store information about + * the fetch method. + */ Worker(MethodConfig *Config); + + /** \brief Clean up this worker. + * + * Closes the file descriptors; if MethodConfig::NeedsCleanup is + * \b false, also rudely interrupts the worker with a SIGINT. + */ ~Worker(); }; +/** @} */ + #endif diff --git a/apt-pkg/acquire.h b/apt-pkg/acquire.h index 5fbc5c867..1de6f5e44 100644 --- a/apt-pkg/acquire.h +++ b/apt-pkg/acquire.h @@ -29,6 +29,40 @@ ##################################################################### */ /*}}}*/ + +/** \defgroup acquire Acquire system + * + * \brief The Acquire system is responsible for retrieving files from + * local or remote URIs and postprocessing them (for instance, + * verifying their authenticity). The core class in this system is + * pkgAcquire, which is responsible for managing the download queues + * during the download. There is at least one download queue for + * each supported protocol; protocols such as http may provide one + * queue per host. + * + * Each file to download is represented by a subclass of + * pkgAcquire::Item. The files add themselves to the download + * queue(s) by providing their URI information to + * pkgAcquire::Item::QueueURI, which calls pkgAcquire::Enqueue. + * + * Once the system is set up, the Run method will spawn subprocesses + * to handle the enqueued URIs; the scheduler will then take items + * from the queues and feed them into the handlers until the queues + * are empty. + * + * \todo Acquire supports inserting an object into several queues at + * once, but it is not clear what its behavior in this case is, and + * no subclass of pkgAcquire::Item seems to actually use this + * capability. + */ + +/** \addtogroup acquire + * + * @{ + * + * \file acquire.h + */ + #ifndef PKGLIB_ACQUIRE_H #define PKGLIB_ACQUIRE_H @@ -43,6 +77,15 @@ using std::string; #include <unistd.h> class pkgAcquireStatus; + +/** \brief The core download scheduler. + * + * This class represents an ongoing download. It manages the lists + * of active and pending downloads and handles setting up and tearing + * down download-related structures. + * + * \todo Why all the protected data items and methods? + */ class pkgAcquire { public: @@ -57,97 +100,299 @@ class pkgAcquire typedef vector<Item *>::iterator ItemIterator; typedef vector<Item *>::const_iterator ItemCIterator; - + protected: - // List of items to fetch + /** \brief A list of items to download. + * + * This is built monotonically as items are created and only + * emptied when the download shuts down. + */ vector<Item *> Items; - // List of active queues and fetched method configuration parameters + /** \brief The head of the list of active queues. + * + * \todo why a hand-managed list of queues instead of std::list or + * std::set? + */ Queue *Queues; + + /** \brief The head of the list of active workers. + * + * \todo why a hand-managed list of workers instead of std::list + * or std::set? + */ Worker *Workers; + + /** \brief The head of the list of acquire method configurations. + * + * Each protocol (http, ftp, gzip, etc) via which files can be + * fetched can have a representation in this list. The + * configuration data is filled in by parsing the 100 Capabilities + * string output by a method on startup (see + * pkgAcqMethod::pkgAcqMethod and pkgAcquire::GetConfig). + * + * \todo why a hand-managed config dictionary instead of std::map? + */ MethodConfig *Configs; + + /** \brief The progress indicator for this download. */ pkgAcquireStatus *Log; + + /** \brief The total size of the files which are to be fetched. + * + * This is not necessarily the total number of bytes to download + * when, e.g., download resumption and list updates via patches + * are taken into account. + */ unsigned long ToFetch; - // Configurable parameters for the schedular - enum {QueueHost,QueueAccess} QueueMode; + // Configurable parameters for the scheduler + + /** \brief Represents the queuing strategy for remote URIs. */ + enum QueueStrategy { + /** \brief Generate one queue for each protocol/host combination; downloads from + * multiple hosts can proceed in parallel. + */ + QueueHost, + /** \brief Generate a single queue for each protocol; serialize + * downloads from multiple hosts. + */ + QueueAccess} QueueMode; + + /** \brief If \b true, debugging information will be dumped to std::clog. */ bool Debug; + /** \brief If \b true, a download is currently in progress. */ bool Running; - + + /** \brief Add the given item to the list of items. */ void Add(Item *Item); + + /** \brief Remove the given item from the list of items. */ void Remove(Item *Item); + + /** \brief Add the given worker to the list of workers. */ void Add(Worker *Work); + + /** \brief Remove the given worker from the list of workers. */ void Remove(Worker *Work); + /** \brief Insert the given fetch request into the appropriate queue. + * + * \param Item The URI to download and the item to download it + * for. Copied by value into the queue; no reference to Item is + * retained. + */ void Enqueue(ItemDesc &Item); + + /** \brief Remove all fetch requests for this item from all queues. */ void Dequeue(Item *Item); + + /** \brief Determine the fetch method and queue of a URI. + * + * \param URI The URI to fetch. + * + * \param[out] Config A location in which to place the method via + * which the URI is to be fetched. + * + * \return the string-name of the queue in which a fetch request + * for the given URI should be placed. + */ string QueueName(string URI,MethodConfig const *&Config); - // FDSET managers for derived classes + /** \brief Build up the set of file descriptors upon which select() should + * block. + * + * The default implementation inserts the file descriptors + * corresponding to active downloads. + * + * \param[out] Fd The largest file descriptor in the generated sets. + * + * \param[out] RSet The set of file descriptors that should be + * watched for input. + * + * \param[out] WSet The set of file descriptors that should be + * watched for output. + */ virtual void SetFds(int &Fd,fd_set *RSet,fd_set *WSet); + + /** Handle input from and output to file descriptors which select() + * has determined are ready. The default implementation + * dispatches to all active downloads. + * + * \param RSet The set of file descriptors that are ready for + * input. + * + * \param WSet The set of file descriptors that are ready for + * output. + */ virtual void RunFds(fd_set *RSet,fd_set *WSet); - // A queue calls this when it dequeues an item + /** \brief Check for idle queues with ready-to-fetch items. + * + * Called by pkgAcquire::Queue::Done each time an item is dequeued + * but remains on some queues; i.e., another queue should start + * fetching it. + */ void Bump(); public: + /** \brief Retrieve information about a fetch method by name. + * + * \param Access The name of the method to look up. + * + * \return the method whose name is Access, or \b NULL if no such method exists. + */ MethodConfig *GetConfig(string Access); - enum RunResult {Continue,Failed,Cancelled}; + /** \brief Provides information on how a download terminated. */ + enum RunResult { + /** \brief All files were fetched successfully. */ + Continue, + + /** \brief Some files failed to download. */ + Failed, + + /** \brief The download was cancelled by the user (i.e., #Log's + * pkgAcquireStatus::Pulse() method returned \b false). + */ + Cancelled}; - RunResult Run(int PulseIntervall=500000); + /** \brief Download all the items that have been Add()ed to this + * download process. + * + * This method will block until the download completes, invoking + * methods on #Log to report on the progress of the download. + * + * \param PulseInterval The method pkgAcquireStatus::Pulse will be + * invoked on #Log at intervals of PulseInterval milliseconds. + * + * \return the result of the download. + */ + RunResult Run(int PulseInterval=500000); + + /** \brief Remove all items from this download process, terminate + * all download workers, and empty all queues. + */ void Shutdown(); - // Simple iteration mechanism + /** \brief Get the first #Worker object. + * + * \return the first active worker in this download process. + */ inline Worker *WorkersBegin() {return Workers;}; + + /** \brief Advance to the next #Worker object. + * + * \return the worker immediately following I, or \b NULL if none + * exists. + */ Worker *WorkerStep(Worker *I); + + /** \brief Get the head of the list of items. */ inline ItemIterator ItemsBegin() {return Items.begin();}; + + /** \brief Get the end iterator of the list of items. */ inline ItemIterator ItemsEnd() {return Items.end();}; // Iterate over queued Item URIs class UriIterator; + /** \brief Get the head of the list of enqueued item URIs. + * + * This iterator will step over every element of every active + * queue. + */ UriIterator UriBegin(); + /** \brief Get the end iterator of the list of enqueued item URIs. */ UriIterator UriEnd(); - // Cleans out the download dir + /** Deletes each entry in the given directory that is not being + * downloaded by this object. For instance, when downloading new + * list files, calling Clean() will delete the old ones. + * + * \param Dir The directory to be cleaned out. + * + * \return \b true if the directory exists and is readable. + */ bool Clean(string Dir); - // Returns the size of the total download set + /** \return the total size in bytes of all the items included in + * this download. + */ double TotalNeeded(); + + /** \return the size in bytes of all non-local items included in + * this download. + */ double FetchNeeded(); + + /** \return the amount of data to be fetched that is already + * present on the filesystem. + */ double PartialPresent(); + /** \brief Construct a new pkgAcquire. + * + * \param Log The progress indicator associated with this + * download, or \b NULL for none. This object is not owned by the + * download process and will not be deleted when the pkgAcquire + * object is destroyed. Naturally, it should live for at least as + * long as the pkgAcquire object does. + */ pkgAcquire(pkgAcquireStatus *Log = 0); + + /** \brief Destroy this pkgAcquire object. + * + * Destroys all queue, method, and item objects associated with + * this download. + */ virtual ~pkgAcquire(); }; -// Description of an Item+URI +/** \brief Represents a single download source from which an item + * should be downloaded. + * + * An item may have several assocated ItemDescs over its lifetime. + */ struct pkgAcquire::ItemDesc { + /** \brief The URI from which to download this item. */ string URI; + /** brief A description of this item. */ string Description; + /** brief A shorter description of this item. */ string ShortDesc; + /** brief The underlying item which is to be downloaded. */ Item *Owner; }; -// List of possible items queued for download. +/** \brief A single download queue in a pkgAcquire object. + * + * \todo Why so many protected values? + */ class pkgAcquire::Queue { friend class pkgAcquire; friend class pkgAcquire::UriIterator; friend class pkgAcquire::Worker; + + /** \brief The next queue in the pkgAcquire object's list of queues. */ Queue *Next; protected: - // Queued item + /** \brief A single item placed in this queue. */ struct QItem : pkgAcquire::ItemDesc { - QItem *Next; + /** \brief The next item in the queue. */ + QItem *Next; + /** \brief The worker associated with this item, if any. */ pkgAcquire::Worker *Worker; - + + /** \brief Assign the ItemDesc portion of this QItem from + * another ItemDesc + */ void operator =(pkgAcquire::ItemDesc const &I) { URI = I.URI; @@ -157,45 +402,145 @@ class pkgAcquire::Queue }; }; - // Name of the queue + /** \brief The name of this queue. */ string Name; - // Items queued into this queue + /** \brief The head of the list of items contained in this queue. + * + * \todo why a by-hand list instead of an STL structure? + */ QItem *Items; + + /** \brief The head of the list of workers associated with this queue. + * + * \todo This is plural because support exists in Queue for + * multiple workers. However, it does not appear that there is + * any way to actually associate more than one worker with a + * queue. + * + * \todo Why not just use a std::set? + */ pkgAcquire::Worker *Workers; + + /** \brief the download scheduler with which this queue is associated. */ pkgAcquire *Owner; + + /** \brief The number of entries in this queue that are currently + * being downloaded. + */ signed long PipeDepth; + + /** \brief The maximum number of entries that this queue will + * attempt to download at once. + */ unsigned long MaxPipeDepth; public: - // Put an item into this queue + /** \brief Insert the given fetch request into this queue. + * + * \return \b true if the queuing was successful. May return + * \b false if the Item is already in the queue + */ bool Enqueue(ItemDesc &Item); + + /** \brief Remove all fetch requests for the given item from this queue. + * + * \return \b true if at least one request was removed from the queue. + */ bool Dequeue(Item *Owner); - // Find a Queued item + /** \brief Locate an item in this queue. + * + * \param URI A URI to match against. + * \param Owner A pkgAcquire::Worker to match against. + * + * \return the first item in the queue whose URI is #URI and that + * is being downloaded by #Owner. + */ QItem *FindItem(string URI,pkgAcquire::Worker *Owner); + + /** Presumably this should start downloading an item? + * + * \todo Unimplemented. Implement it or remove? + */ bool ItemStart(QItem *Itm,unsigned long Size); + + /** \brief Remove the given item from this queue and set its state + * to pkgAcquire::Item::StatDone. + * + * If this is the only queue containing the item, the item is also + * removed from the main queue by calling pkgAcquire::Dequeue. + * + * \param Itm The item to remove. + * + * \return \b true if no errors are encountered. + */ bool ItemDone(QItem *Itm); + /** \brief Start the worker process associated with this queue. + * + * If a worker process is already associated with this queue, + * this is equivalent to calling Cycle(). + * + * \return \b true if the startup was successful. + */ bool Startup(); + + /** \brief Shut down the worker process associated with this queue. + * + * \param Final If \b true, then the process is stopped unconditionally. + * Otherwise, it is only stopped if it does not need cleanup + * as indicated by the pkgAcqMethod::NeedsCleanup member of + * its configuration. + * + * \return \b true. + */ bool Shutdown(bool Final); + + /** \brief Send idle items to the worker process. + * + * Fills up the pipeline by inserting idle items into the worker's queue. + */ bool Cycle(); + + /** \brief Check for items that could be enqueued. + * + * Call this after an item placed in multiple queues has gone from + * the pkgAcquire::Item::StatFetching state to the + * pkgAcquire::Item::StatIdle state, to possibly refill an empty queue. + * This is an alias for Cycle(). + * + * \todo Why both this and Cycle()? Are they expected to be + * different someday? + */ void Bump(); + /** \brief Create a new Queue. + * + * \param Name The name of the new queue. + * \param Owner The download process that owns the new queue. + */ Queue(string Name,pkgAcquire *Owner); + + /** Shut down all the worker processes associated with this queue + * and empty the queue. + */ ~Queue(); }; +/** \brief Iterates over all the URIs being fetched by a pkgAcquire object. */ class pkgAcquire::UriIterator { + /** The next queue to iterate over. */ pkgAcquire::Queue *CurQ; + /** The item that we currently point at. */ pkgAcquire::Queue::QItem *CurItem; public: - // Advance to the next item inline void operator ++() {operator ++();}; + void operator ++(int) { CurItem = CurItem->Next; @@ -206,11 +551,14 @@ class pkgAcquire::UriIterator } }; - // Accessors inline pkgAcquire::ItemDesc const *operator ->() const {return CurItem;}; inline bool operator !=(UriIterator const &rhs) const {return rhs.CurQ != CurQ || rhs.CurItem != CurItem;}; inline bool operator ==(UriIterator const &rhs) const {return rhs.CurQ == CurQ && rhs.CurItem == CurItem;}; + /** \brief Create a new UriIterator. + * + * \param Q The queue over which this UriIterator should iterate. + */ UriIterator(pkgAcquire::Queue *Q) : CurQ(Q), CurItem(0) { while (CurItem == 0 && CurQ != 0) @@ -221,61 +569,200 @@ class pkgAcquire::UriIterator } }; -// Configuration information from each method +/** \brief Information about the properties of a single acquire method. */ struct pkgAcquire::MethodConfig { + /** \brief The next link on the acquire method list. + * + * \todo Why not an STL container? + */ MethodConfig *Next; + /** \brief The name of this acquire method (e.g., http). */ string Access; + /** \brief The implementation version of this acquire method. */ string Version; + + /** \brief If \b true, only one download queue should be created for this + * method. + */ bool SingleInstance; + + /** \brief If \b true, this method supports pipelined downloading. */ bool Pipeline; + + /** \brief If \b true, the worker process should send the entire + * APT configuration tree to the fetch subprocess when it starts + * up. + */ bool SendConfig; + + /** \brief If \b true, this fetch method does not require network access; + * all files are to be acquired from the local disk. + */ bool LocalOnly; + + /** \brief If \b true, the subprocess has to carry out some cleanup + * actions before shutting down. + * + * For instance, the cdrom method needs to unmount the CD after it + * finishes. + */ bool NeedsCleanup; + + /** \brief If \b true, this fetch method acquires files from removable media. */ bool Removable; + /** \brief Set up the default method parameters. + * + * All fields are initialized to NULL, "", or \b false as + * appropriate. + */ MethodConfig(); }; +/** \brief A monitor object for downloads controlled by the pkgAcquire class. + * + * \todo Why protected members? + * + * \todo Should the double members be uint64_t? + */ class pkgAcquireStatus { protected: + /** \brief The last time at which this monitor object was updated. */ struct timeval Time; + + /** \brief The time at which the download started. */ struct timeval StartTime; + + /** \brief The number of bytes fetched as of the previous call to + * pkgAcquireStatus::Pulse, including local items. + */ double LastBytes; + + /** \brief The current rate of download as of the most recent call + * to pkgAcquireStatus::Pulse, in bytes per second. + */ double CurrentCPS; + + /** \brief The number of bytes fetched as of the most recent call + * to pkgAcquireStatus::Pulse, including local items. + */ double CurrentBytes; + + /** \brief The total number of bytes that need to be fetched. + * + * \warning This member is inaccurate, as new items might be + * enqueued while the download is in progress! + */ double TotalBytes; + + /** \brief The total number of bytes accounted for by items that + * were successfully fetched. + */ double FetchedBytes; + + /** \brief The amount of time that has elapsed since the download + * started. + */ unsigned long ElapsedTime; + + /** \brief The total number of items that need to be fetched. + * + * \warning This member is inaccurate, as new items might be + * enqueued while the download is in progress! + */ unsigned long TotalItems; + + /** \brief The number of items that have been successfully downloaded. */ unsigned long CurrentItems; public: + /** \brief If \b true, the download scheduler should call Pulse() + * at the next available opportunity. + */ bool Update; + + /** \brief If \b true, extra Pulse() invocations will be performed. + * + * With this option set, Pulse() will be called every time that a + * download item starts downloading, finishes downloading, or + * terminates with an error. + */ bool MorePulses; - // Called by items when they have finished a real download + /** \brief Invoked when a local or remote file has been completely fetched. + * + * \param Size The size of the file fetched. + * + * \param ResumePoint How much of the file was already fetched. + */ virtual void Fetched(unsigned long Size,unsigned long ResumePoint); - // Called to change media + /** \brief Invoked when the user should be prompted to change the + * inserted removable media. + * + * This method should not return until the user has confirmed to + * the user interface that the media change is complete. + * + * \param Media The name of the media type that should be changed. + * + * \param Drive The identifying name of the drive whose media + * should be changed. + * + * \return \b true if the user confirms the media change, \b + * false if it is cancelled. + * + * \todo This is a horrible blocking monster; it should be CPSed + * with prejudice. + */ virtual bool MediaChange(string Media,string Drive) = 0; - // Each of these is called by the workers when an event occures + /** \brief Invoked when an item is confirmed to be up-to-date. + + * For instance, when an HTTP download is informed that the file on + * the server was not modified. + */ virtual void IMSHit(pkgAcquire::ItemDesc &/*Itm*/) {}; + + /** \brief Invoked when some of an item's data is fetched. */ virtual void Fetch(pkgAcquire::ItemDesc &/*Itm*/) {}; + + /** \brief Invoked when an item is successfully and completely fetched. */ virtual void Done(pkgAcquire::ItemDesc &/*Itm*/) {}; + + /** \brief Invoked when the process of fetching an item encounters + * a fatal error. + */ virtual void Fail(pkgAcquire::ItemDesc &/*Itm*/) {}; - virtual bool Pulse(pkgAcquire *Owner); // returns false on user cancel + + /** \brief Periodically invoked while the Acquire process is underway. + * + * Subclasses should first call pkgAcquireStatus::Pulse(), then + * update their status output. The download process is blocked + * while Pulse() is being called. + * + * \return \b false if the user asked to cancel the whole Acquire process. + * + * \see pkgAcquire::Run + */ + virtual bool Pulse(pkgAcquire *Owner); + + /** \brief Invoked when the Acquire process starts running. */ virtual void Start(); + + /** \brief Invoked when the Acquire process stops running. */ virtual void Stop(); + /** \brief Initialize all counters to 0 and the time to the current time. */ pkgAcquireStatus(); virtual ~pkgAcquireStatus() {}; }; +/** @} */ + #endif diff --git a/apt-pkg/algorithms.cc b/apt-pkg/algorithms.cc index 402d01d69..b21fcbb2f 100644 --- a/apt-pkg/algorithms.cc +++ b/apt-pkg/algorithms.cc @@ -23,6 +23,8 @@ #include <apti18n.h> #include <sys/types.h> +#include <cstdlib> +#include <algorithm> #include <iostream> /*}}}*/ using namespace std; diff --git a/apt-pkg/cdrom.cc b/apt-pkg/cdrom.cc index 55f342d9f..4a688a5e1 100644 --- a/apt-pkg/cdrom.cc +++ b/apt-pkg/cdrom.cc @@ -15,6 +15,7 @@ #include <dirent.h> #include <unistd.h> #include <stdio.h> +#include <algorithm> #include "indexcopy.h" @@ -704,7 +705,7 @@ bool pkgCdrom::Add(pkgCdromStatus *log) if(log) { msg.str(""); - ioprintf(msg, "Found label '%s'\n", Name.c_str()); + ioprintf(msg, _("Found label '%s'\n"), Name.c_str()); log->Update(msg.str()); } Database.Set("CD::" + ID + "::Label",Name); @@ -830,7 +831,7 @@ bool pkgCdrom::Add(pkgCdromStatus *log) // Unmount and finish if (_config->FindB("APT::CDROM::NoMount",false) == false) { - log->Update(_("Unmounting CD-ROM..."), STEP_LAST); + log->Update(_("Unmounting CD-ROM...\n"), STEP_LAST); UnmountCdrom(CDROM); } diff --git a/apt-pkg/contrib/fileutl.cc b/apt-pkg/contrib/fileutl.cc index 70ac52e30..d19a92e62 100644 --- a/apt-pkg/contrib/fileutl.cc +++ b/apt-pkg/contrib/fileutl.cc @@ -21,6 +21,7 @@ #include <apti18n.h> +#include <cstdlib> #include <iostream> #include <unistd.h> #include <fcntl.h> diff --git a/apt-pkg/contrib/strutl.cc b/apt-pkg/contrib/strutl.cc index ae5409aa1..006452af4 100644 --- a/apt-pkg/contrib/strutl.cc +++ b/apt-pkg/contrib/strutl.cc @@ -24,6 +24,7 @@ #include <ctype.h> #include <string.h> #include <stdio.h> +#include <algorithm> #include <unistd.h> #include <regex.h> #include <errno.h> diff --git a/apt-pkg/deb/debrecords.cc b/apt-pkg/deb/debrecords.cc index 5421b3db7..8a5b6e215 100644 --- a/apt-pkg/deb/debrecords.cc +++ b/apt-pkg/deb/debrecords.cc @@ -108,18 +108,44 @@ string debRecordParser::LongDesc() return orig; } /*}}}*/ + +static const char *SourceVerSeparators = " ()"; + // RecordParser::SourcePkg - Return the source package name if any /*{{{*/ // --------------------------------------------------------------------- /* */ string debRecordParser::SourcePkg() { string Res = Section.FindS("Source"); - string::size_type Pos = Res.find(' '); + string::size_type Pos = Res.find_first_of(SourceVerSeparators); if (Pos == string::npos) return Res; return string(Res,0,Pos); } /*}}}*/ +// RecordParser::SourceVer - Return the source version number if present /*{{{*/ +// --------------------------------------------------------------------- +/* */ +string debRecordParser::SourceVer() +{ + string Pkg = Section.FindS("Source"); + string::size_type Pos = Pkg.find_first_of(SourceVerSeparators); + if (Pos == string::npos) + return ""; + + string::size_type VerStart = Pkg.find_first_not_of(SourceVerSeparators, Pos); + if(VerStart == string::npos) + return ""; + + string::size_type VerEnd = Pkg.find_first_of(SourceVerSeparators, VerStart); + if(VerEnd == string::npos) + // Corresponds to the case of, e.g., "foo (1.2" without a closing + // paren. Be liberal and guess what it means. + return string(Pkg, VerStart); + else + return string(Pkg, VerStart, VerEnd - VerStart); +} + /*}}}*/ // RecordParser::GetRec - Return the whole record /*{{{*/ // --------------------------------------------------------------------- /* */ diff --git a/apt-pkg/deb/debrecords.h b/apt-pkg/deb/debrecords.h index fdf8d762b..df21931a8 100644 --- a/apt-pkg/deb/debrecords.h +++ b/apt-pkg/deb/debrecords.h @@ -36,6 +36,7 @@ class debRecordParser : public pkgRecords::Parser virtual string MD5Hash(); virtual string SHA1Hash(); virtual string SourcePkg(); + virtual string SourceVer(); // These are some general stats about the package virtual string Maintainer(); diff --git a/apt-pkg/deb/debsrcrecords.cc b/apt-pkg/deb/debsrcrecords.cc index 7338de15d..fcd9bb901 100644 --- a/apt-pkg/deb/debsrcrecords.cc +++ b/apt-pkg/deb/debsrcrecords.cc @@ -36,7 +36,7 @@ const char **debSrcRecordParser::Binaries() { delete [] Buffer; // allocate new size based on buffer (but never smaller than 4000) - BufSize = max((unsigned long)4000, max((unsigned long)Bins.length()+1,2*BufSize)); + BufSize = max((unsigned int)4000, max((unsigned int)Bins.length()+1,2*BufSize)); Buffer = new char[BufSize]; } diff --git a/apt-pkg/deb/debsrcrecords.h b/apt-pkg/deb/debsrcrecords.h index 55fdcb667..8b1237ccd 100644 --- a/apt-pkg/deb/debsrcrecords.h +++ b/apt-pkg/deb/debsrcrecords.h @@ -24,7 +24,7 @@ class debSrcRecordParser : public pkgSrcRecords::Parser char *StaticBinList[400]; unsigned long iOffset; char *Buffer; - unsigned long BufSize; + unsigned int BufSize; public: diff --git a/apt-pkg/depcache.cc b/apt-pkg/depcache.cc index 9f0fa143d..491ba6d4c 100644 --- a/apt-pkg/depcache.cc +++ b/apt-pkg/depcache.cc @@ -240,9 +240,9 @@ bool pkgDepCache::writeStateFile(OpProgress *prog, bool InstalledOnly) std::clog << "Skipping already written " << pkg.Name() << std::endl; continue; } - // skip not installed ones if requested - if(InstalledOnly && pkg->CurrentVer == 0) - continue; + // skip not installed ones if requested + if(InstalledOnly && pkg->CurrentVer == 0) + continue; if(_config->FindB("Debug::pkgAutoRemove",false)) std::clog << "Writing new AutoInstall: " << pkg.Name() << std::endl; @@ -715,7 +715,6 @@ void pkgDepCache::MarkKeep(PkgIterator const &Pkg, bool Soft, bool FromUser) // We dont even try to keep virtual packages.. if (Pkg->VersionList == 0) return; - #if 0 // reseting the autoflag here means we lose the // auto-mark information if a user selects a package for removal // but changes his mind then and sets it for keep again @@ -955,23 +954,22 @@ void pkgDepCache::MarkInstall(PkgIterator const &Pkg,bool AutoInst, std::clog << "Installing " << InstPkg.Name() << " as dep of " << Pkg.Name() << std::endl; - - // now check if we should consider it a automatic dependency or not - string sec = _config->Find("APT::Never-MarkAuto-Section",""); - if(Pkg.Section() && (string(Pkg.Section()) == sec)) - { - if(_config->FindB("Debug::pkgDepCache::AutoInstall",false) == true) - std::clog << "Setting NOT as auto-installed because its a direct dep of a package in section " << sec << std::endl; - MarkInstall(InstPkg,true,Depth + 1, true, ForceImportantDeps); - } - else - { - // mark automatic dependency - MarkInstall(InstPkg,true,Depth + 1, false, ForceImportantDeps); - // Set the autoflag, after MarkInstall because MarkInstall unsets it - if (P->CurrentVer == 0) - PkgState[InstPkg->ID].Flags |= Flag::Auto; - } + // now check if we should consider it a automatic dependency or not + string sec = _config->Find("APT::Never-MarkAuto-Section",""); + if(Pkg.Section() && (string(Pkg.Section()) == sec)) + { + if(_config->FindB("Debug::pkgDepCache::AutoInstall",false) == true) + std::clog << "Setting NOT as auto-installed because its a direct dep of a package in section " << sec << std::endl; + MarkInstall(InstPkg,true,Depth + 1, true); + } + else + { + // mark automatic dependency + MarkInstall(InstPkg,true,Depth + 1, false, ForceImportantDeps); + // Set the autoflag, after MarkInstall because MarkInstall unsets it + if (P->CurrentVer == 0) + PkgState[InstPkg->ID].Flags |= Flag::Auto; + } } continue; } @@ -1382,3 +1380,4 @@ bool pkgDepCache::Policy::IsImportantDep(DepIterator Dep) return false; } /*}}}*/ + diff --git a/apt-pkg/indexfile.cc b/apt-pkg/indexfile.cc index 2dda2d892..ca11fc111 100644 --- a/apt-pkg/indexfile.cc +++ b/apt-pkg/indexfile.cc @@ -71,7 +71,7 @@ string pkgIndexFile::SourceInfo(pkgSrcRecords::Parser const &Record, /* */ bool pkgIndexFile::TranslationsAvailable() { - const string Translation = _config->Find("APT::Acquire::Translation", "environment"); + const string Translation = _config->Find("APT::Acquire::Translation"); if (Translation.compare("none") != 0) return CheckLanguageCode(LanguageCode().c_str()); @@ -103,7 +103,7 @@ bool pkgIndexFile::CheckLanguageCode(const char *Lang) /* return the language code */ string pkgIndexFile::LanguageCode() { - const string Translation = _config->Find("APT::Acquire::Translation", "environment"); + const string Translation = _config->Find("APT::Acquire::Translation"); if (Translation.compare("environment") == 0) { diff --git a/apt-pkg/init.cc b/apt-pkg/init.cc index f58855792..a209d7477 100644 --- a/apt-pkg/init.cc +++ b/apt-pkg/init.cc @@ -14,6 +14,7 @@ #include <apti18n.h> #include <config.h> +#include <cstdlib> #include <sys/stat.h> /*}}}*/ @@ -105,7 +106,9 @@ bool pkgInitConfig(Configuration &Cnf) bindtextdomain(textdomain(0),Cnf.FindDir("Dir::Locale").c_str()); } #endif - + // Translation + Cnf.Set("APT::Acquire::Translation", "environment"); + return true; } /*}}}*/ diff --git a/apt-pkg/init.h b/apt-pkg/init.h index 905173a7a..bc0e55036 100644 --- a/apt-pkg/init.h +++ b/apt-pkg/init.h @@ -17,8 +17,8 @@ #include <apt-pkg/pkgsystem.h> // See the makefile -#define APT_PKG_MAJOR 3 -#define APT_PKG_MINOR 53 +#define APT_PKG_MAJOR 4 +#define APT_PKG_MINOR 4 #define APT_PKG_RELEASE 0 extern const char *pkgVersion; diff --git a/apt-pkg/makefile b/apt-pkg/makefile index d36747d85..df9954f67 100644 --- a/apt-pkg/makefile +++ b/apt-pkg/makefile @@ -13,7 +13,7 @@ include ../buildlib/defaults.mak # methods/makefile - FIXME LIBRARY=apt-pkg LIBEXT=$(GLIBC_VER)$(LIBSTDCPP_VER) -MAJOR=3.53 +MAJOR=4.4 MINOR=0 SLIBS=$(PTHREADLIB) $(INTLLIBS) APT_DOMAIN:=libapt-pkg$(MAJOR) diff --git a/apt-pkg/pkgrecords.h b/apt-pkg/pkgrecords.h index bae5284ab..7b9f51a50 100644 --- a/apt-pkg/pkgrecords.h +++ b/apt-pkg/pkgrecords.h @@ -58,6 +58,7 @@ class pkgRecords::Parser virtual string MD5Hash() {return string();}; virtual string SHA1Hash() {return string();}; virtual string SourcePkg() {return string();}; + virtual string SourceVer() {return string();}; // These are some general stats about the package virtual string Maintainer() {return string();}; |