From b2e465d6d32d2dc884f58b94acb7e35f671a87fe Mon Sep 17 00:00:00 2001 From: Arch Librarian Date: Mon, 20 Sep 2004 16:56:32 +0000 Subject: Join with aliencode Author: jgg Date: 2001-02-20 07:03:16 GMT Join with aliencode --- apt-pkg/acquire-item.cc | 142 ++++---- apt-pkg/acquire-item.h | 20 +- apt-pkg/acquire-method.cc | 10 +- apt-pkg/acquire-method.h | 6 +- apt-pkg/acquire-worker.cc | 16 +- apt-pkg/acquire-worker.h | 6 +- apt-pkg/acquire.cc | 26 +- apt-pkg/acquire.h | 25 +- apt-pkg/algorithms.cc | 223 +++++++++---- apt-pkg/algorithms.h | 25 +- apt-pkg/cachefile.cc | 90 +++-- apt-pkg/cachefile.h | 31 +- apt-pkg/cacheiterators.h | 50 +-- apt-pkg/clean.cc | 28 +- apt-pkg/contrib/cdromutl.cc | 14 +- apt-pkg/contrib/cmndline.cc | 30 +- apt-pkg/contrib/configuration.cc | 406 +++++++++++++++++++---- apt-pkg/contrib/configuration.h | 57 +++- apt-pkg/contrib/error.cc | 4 +- apt-pkg/contrib/error.h | 22 +- apt-pkg/contrib/fileutl.cc | 107 ++++-- apt-pkg/contrib/fileutl.h | 7 +- apt-pkg/contrib/md5.h | 4 +- apt-pkg/contrib/mmap.cc | 23 +- apt-pkg/contrib/progress.cc | 14 +- apt-pkg/contrib/sptr.h | 66 ++++ apt-pkg/contrib/strutl.cc | 163 +++++++++- apt-pkg/contrib/strutl.h | 38 ++- apt-pkg/deb/debindexfile.cc | 506 ++++++++++++++++++++++++++++ apt-pkg/deb/debindexfile.h | 112 +++++++ apt-pkg/deb/deblistparser.cc | 221 ++++++++----- apt-pkg/deb/deblistparser.h | 36 +- apt-pkg/deb/debrecords.cc | 23 +- apt-pkg/deb/debrecords.h | 12 +- apt-pkg/deb/debsrcrecords.cc | 97 ++++-- apt-pkg/deb/debsrcrecords.h | 24 +- apt-pkg/deb/debsystem.cc | 197 +++++++++++ apt-pkg/deb/debsystem.h | 41 +++ apt-pkg/deb/debversion.cc | 266 +++++++++++++++ apt-pkg/deb/debversion.h | 72 ++++ apt-pkg/deb/dpkginit.cc | 119 ------- apt-pkg/deb/dpkginit.h | 34 -- apt-pkg/deb/dpkgpm.cc | 162 +++++++-- apt-pkg/deb/dpkgpm.h | 8 +- apt-pkg/depcache.cc | 255 +++++++++------ apt-pkg/depcache.h | 72 ++-- apt-pkg/indexfile.cc | 77 +++++ apt-pkg/indexfile.h | 80 +++++ apt-pkg/init.cc | 105 ++++-- apt-pkg/init.h | 28 +- apt-pkg/makefile | 43 +-- apt-pkg/orderlist.cc | 119 ++++--- apt-pkg/orderlist.h | 21 +- apt-pkg/packagemanager.cc | 56 ++-- apt-pkg/packagemanager.h | 25 +- apt-pkg/pkgcache.cc | 245 ++++++++------ apt-pkg/pkgcache.h | 64 +++- apt-pkg/pkgcachegen.cc | 688 ++++++++++++++------------------------- apt-pkg/pkgcachegen.h | 41 ++- apt-pkg/pkgrecords.cc | 45 +-- apt-pkg/pkgrecords.h | 27 +- apt-pkg/pkgsystem.cc | 45 +++ apt-pkg/pkgsystem.h | 95 ++++++ apt-pkg/policy.cc | 275 ++++++++++++++++ apt-pkg/policy.h | 83 +++++ apt-pkg/sourcelist.cc | 424 ++++++++---------------- apt-pkg/sourcelist.h | 61 ++-- apt-pkg/srcrecords.cc | 68 ++-- apt-pkg/srcrecords.h | 47 ++- apt-pkg/tagfile.cc | 282 ++++++++++++++-- apt-pkg/tagfile.h | 49 ++- apt-pkg/version.cc | 261 +-------------- apt-pkg/version.h | 69 +++- apt-pkg/versionmatch.cc | 210 ++++++++++++ apt-pkg/versionmatch.h | 69 ++++ 75 files changed, 5330 insertions(+), 2282 deletions(-) create mode 100644 apt-pkg/contrib/sptr.h create mode 100644 apt-pkg/deb/debindexfile.cc create mode 100644 apt-pkg/deb/debindexfile.h create mode 100644 apt-pkg/deb/debsystem.cc create mode 100644 apt-pkg/deb/debsystem.h create mode 100644 apt-pkg/deb/debversion.cc create mode 100644 apt-pkg/deb/debversion.h delete mode 100644 apt-pkg/deb/dpkginit.cc delete mode 100644 apt-pkg/deb/dpkginit.h create mode 100644 apt-pkg/indexfile.cc create mode 100644 apt-pkg/indexfile.h create mode 100644 apt-pkg/pkgsystem.cc create mode 100644 apt-pkg/pkgsystem.h create mode 100644 apt-pkg/policy.cc create mode 100644 apt-pkg/policy.h create mode 100644 apt-pkg/versionmatch.cc create mode 100644 apt-pkg/versionmatch.h (limited to 'apt-pkg') diff --git a/apt-pkg/acquire-item.cc b/apt-pkg/acquire-item.cc index 0de5eef7c..431382ef1 100644 --- a/apt-pkg/acquire-item.cc +++ b/apt-pkg/acquire-item.cc @@ -1,6 +1,6 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ -// $Id: acquire-item.cc,v 1.41 2000/01/17 07:11:49 jgg Exp $ +// $Id: acquire-item.cc,v 1.42 2001/02/20 07:03:17 jgg Exp $ /* ###################################################################### Acquire Item - Item to acquire @@ -18,10 +18,13 @@ #endif #include #include +#include #include #include #include +#include + #include #include #include @@ -116,7 +119,7 @@ void pkgAcquire::Item::Rename(string From,string To) if (rename(From.c_str(),To.c_str()) != 0) { char S[300]; - sprintf(S,"rename failed, %s (%s -> %s).",strerror(errno), + sprintf(S,_("rename failed, %s (%s -> %s)."),strerror(errno), From.c_str(),To.c_str()); Status = StatError; ErrorText = S; @@ -127,31 +130,24 @@ void pkgAcquire::Item::Rename(string From,string To) // 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,const pkgSourceList::Item *Location) : - Item(Owner), Location(Location) + instantiated to fetch the revision file */ +pkgAcqIndex::pkgAcqIndex(pkgAcquire *Owner, + string URI,string URIDesc,string ShortDesc) : + Item(Owner), RealURI(URI) { Decompression = false; Erase = false; DestFile = _config->FindDir("Dir::State::lists") + "partial/"; - DestFile += URItoFileName(Location->PackagesURI()); + DestFile += URItoFileName(URI); // Create the item - Desc.URI = Location->PackagesURI() + ".gz"; - Desc.Description = Location->PackagesInfo(); + Desc.URI = URI + ".gz"; + Desc.Description = URIDesc; Desc.Owner = this; - - // Set the short description to the archive component - if (Location->Dist[Location->Dist.size() - 1] == '/') - Desc.ShortDesc = Location->Dist; - else - Desc.ShortDesc = Location->Dist + '/' + Location->Section; + Desc.ShortDesc = ShortDesc; QueueURI(Desc); - - // Create the Release fetch class - new pkgAcqIndexRel(Owner,Location); } /*}}}*/ // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/ @@ -160,7 +156,7 @@ pkgAcqIndex::pkgAcqIndex(pkgAcquire *Owner,const pkgSourceList::Item *Location) string pkgAcqIndex::Custom600Headers() { string Final = _config->FindDir("Dir::State::lists"); - Final += URItoFileName(Location->PackagesURI()); + Final += URItoFileName(RealURI); struct stat Buf; if (stat(Final.c_str(),&Buf) != 0) @@ -185,13 +181,13 @@ void pkgAcqIndex::Done(string Message,unsigned long Size,string MD5, { // Done, move it into position string FinalFile = _config->FindDir("Dir::State::lists"); - FinalFile += URItoFileName(Location->PackagesURI()); + FinalFile += URItoFileName(RealURI); Rename(DestFile,FinalFile); /* We restore the original name to DestFile so that the clean operation will work OK */ DestFile = _config->FindDir("Dir::State::lists") + "partial/"; - DestFile += URItoFileName(Location->PackagesURI()); + DestFile += URItoFileName(RealURI); // Remove the compressed version. if (Erase == true) @@ -237,7 +233,7 @@ void pkgAcqIndex::Done(string Message,unsigned long Size,string MD5, Decompression = true; DestFile += ".decomp"; - Desc.URI = "gzip:" + FileName,Location->PackagesInfo(); + Desc.URI = "gzip:" + FileName; QueueURI(Desc); Mode = "gzip"; } @@ -247,23 +243,18 @@ void pkgAcqIndex::Done(string Message,unsigned long Size,string MD5, // --------------------------------------------------------------------- /* The Release file is added to the queue */ pkgAcqIndexRel::pkgAcqIndexRel(pkgAcquire *Owner, - const pkgSourceList::Item *Location) : - Item(Owner), Location(Location) + string URI,string URIDesc,string ShortDesc) : + Item(Owner), RealURI(URI) { DestFile = _config->FindDir("Dir::State::lists") + "partial/"; - DestFile += URItoFileName(Location->ReleaseURI()); + DestFile += URItoFileName(URI); // Create the item - Desc.URI = Location->ReleaseURI(); - Desc.Description = Location->ReleaseInfo(); + Desc.URI = URI; + Desc.Description = URIDesc; + Desc.ShortDesc = ShortDesc; Desc.Owner = this; - // Set the short description to the archive component - if (Location->Dist[Location->Dist.size() - 1] == '/') - Desc.ShortDesc = Location->Dist; - else - Desc.ShortDesc = Location->Dist + '/' + Location->Section; - QueueURI(Desc); } /*}}}*/ @@ -273,7 +264,7 @@ pkgAcqIndexRel::pkgAcqIndexRel(pkgAcquire *Owner, string pkgAcqIndexRel::Custom600Headers() { string Final = _config->FindDir("Dir::State::lists"); - Final += URItoFileName(Location->ReleaseURI()); + Final += URItoFileName(RealURI); struct stat Buf; if (stat(Final.c_str(),&Buf) != 0) @@ -317,7 +308,7 @@ void pkgAcqIndexRel::Done(string Message,unsigned long Size,string MD5, // Done, move it into position string FinalFile = _config->FindDir("Dir::State::lists"); - FinalFile += URItoFileName(Location->ReleaseURI()); + FinalFile += URItoFileName(RealURI); Rename(DestFile,FinalFile); } /*}}}*/ @@ -354,21 +345,42 @@ pkgAcqArchive::pkgAcqArchive(pkgAcquire *Owner,pkgSourceList *Sources, if (Version.Arch() == 0) { - _error->Error("I wasn't able to locate file for the %s package. " - "This might mean you need to manually fix this package. (due to missing arch)", + _error->Error(_("I wasn't able to locate file for the %s package. " + "This might mean you need to manually fix this package. (due to missing arch)"), Version.ParentPkg().Name()); return; } - // Generate the final file name as: package_version_arch.deb - StoreFilename = QuoteString(Version.ParentPkg().Name(),"_:") + '_' + - QuoteString(Version.VerStr(),"_:") + '_' + - QuoteString(Version.Arch(),"_:.") + ".deb"; - + /* We need to find a filename to determine the extension. We make the + assumption here that all the available sources for this version share + the same extension.. */ + // Skip not source sources, they do not have file fields. + for (; Vf.end() == false; Vf++) + { + if ((Vf.File()->Flags & pkgCache::Flag::NotSource) != 0) + continue; + break; + } + + // Does not really matter here.. we are going to fail out below + if (Vf.end() != true) + { + // If this fails to get a file name we will bomb out below. + pkgRecords::Parser &Parse = Recs->Lookup(Vf); + if (_error->PendingError() == true) + return; + + // Generate the final file name as: package_version_arch.foo + StoreFilename = QuoteString(Version.ParentPkg().Name(),"_:") + '_' + + QuoteString(Version.VerStr(),"_:") + '_' + + QuoteString(Version.Arch(),"_:.") + + "." + flExtension(Parse.FileName()); + } + // Select a source if (QueueNext() == false && _error->PendingError() == false) - _error->Error("I wasn't able to locate file for the %s package. " - "This might mean you need to manually fix this package.", + _error->Error(_("I wasn't able to locate file for the %s package. " + "This might mean you need to manually fix this package."), Version.ParentPkg().Name()); } /*}}}*/ @@ -378,7 +390,7 @@ pkgAcqArchive::pkgAcqArchive(pkgAcquire *Owner,pkgSourceList *Sources, the archive is already available in the cache and stashs the MD5 for checking later. */ bool pkgAcqArchive::QueueNext() -{ +{ for (; Vf.end() == false; Vf++) { // Ignore not source sources @@ -386,26 +398,21 @@ bool pkgAcqArchive::QueueNext() continue; // Try to cross match against the source list - string PkgFile = flNotDir(Vf.File().FileName()); - pkgSourceList::const_iterator Location; - for (Location = Sources->begin(); Location != Sources->end(); Location++) - if (PkgFile == URItoFileName(Location->PackagesURI())) - break; - - if (Location == Sources->end()) - continue; + pkgIndexFile *Index; + if (Sources->FindIndex(Vf.File(),Index) == false) + continue; // Grab the text package record pkgRecords::Parser &Parse = Recs->Lookup(Vf); if (_error->PendingError() == true) return false; - PkgFile = Parse.FileName(); + string PkgFile = Parse.FileName(); MD5 = Parse.MD5Hash(); if (PkgFile.empty() == true) - return _error->Error("The package index files are corrupted. No Filename: " - "field for package %s." - ,Version.ParentPkg().Name()); + return _error->Error(_("The package index files are corrupted. No Filename: " + "field for package %s."), + Version.ParentPkg().Name()); // See if we already have the file. (Legacy filenames) FileSize = Version->Size; @@ -460,8 +467,9 @@ bool pkgAcqArchive::QueueNext() } // Create the item - Desc.URI = Location->ArchiveURI(PkgFile); - Desc.Description = Location->ArchiveInfo(Version); + Local = false; + Desc.URI = Index->ArchiveURI(PkgFile); + Desc.Description = Index->ArchiveInfo(Version); Desc.Owner = this; Desc.ShortDesc = Version.ParentPkg().Name(); QueueURI(Desc); @@ -484,7 +492,7 @@ void pkgAcqArchive::Done(string Message,unsigned long Size,string Md5Hash, if (Size != Version->Size) { Status = StatError; - ErrorText = "Size mismatch"; + ErrorText = _("Size mismatch"); return; } @@ -494,7 +502,7 @@ void pkgAcqArchive::Done(string Message,unsigned long Size,string Md5Hash, if (Md5Hash != MD5) { Status = StatError; - ErrorText = "MD5Sum mismatch"; + ErrorText = _("MD5Sum mismatch"); Rename(DestFile,DestFile + ".FAILED"); return; } @@ -534,6 +542,20 @@ void pkgAcqArchive::Done(string Message,unsigned long Size,string Md5Hash, void pkgAcqArchive::Failed(string Message,pkgAcquire::MethodConfig *Cnf) { ErrorText = LookupTag(Message,"Message"); + + /* We don't really want to retry on failed media swaps, this prevents + that. An interesting observation is that permanent failures are not + recorded. */ + if (Cnf->Removable == true && + StringToBool(LookupTag(Message,"Transient-Failure"),false) == true) + { + // Vf = Version.FileList(); + while (Vf.end() == false) Vf++; + StoreFilename = string(); + Item::Failed(Message,Cnf); + return; + } + if (QueueNext() == false) { // This is the retry counter diff --git a/apt-pkg/acquire-item.h b/apt-pkg/acquire-item.h index bf1a50e75..3d411978e 100644 --- a/apt-pkg/acquire-item.h +++ b/apt-pkg/acquire-item.h @@ -1,6 +1,6 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ -// $Id: acquire-item.h,v 1.24 2000/01/27 04:15:09 jgg Exp $ +// $Id: acquire-item.h,v 1.25 2001/02/20 07:03:17 jgg Exp $ /* ###################################################################### Acquire Item - Item to acquire @@ -21,7 +21,7 @@ #define PKGLIB_ACQUIRE_ITEM_H #include -#include +#include #include #ifdef __GNUG__ @@ -49,7 +49,7 @@ class pkgAcquire::Item string ErrorText; unsigned long FileSize; unsigned long PartialSize; - char *Mode; + const char *Mode; unsigned long ID; bool Complete; bool Local; @@ -82,10 +82,10 @@ class pkgAcqIndex : public pkgAcquire::Item { protected: - const pkgSourceList::Item *Location; bool Decompression; bool Erase; pkgAcquire::ItemDesc Desc; + string RealURI; public: @@ -93,9 +93,10 @@ class pkgAcqIndex : public pkgAcquire::Item virtual void Done(string Message,unsigned long Size,string Md5Hash, pkgAcquire::MethodConfig *Cnf); virtual string Custom600Headers(); - virtual string DescURI() {return Location->PackagesURI();}; + virtual string DescURI() {return RealURI;}; - pkgAcqIndex(pkgAcquire *Owner,const pkgSourceList::Item *Location); + pkgAcqIndex(pkgAcquire *Owner,string URI,string URIDesc, + string ShortDesct); }; // Item class for index files @@ -103,8 +104,8 @@ class pkgAcqIndexRel : public pkgAcquire::Item { protected: - const pkgSourceList::Item *Location; pkgAcquire::ItemDesc Desc; + string RealURI; public: @@ -113,9 +114,10 @@ class pkgAcqIndexRel : public pkgAcquire::Item virtual void Done(string Message,unsigned long Size,string Md5Hash, pkgAcquire::MethodConfig *Cnf); virtual string Custom600Headers(); - virtual string DescURI() {return Location->ReleaseURI();}; + virtual string DescURI() {return RealURI;}; - pkgAcqIndexRel(pkgAcquire *Owner,const pkgSourceList::Item *Location); + pkgAcqIndexRel(pkgAcquire *Owner,string URI,string URIDesc, + string ShortDesct); }; // Item class for archive files diff --git a/apt-pkg/acquire-method.cc b/apt-pkg/acquire-method.cc index 770c68a90..3b905f4e9 100644 --- a/apt-pkg/acquire-method.cc +++ b/apt-pkg/acquire-method.cc @@ -1,12 +1,12 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ -// $Id: acquire-method.cc,v 1.24 2000/01/17 07:11:49 jgg Exp $ +// $Id: acquire-method.cc,v 1.25 2001/02/20 07:03:17 jgg Exp $ /* ###################################################################### Acquire Method This is a skeleton class that implements most of the functionality - of a method and some usefull functions to make method implementation + of a method and some useful functions to make method implementation simpler. The methods all derive this and specialize it. The most complex implementation is the http method which needs to provide pipelining, it runs the message engine at the same time it is @@ -97,7 +97,8 @@ void pkgAcqMethod::Fail(string Err,bool Transient) if (Queue != 0) { snprintf(S,sizeof(S)-50,"400 URI Failure\nURI: %s\n" - "Message: %s\n",Queue->Uri.c_str(),Err.c_str()); + "Message: %s %s\n",Queue->Uri.c_str(),Err.c_str(), + FailExtra.c_str()); // Dequeue FetchItem *Tmp = Queue; @@ -108,7 +109,8 @@ void pkgAcqMethod::Fail(string Err,bool Transient) } else snprintf(S,sizeof(S)-50,"400 URI Failure\nURI: \n" - "Message: %s\n",Err.c_str()); + "Message: %s %s\n",Err.c_str(), + FailExtra.c_str()); // Set the transient flag if (Transient == true) diff --git a/apt-pkg/acquire-method.h b/apt-pkg/acquire-method.h index 64cff7331..b32d80c43 100644 --- a/apt-pkg/acquire-method.h +++ b/apt-pkg/acquire-method.h @@ -1,6 +1,6 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ -// $Id: acquire-method.h,v 1.13 2000/01/17 07:11:49 jgg Exp $ +// $Id: acquire-method.h,v 1.14 2001/02/20 07:03:17 jgg Exp $ /* ###################################################################### Acquire Method - Method helper class + functions @@ -49,7 +49,8 @@ class pkgAcqMethod vector Messages; FetchItem *Queue; FetchItem *QueueBack; - + string FailExtra; + // Handlers for messages virtual bool Configuration(string Message); virtual bool Fetch(FetchItem * /*Item*/) {return true;}; @@ -74,6 +75,7 @@ class pkgAcqMethod void Status(const char *Format,...); int Run(bool Single = false); + inline void SetFailExtraMsg(string Msg) {FailExtra = Msg;}; pkgAcqMethod(const char *Ver,unsigned long Flags = 0); virtual ~pkgAcqMethod() {}; diff --git a/apt-pkg/acquire-worker.cc b/apt-pkg/acquire-worker.cc index a2f970ab6..4805b5ebc 100644 --- a/apt-pkg/acquire-worker.cc +++ b/apt-pkg/acquire-worker.cc @@ -1,6 +1,6 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ -// $Id: acquire-worker.cc,v 1.31 2000/05/10 05:56:46 jgg Exp $ +// $Id: acquire-worker.cc,v 1.32 2001/02/20 07:03:17 jgg Exp $ /* ###################################################################### Acquire Worker @@ -22,6 +22,8 @@ #include #include +#include + #include #include #include @@ -102,7 +104,7 @@ bool pkgAcquire::Worker::Start() // Get the method path string Method = _config->FindDir("Dir::Bin::Methods") + Access; if (FileExists(Method) == false) - return _error->Error("The method driver %s could not be found.",Method.c_str()); + return _error->Error(_("The method driver %s could not be found."),Method.c_str()); if (Debug == true) clog << "Starting method '" << Method << '\'' << endl; @@ -154,7 +156,7 @@ bool pkgAcquire::Worker::Start() // Read the configuration data if (WaitFd(InFd) == false || ReadMessages() == false) - return _error->Error("Method %s did not start correctly",Method.c_str()); + return _error->Error(_("Method %s did not start correctly"),Method.c_str()); RunMessages(); if (OwnerQ != 0) @@ -260,9 +262,9 @@ bool pkgAcquire::Worker::RunMessages() Log->Pulse(Owner->GetOwner()); OwnerQ->ItemDone(Itm); - if (TotalSize != 0 && + if (TotalSize != 0 && (unsigned)atoi(LookupTag(Message,"Size","0").c_str()) != TotalSize) - _error->Warning("Bizzar Error - File size is not what the server reported %s %u", + _error->Warning("Bizarre Error - File size is not what the server reported %s %lu", LookupTag(Message,"Size","0").c_str(),TotalSize); Owner->Done(Message,atoi(LookupTag(Message,"Size","0").c_str()), @@ -313,7 +315,7 @@ bool pkgAcquire::Worker::RunMessages() // 401 General Failure case 401: - _error->Error("Method %s General failure: %s",LookupTag(Message,"Message").c_str()); + _error->Error("Method %s General failure: %s",Access.c_str(),LookupTag(Message,"Message").c_str()); break; // 403 Media Change @@ -405,7 +407,7 @@ bool pkgAcquire::Worker::SendConfiguration() { if (Top->Value.empty() == false) { - string Line = "Config-Item: " + Top->FullTag() + "="; + string Line = "Config-Item: " + QuoteString(Top->FullTag(),"=\"\n") + "="; Line += QuoteString(Top->Value,"\n") + '\n'; Message += Line; } diff --git a/apt-pkg/acquire-worker.h b/apt-pkg/acquire-worker.h index 797ea3f7c..6e1952202 100644 --- a/apt-pkg/acquire-worker.h +++ b/apt-pkg/acquire-worker.h @@ -1,6 +1,6 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ -// $Id: acquire-worker.h,v 1.11 1999/10/18 00:37:35 jgg Exp $ +// $Id: acquire-worker.h,v 1.12 2001/02/20 07:03:17 jgg Exp $ /* ###################################################################### Acquire Worker - Worker process manager @@ -21,10 +21,10 @@ // Interfacing to the method process class pkgAcquire::Worker { - friend pkgAcquire; + friend class pkgAcquire; protected: - friend Queue; + friend class Queue; /* Linked list starting at a Queue and a linked list starting at Acquire */ diff --git a/apt-pkg/acquire.cc b/apt-pkg/acquire.cc index 428bfd50f..1be8551f4 100644 --- a/apt-pkg/acquire.cc +++ b/apt-pkg/acquire.cc @@ -1,6 +1,6 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ -// $Id: acquire.cc,v 1.46 2000/01/27 04:15:09 jgg Exp $ +// $Id: acquire.cc,v 1.47 2001/02/20 07:03:17 jgg Exp $ /* ###################################################################### Acquire - File Acquiration @@ -23,6 +23,8 @@ #include #include +#include + #include #include #include @@ -52,11 +54,11 @@ pkgAcquire::pkgAcquire(pkgAcquireStatus *Log) : Log(Log) struct stat St; if (stat((_config->FindDir("Dir::State::lists") + "partial/").c_str(),&St) != 0 || S_ISDIR(St.st_mode) == 0) - _error->Error("Lists directory %spartial is missing.", + _error->Error(_("Lists directory %spartial is missing."), _config->FindDir("Dir::State::lists").c_str()); if (stat((_config->FindDir("Dir::Cache::Archives") + "partial/").c_str(),&St) != 0 || S_ISDIR(St.st_mode) == 0) - _error->Error("Archive directory %spartial is missing.", + _error->Error(_("Archive directory %spartial is missing."), _config->FindDir("Dir::Cache::Archives").c_str()); } /*}}}*/ @@ -398,13 +400,13 @@ bool pkgAcquire::Clean(string Dir) { DIR *D = opendir(Dir.c_str()); if (D == 0) - return _error->Errno("opendir","Unable to read %s",Dir.c_str()); + return _error->Errno("opendir",_("Unable to read %s"),Dir.c_str()); string StartDir = SafeGetCWD(); if (chdir(Dir.c_str()) != 0) { closedir(D); - return _error->Errno("chdir","Unable to change to ",Dir.c_str()); + return _error->Errno("chdir",_("Unable to change to %s"),Dir.c_str()); } for (struct dirent *Dir = readdir(D); Dir != 0; Dir = readdir(D)) @@ -435,9 +437,9 @@ bool pkgAcquire::Clean(string Dir) // Acquire::TotalNeeded - Number of bytes to fetch /*{{{*/ // --------------------------------------------------------------------- /* This is the total number of bytes needed */ -unsigned long pkgAcquire::TotalNeeded() +double pkgAcquire::TotalNeeded() { - unsigned long Total = 0; + double Total = 0; for (pkgAcquire::Item **I = ItemsBegin(); I != ItemsEnd(); I++) Total += (*I)->FileSize; return Total; @@ -446,9 +448,9 @@ unsigned long pkgAcquire::TotalNeeded() // Acquire::FetchNeeded - Number of bytes needed to get /*{{{*/ // --------------------------------------------------------------------- /* This is the number of bytes that is not local */ -unsigned long pkgAcquire::FetchNeeded() +double pkgAcquire::FetchNeeded() { - unsigned long Total = 0; + double Total = 0; for (pkgAcquire::Item **I = ItemsBegin(); I != ItemsEnd(); I++) if ((*I)->Local == false) Total += (*I)->FileSize; @@ -458,9 +460,9 @@ unsigned long pkgAcquire::FetchNeeded() // Acquire::PartialPresent - Number of partial bytes we already have /*{{{*/ // --------------------------------------------------------------------- /* This is the number of bytes that is not local */ -unsigned long pkgAcquire::PartialPresent() +double pkgAcquire::PartialPresent() { - unsigned long Total = 0; + double Total = 0; for (pkgAcquire::Item **I = ItemsBegin(); I != ItemsEnd(); I++) if ((*I)->Local == false) Total += (*I)->PartialSize; @@ -736,7 +738,7 @@ bool pkgAcquireStatus::Pulse(pkgAcquire *Owner) // Totally ignore local items if ((*I)->Local == true) continue; - + TotalBytes += (*I)->FileSize; if ((*I)->Complete == true) CurrentBytes += (*I)->FileSize; diff --git a/apt-pkg/acquire.h b/apt-pkg/acquire.h index de1474f56..d5b759cb3 100644 --- a/apt-pkg/acquire.h +++ b/apt-pkg/acquire.h @@ -1,6 +1,6 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ -// $Id: acquire.h,v 1.27 2000/01/27 04:15:09 jgg Exp $ +// $Id: acquire.h,v 1.28 2001/02/20 07:03:17 jgg Exp $ /* ###################################################################### Acquire - File Acquiration @@ -52,8 +52,8 @@ class pkgAcquire class Worker; struct MethodConfig; struct ItemDesc; - friend Item; - friend Queue; + friend class Item; + friend class Queue; protected: @@ -112,9 +112,9 @@ class pkgAcquire bool Clean(string Dir); // Returns the size of the total download set - unsigned long TotalNeeded(); - unsigned long FetchNeeded(); - unsigned long PartialPresent(); + double TotalNeeded(); + double FetchNeeded(); + double PartialPresent(); pkgAcquire(pkgAcquireStatus *Log = 0); virtual ~pkgAcquire(); @@ -132,8 +132,9 @@ struct pkgAcquire::ItemDesc // List of possible items queued for download. class pkgAcquire::Queue { - friend pkgAcquire; - friend pkgAcquire::UriIterator; + friend class pkgAcquire; + friend class pkgAcquire::UriIterator; + friend class pkgAcquire::Worker; Queue *Next; protected: @@ -241,11 +242,11 @@ class pkgAcquireStatus struct timeval Time; struct timeval StartTime; - unsigned long LastBytes; + double LastBytes; double CurrentCPS; - unsigned long CurrentBytes; - unsigned long TotalBytes; - unsigned long FetchedBytes; + double CurrentBytes; + double TotalBytes; + double FetchedBytes; unsigned long ElapsedTime; unsigned long TotalItems; unsigned long CurrentItems; diff --git a/apt-pkg/algorithms.cc b/apt-pkg/algorithms.cc index 7f7cb204f..fb85d12f9 100644 --- a/apt-pkg/algorithms.cc +++ b/apt-pkg/algorithms.cc @@ -1,6 +1,6 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ -// $Id: algorithms.cc,v 1.31 2000/10/03 23:59:05 jgg Exp $ +// $Id: algorithms.cc,v 1.32 2001/02/20 07:03:17 jgg Exp $ /* ###################################################################### Algorithms - A set of misc algorithms @@ -20,6 +20,10 @@ #include #include #include +#include + +#include + #include /*}}}*/ @@ -27,19 +31,41 @@ pkgProblemResolver *pkgProblemResolver::This = 0; // Simulate::Simulate - Constructor /*{{{*/ // --------------------------------------------------------------------- -/* */ -pkgSimulate::pkgSimulate(pkgDepCache &Cache) : pkgPackageManager(Cache), - Sim(Cache.GetMap()) +/* The legacy translations here of input Pkg iterators is obsolete, + this is not necessary since the pkgCaches are fully shared now. */ +pkgSimulate::pkgSimulate(pkgDepCache *Cache) : pkgPackageManager(Cache), + iPolicy(Cache), + Sim(&Cache->GetCache(),&iPolicy) { - Flags = new unsigned char[Cache.HeaderP->PackageCount]; - memset(Flags,0,sizeof(*Flags)*Cache.HeaderP->PackageCount); + Sim.Init(0); + Flags = new unsigned char[Cache->Head().PackageCount]; + memset(Flags,0,sizeof(*Flags)*Cache->Head().PackageCount); // Fake a filename so as not to activate the media swapping string Jnk = "SIMULATE"; - for (unsigned int I = 0; I != Cache.Head().PackageCount; I++) + for (unsigned int I = 0; I != Cache->Head().PackageCount; I++) FileNames[I] = Jnk; } /*}}}*/ +// Simulate::Describe - Describe a package /*{{{*/ +// --------------------------------------------------------------------- +/* */ +void pkgSimulate::Describe(PkgIterator Pkg,ostream &out,bool Now) +{ + VerIterator Ver(Sim); + if (Now == true) + Ver = Pkg.CurrentVer(); + else + Ver = Sim[Pkg].CandidateVerIter(Sim); + + out << Pkg.Name(); + + if (Ver.end() == true) + return; + + out << " (" << Ver.VerStr() << ' ' << Ver.RelStr() << ')'; +} + /*}}}*/ // Simulate::Install - Simulate unpacking of a package /*{{{*/ // --------------------------------------------------------------------- /* */ @@ -49,7 +75,8 @@ bool pkgSimulate::Install(PkgIterator iPkg,string /*File*/) PkgIterator Pkg = Sim.FindPkg(iPkg.Name()); Flags[Pkg->ID] = 1; - cout << "Inst " << Pkg.Name(); + cout << "Inst "; + Describe(Pkg,cout,false); Sim.MarkInstall(Pkg,false); // Look for broken conflicts+predepends. @@ -58,16 +85,23 @@ bool pkgSimulate::Install(PkgIterator iPkg,string /*File*/) if (Sim[I].InstallVer == 0) continue; - for (DepIterator D = Sim[I].InstVerIter(Sim).DependsList(); D.end() == false; D++) - if (D->Type == pkgCache::Dep::Conflicts || D->Type == pkgCache::Dep::PreDepends) + for (DepIterator D = Sim[I].InstVerIter(Sim).DependsList(); D.end() == false;) + { + DepIterator Start; + DepIterator End; + D.GlobOr(Start,End); + if (Start->Type == pkgCache::Dep::Conflicts || + Start->Type == pkgCache::Dep::Obsoletes || + End->Type == pkgCache::Dep::PreDepends) { - if ((Sim[D] & pkgDepCache::DepInstall) == 0) + if ((Sim[End] & pkgDepCache::DepGInstall) == 0) { - cout << " [" << I.Name() << " on " << D.TargetPkg().Name() << ']'; - if (D->Type == pkgCache::Dep::Conflicts) + cout << " [" << I.Name() << " on " << Start.TargetPkg().Name() << ']'; + if (Start->Type == pkgCache::Dep::Conflicts) _error->Error("Fatal, conflicts violated %s",I.Name()); } - } + } + } } if (Sim.BrokenCount() != 0) @@ -102,7 +136,9 @@ bool pkgSimulate::Configure(PkgIterator iPkg) (Sim[D] & pkgDepCache::DepInstall) != 0) continue; - if (D->Type == pkgCache::Dep::Conflicts) + if (D->Type == pkgCache::Dep::Obsoletes) + cout << " Obsoletes:" << D.TargetPkg().Name(); + else if (D->Type == pkgCache::Dep::Conflicts) cout << " Conflicts:" << D.TargetPkg().Name(); else cout << " Depends:" << D.TargetPkg().Name(); @@ -112,7 +148,10 @@ bool pkgSimulate::Configure(PkgIterator iPkg) _error->Error("Conf Broken %s",Pkg.Name()); } else - cout << "Conf " << Pkg.Name(); + { + cout << "Conf "; + Describe(Pkg,cout,false); + } if (Sim.BrokenCount() != 0) ShortBreaks(); @@ -133,9 +172,10 @@ bool pkgSimulate::Remove(PkgIterator iPkg,bool Purge) Flags[Pkg->ID] = 3; Sim.MarkDelete(Pkg); if (Purge == true) - cout << "Purg " << Pkg.Name(); + cout << "Purg "; else - cout << "Remv " << Pkg.Name(); + cout << "Remv "; + Describe(Pkg,cout,false); if (Sim.BrokenCount() != 0) ShortBreaks(); @@ -185,8 +225,8 @@ bool pkgApplyStatus(pkgDepCache &Cache) if (Cache[I].CandidateVerIter(Cache).Downloadable() == true) Cache.MarkInstall(I); else - return _error->Error("The package %s needs to be reinstalled, " - "but I can't find an archive for it.",I.Name()); + return _error->Error(_("The package %s needs to be reinstalled, " + "but I can't find an archive for it."),I.Name()); } continue; @@ -249,7 +289,7 @@ bool pkgFixBroken(pkgDepCache &Cache) Cache.MarkInstall(I,true); } - pkgProblemResolver Fix(Cache); + pkgProblemResolver Fix(&Cache); return Fix.Resolve(true); } /*}}}*/ @@ -281,7 +321,7 @@ bool pkgDistUpgrade(pkgDepCache &Cache) if (I->CurrentVer != 0) Cache.MarkInstall(I,false); - pkgProblemResolver Fix(Cache); + pkgProblemResolver Fix(&Cache); // Hold back held packages. if (_config->FindB("APT::Ignore-Hold",false) == false) @@ -306,7 +346,7 @@ bool pkgDistUpgrade(pkgDepCache &Cache) to install packages not marked for install */ bool pkgAllUpgrade(pkgDepCache &Cache) { - pkgProblemResolver Fix(Cache); + pkgProblemResolver Fix(&Cache); if (Cache.BrokenCount() != 0) return false; @@ -317,7 +357,7 @@ bool pkgAllUpgrade(pkgDepCache &Cache) if (Cache[I].Install() == true) Fix.Protect(I); - if (_config->FindB("APT::Ingore-Hold",false) == false) + if (_config->FindB("APT::Ignore-Hold",false) == false) if (I->SelectedState == pkgCache::State::Hold) continue; @@ -375,10 +415,10 @@ bool pkgMinimizeUpgrade(pkgDepCache &Cache) // ProblemResolver::pkgProblemResolver - Constructor /*{{{*/ // --------------------------------------------------------------------- /* */ -pkgProblemResolver::pkgProblemResolver(pkgDepCache &Cache) : Cache(Cache) +pkgProblemResolver::pkgProblemResolver(pkgDepCache *pCache) : Cache(*pCache) { // Allocate memory - unsigned long Size = Cache.HeaderP->PackageCount; + unsigned long Size = Cache.Head().PackageCount; Scores = new signed short[Size]; Flags = new unsigned char[Size]; memset(Flags,0,sizeof(*Flags)*Size); @@ -387,6 +427,15 @@ pkgProblemResolver::pkgProblemResolver(pkgDepCache &Cache) : Cache(Cache) Debug = _config->FindB("Debug::pkgProblemResolver",false); } /*}}}*/ +// ProblemResolver::~pkgProblemResolver - Destructor /*{{{*/ +// --------------------------------------------------------------------- +/* */ +pkgProblemResolver::~pkgProblemResolver() +{ + delete [] Scores; + delete [] Flags; +} + /*}}}*/ // ProblemResolver::ScoreSort - Sort the list by score /*{{{*/ // --------------------------------------------------------------------- /* */ @@ -406,7 +455,7 @@ int pkgProblemResolver::ScoreSort(const void *a,const void *b) /* */ void pkgProblemResolver::MakeScores() { - unsigned long Size = Cache.HeaderP->PackageCount; + unsigned long Size = Cache.Head().PackageCount; memset(Scores,0,sizeof(*Scores)*Size); // Generate the base scores for a package based on its properties @@ -450,7 +499,7 @@ void pkgProblemResolver::MakeScores() } // Copy the scores to advoid additive looping - signed short *OldScores = new signed short[Size]; + SPtrArray OldScores = new signed short[Size]; memcpy(OldScores,Scores,sizeof(*Scores)*Size); /* Now we cause 1 level of dependency inheritance, that is we add the @@ -493,9 +542,7 @@ void pkgProblemResolver::MakeScores() Scores[I->ID] += 10000; if ((I->Flags & pkgCache::Flag::Essential) == pkgCache::Flag::Essential) Scores[I->ID] += 5000; - } - - delete [] OldScores; + } } /*}}}*/ // ProblemResolver::DoUpgrade - Attempt to upgrade this package /*{{{*/ @@ -573,8 +620,9 @@ bool pkgProblemResolver::DoUpgrade(pkgCache::PkgIterator Pkg) { /* We let the algorithm deal with conflicts on its next iteration, it is much smarter than us */ - if (Start->Type == pkgCache::Dep::Conflicts) - break; + if (Start->Type == pkgCache::Dep::Conflicts || + Start->Type == pkgCache::Dep::Obsoletes) + break; if (Debug == true) clog << " Reinst Failed early because of " << Start.TargetPkg().Name() << endl; @@ -621,7 +669,7 @@ bool pkgProblemResolver::DoUpgrade(pkgCache::PkgIterator Pkg) upgrade packages to advoid problems. */ bool pkgProblemResolver::Resolve(bool BrokenFix) { - unsigned long Size = Cache.HeaderP->PackageCount; + unsigned long Size = Cache.Head().PackageCount; // Record which packages are marked for install bool Again = false; @@ -657,7 +705,7 @@ bool pkgProblemResolver::Resolve(bool BrokenFix) operates from highest score to lowest. This prevents problems when high score packages cause the removal of lower score packages that would cause the removal of even lower score packages. */ - pkgCache::Package **PList = new pkgCache::Package *[Size]; + SPtrArray PList = new pkgCache::Package *[Size]; pkgCache::Package **PEnd = PList; for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++) *PEnd++ = I; @@ -728,19 +776,12 @@ bool pkgProblemResolver::Resolve(bool BrokenFix) bool InOr = false; pkgCache::DepIterator Start; pkgCache::DepIterator End; - PackageKill *OldEnd; + PackageKill *OldEnd = LEnd; enum {OrRemove,OrKeep} OrOp = OrRemove; for (pkgCache::DepIterator D = Cache[I].InstVerIter(Cache).DependsList(); D.end() == false || InOr == true;) { - // We only worry about critical deps. - if (D.IsCritical() != true) - { - D++; - continue; - } - // Compute a single dependency element (glob or) if (Start == End) { @@ -761,13 +802,22 @@ bool pkgProblemResolver::Resolve(bool BrokenFix) if (Debug == true) clog << " Or group keep for " << I.Name() << endl; Cache.MarkKeep(I); - } + } } + /* We do an extra loop (as above) to finalize the or group + processing */ + InOr = false; OrOp = OrRemove; D.GlobOr(Start,End); + if (Start.end() == true) + break; + + // We only worry about critical deps. + if (End.IsCritical() != true) + continue; + InOr = Start != End; - cout << Start.TargetPkg().Name() << ',' << End.TargetPkg().Name() << ',' << InOr << endl; OldEnd = LEnd; } else @@ -783,9 +833,10 @@ bool pkgProblemResolver::Resolve(bool BrokenFix) /* Look across the version list. If there are no possible targets then we keep the package and bail. This is necessary if a package has a dep on another package that cant be found */ - pkgCache::Version **VList = Start.AllTargets(); + SPtrArray VList = Start.AllTargets(); if (*VList == 0 && (Flags[I->ID] & Protected) != Protected && Start->Type != pkgCache::Dep::Conflicts && + Start->Type != pkgCache::Dep::Obsoletes && Cache[I].NowBroken() == false) { if (InOr == true) @@ -811,14 +862,16 @@ bool pkgProblemResolver::Resolve(bool BrokenFix) " as a solution to " << I.Name() << ' ' << (int)Scores[I->ID] << endl; if (Scores[I->ID] <= Scores[Pkg->ID] || ((Cache[Start] & pkgDepCache::DepNow) == 0 && - End->Type != pkgCache::Dep::Conflicts)) + End->Type != pkgCache::Dep::Conflicts && + End->Type != pkgCache::Dep::Obsoletes)) { // Try a little harder to fix protected packages.. if ((Flags[I->ID] & Protected) == Protected) { if (DoUpgrade(Pkg) == true) { - Scores[Pkg->ID] = Scores[I->ID]; + if (Scores[Pkg->ID] > Scores[I->ID]) + Scores[Pkg->ID] = Scores[I->ID]; break; } @@ -853,7 +906,10 @@ bool pkgProblemResolver::Resolve(bool BrokenFix) clog << " Removing " << I.Name() << " rather than change " << Start.TargetPkg().Name() << endl; Cache.MarkDelete(I); if (Counter > 1) - Scores[I->ID] = Scores[Pkg->ID]; + { + if (Scores[Pkg->ID] > Scores[I->ID]) + Scores[I->ID] = Scores[Pkg->ID]; + } } } } @@ -874,13 +930,16 @@ bool pkgProblemResolver::Resolve(bool BrokenFix) LEnd->Dep = End; LEnd++; - if (Start->Type != pkgCache::Dep::Conflicts) + if (Start->Type != pkgCache::Dep::Conflicts && + Start->Type != pkgCache::Dep::Obsoletes) break; } } // Hm, nothing can possibly satisify this dep. Nuke it. - if (VList[0] == 0 && Start->Type != pkgCache::Dep::Conflicts && + if (VList[0] == 0 && + Start->Type != pkgCache::Dep::Conflicts && + Start->Type != pkgCache::Dep::Obsoletes && (Flags[I->ID] & Protected) != Protected) { bool Installed = Cache[I].Install(); @@ -910,8 +969,6 @@ bool pkgProblemResolver::Resolve(bool BrokenFix) Done = true; } - delete [] VList; - // Try some more if (InOr == true) continue; @@ -928,7 +985,8 @@ bool pkgProblemResolver::Resolve(bool BrokenFix) Change = true; if ((Cache[J->Dep] & pkgDepCache::DepGNow) == 0) { - if (J->Dep->Type == pkgCache::Dep::Conflicts) + if (J->Dep->Type == pkgCache::Dep::Conflicts || + J->Dep->Type == pkgCache::Dep::Obsoletes) { if (Debug == true) clog << " Fixing " << I.Name() << " via remove of " << J->Pkg.Name() << endl; @@ -941,9 +999,12 @@ bool pkgProblemResolver::Resolve(bool BrokenFix) clog << " Fixing " << I.Name() << " via keep of " << J->Pkg.Name() << endl; Cache.MarkKeep(J->Pkg); } - + if (Counter > 1) - Scores[J->Pkg->ID] = Scores[I->ID]; + { + if (Scores[I->ID] > Scores[J->Pkg->ID]) + Scores[J->Pkg->ID] = Scores[I->ID]; + } } } } @@ -951,10 +1012,7 @@ bool pkgProblemResolver::Resolve(bool BrokenFix) if (Debug == true) clog << "Done" << endl; - - delete [] Scores; - delete [] PList; - + if (Cache.BrokenCount() != 0) { // See if this is the result of a hold @@ -964,9 +1022,9 @@ bool pkgProblemResolver::Resolve(bool BrokenFix) if (Cache[I].InstBroken() == false) continue; if ((Flags[I->ID] & Protected) != Protected) - return _error->Error("Error, pkgProblemResolver::Resolve generated breaks, this may be caused by held packages."); + return _error->Error(_("Error, pkgProblemResolver::Resolve generated breaks, this may be caused by held packages.")); } - return _error->Error("Unable to correct problems, you have held broken packages."); + return _error->Error(_("Unable to correct problems, you have held broken packages.")); } return true; @@ -979,7 +1037,7 @@ bool pkgProblemResolver::Resolve(bool BrokenFix) system was non-broken previously. */ bool pkgProblemResolver::ResolveByKeep() { - unsigned long Size = Cache.HeaderP->PackageCount; + unsigned long Size = Cache.Head().PackageCount; if (Debug == true) clog << "Entering ResolveByKeep" << endl; @@ -1007,7 +1065,7 @@ bool pkgProblemResolver::ResolveByKeep() continue; /* Keep the package. If this works then great, otherwise we have - to be significantly more agressive and manipulate its dependencies */ + to be significantly more agressive and manipulate its dependencies */ if ((Flags[I->ID] & Protected) == 0) { if (Debug == true) @@ -1015,7 +1073,7 @@ bool pkgProblemResolver::ResolveByKeep() Cache.MarkKeep(I); if (Cache[I].InstBroken() == false) { - K = PList; + K = PList - 1; continue; } } @@ -1056,7 +1114,7 @@ bool pkgProblemResolver::ResolveByKeep() clog << "Package " << I.Name() << " has broken dep on " << End.TargetPkg().Name() << endl; // Look at all the possible provides on this package - pkgCache::Version **VList = End.AllTargets(); + SPtrArray VList = End.AllTargets(); for (pkgCache::Version **V = VList; *V != 0; V++) { pkgCache::VerIterator Ver(Cache,*V); @@ -1089,7 +1147,7 @@ bool pkgProblemResolver::ResolveByKeep() if (K == LastStop) return _error->Error("Internal Error, pkgProblemResolver::ResolveByKeep is looping on package %s.",I.Name()); LastStop = K; - K = PList; + K = PList - 1; } return true; @@ -1112,3 +1170,34 @@ void pkgProblemResolver::InstallProtect() } } /*}}}*/ + +// PrioSortList - Sort a list of versions by priority /*{{{*/ +// --------------------------------------------------------------------- +/* This is ment to be used in conjunction with AllTargets to get a list + of versions ordered by preference. */ +static pkgCache *PrioCache; +static int PrioComp(const void *A,const void *B) +{ + pkgCache::VerIterator L(*PrioCache,*(pkgCache::Version **)A); + pkgCache::VerIterator R(*PrioCache,*(pkgCache::Version **)B); + + if ((L.ParentPkg()->Flags & pkgCache::Flag::Essential) == pkgCache::Flag::Essential && + (L.ParentPkg()->Flags & pkgCache::Flag::Essential) != pkgCache::Flag::Essential) + return 1; + if ((L.ParentPkg()->Flags & pkgCache::Flag::Essential) != pkgCache::Flag::Essential && + (L.ParentPkg()->Flags & pkgCache::Flag::Essential) == pkgCache::Flag::Essential) + return -1; + + if (L->Priority != R->Priority) + return L->Priority - R->Priority; + return strcmp(L.ParentPkg().Name(),R.ParentPkg().Name()); +} +void pkgPrioSortList(pkgCache &Cache,pkgCache::Version **List) +{ + unsigned long Count = 0; + PrioCache = &Cache; + for (pkgCache::Version **I = List; *I != 0; I++) + Count++; + qsort(List,Count,sizeof(*List),PrioComp); +} + /*}}}*/ diff --git a/apt-pkg/algorithms.h b/apt-pkg/algorithms.h index d68fbfbea..00b7882e2 100644 --- a/apt-pkg/algorithms.h +++ b/apt-pkg/algorithms.h @@ -1,6 +1,6 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ -// $Id: algorithms.h,v 1.8 1999/10/27 04:38:27 jgg Exp $ +// $Id: algorithms.h,v 1.9 2001/02/20 07:03:17 jgg Exp $ /* ###################################################################### Algorithms - A set of misc algorithms @@ -27,7 +27,6 @@ ##################################################################### */ /*}}}*/ -// Header section: pkglib #ifndef PKGLIB_ALGORITHMS_H #define PKGLIB_ALGORITHMS_H @@ -42,8 +41,22 @@ class pkgSimulate : public pkgPackageManager { protected: + class Policy : public pkgDepCache::Policy + { + pkgDepCache *Cache; + public: + + virtual VerIterator GetCandidateVer(PkgIterator Pkg) + { + return (*Cache)[Pkg].CandidateVerIter(*Cache); + } + + Policy(pkgDepCache *Cache) : Cache(Cache) {}; + }; + unsigned char *Flags; + Policy iPolicy; pkgDepCache Sim; // The Actuall installation implementation @@ -51,10 +64,11 @@ class pkgSimulate : public pkgPackageManager virtual bool Configure(PkgIterator Pkg); virtual bool Remove(PkgIterator Pkg,bool Purge); void ShortBreaks(); + void Describe(PkgIterator iPkg,ostream &out,bool Now); public: - pkgSimulate(pkgDepCache &Cache); + pkgSimulate(pkgDepCache *Cache); }; class pkgProblemResolver @@ -101,7 +115,8 @@ class pkgProblemResolver void InstallProtect(); - pkgProblemResolver(pkgDepCache &Cache); + pkgProblemResolver(pkgDepCache *Cache); + ~pkgProblemResolver(); }; bool pkgDistUpgrade(pkgDepCache &Cache); @@ -110,4 +125,6 @@ bool pkgFixBroken(pkgDepCache &Cache); bool pkgAllUpgrade(pkgDepCache &Cache); bool pkgMinimizeUpgrade(pkgDepCache &Cache); +void pkgPrioSortList(pkgCache &Cache,pkgCache::Version **List); + #endif diff --git a/apt-pkg/cachefile.cc b/apt-pkg/cachefile.cc index d7f3c0937..74d136afb 100644 --- a/apt-pkg/cachefile.cc +++ b/apt-pkg/cachefile.cc @@ -1,6 +1,6 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ -// $Id: cachefile.cc,v 1.4 1999/06/24 04:06:30 jgg Exp $ +// $Id: cachefile.cc,v 1.5 2001/02/20 07:03:17 jgg Exp $ /* ###################################################################### CacheFile - Simple wrapper class for opening, generating and whatnot @@ -21,23 +21,29 @@ #include #include #include +#include +#include + +#include /*}}}*/ // CacheFile::CacheFile - Constructor /*{{{*/ // --------------------------------------------------------------------- /* */ -pkgCacheFile::pkgCacheFile() : Map(0), Cache(0), Lock(0) +pkgCacheFile::pkgCacheFile() : Map(0), Cache(0), DCache(0), Policy(0) { } /*}}}*/ -// CacheFile::~CacheFile - Destructor /*{{{*/ +// CacheFile::~CacheFile - Destructor /*{{{*/ // --------------------------------------------------------------------- /* */ pkgCacheFile::~pkgCacheFile() { + delete DCache; + delete Policy; delete Cache; delete Map; - delete Lock; + _system->UnLock(true); } /*}}}*/ // CacheFile::Open - Open the cache files, creating if necessary /*{{{*/ @@ -46,7 +52,8 @@ pkgCacheFile::~pkgCacheFile() bool pkgCacheFile::Open(OpProgress &Progress,bool WithLock) { if (WithLock == true) - Lock = new pkgDpkgLock; + if (_system->Lock() == false) + return false; if (_error->PendingError() == true) return false; @@ -54,38 +61,35 @@ bool pkgCacheFile::Open(OpProgress &Progress,bool WithLock) // Read the source list pkgSourceList List; if (List.ReadMainList() == false) - return _error->Error("The list of sources could not be read."); + return _error->Error(_("The list of sources could not be read.")); + + // Read the caches + bool Res = pkgMakeStatusCache(List,Progress,&Map,!WithLock); + Progress.Done(); + if (Res == false) + return _error->Error(_("The package lists or status file could not be parsed or opened.")); + + /* This sux, remove it someday */ + if (_error->empty() == false) + _error->Warning(_("You may want to run apt-get update to correct these missing files")); + + Cache = new pkgCache(Map); + if (_error->PendingError() == true) + return false; - /* Build all of the caches, using the cache files if we are locking - (ie as root) */ - if (WithLock == true) - { - pkgMakeStatusCache(List,Progress); - Progress.Done(); - if (_error->PendingError() == true) - return _error->Error("The package lists or status file could not be parsed or opened."); - if (_error->empty() == false) - _error->Warning("You may want to run apt-get update to correct these missing files"); - - // Open the cache file - FileFd File(_config->FindFile("Dir::Cache::pkgcache"),FileFd::ReadOnly); - if (_error->PendingError() == true) - return false; - - Map = new MMap(File,MMap::Public | MMap::ReadOnly); - if (_error->PendingError() == true) - return false; - } - else - { - Map = pkgMakeStatusCacheMem(List,Progress); - Progress.Done(); - if (Map == 0) - return false; - } + // The policy engine + Policy = new pkgPolicy(Cache); + if (_error->PendingError() == true) + return false; + if (ReadPinFile(*Policy) == false) + return false; // Create the dependency cache - Cache = new pkgDepCache(*Map,Progress); + DCache = new pkgDepCache(Cache,Policy); + if (_error->PendingError() == true) + return false; + + DCache->Init(&Progress); Progress.Done(); if (_error->PendingError() == true) return false; @@ -93,3 +97,21 @@ bool pkgCacheFile::Open(OpProgress &Progress,bool WithLock) return true; } /*}}}*/ + +// CacheFile::Close - close the cache files /*{{{*/ +// --------------------------------------------------------------------- +/* */ +void pkgCacheFile::Close() +{ + delete DCache; + delete Policy; + delete Cache; + delete Map; + _system->UnLock(true); + + Map = 0; + DCache = 0; + Policy = 0; + Cache = 0; +} + /*}}}*/ diff --git a/apt-pkg/cachefile.h b/apt-pkg/cachefile.h index e2414446e..e2540ed58 100644 --- a/apt-pkg/cachefile.h +++ b/apt-pkg/cachefile.h @@ -1,6 +1,6 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ -// $Id: cachefile.h,v 1.3 1999/06/27 03:18:28 jgg Exp $ +// $Id: cachefile.h,v 1.4 2001/02/20 07:03:17 jgg Exp $ /* ###################################################################### CacheFile - Simple wrapper class for opening, generating and whatnot @@ -9,6 +9,9 @@ of caches. It can operate as root, as not root, show progress and so on, it transparently handles everything necessary. + This means it can rebuild caches from the source list and instantiates + and prepares the standard policy mechanism. + ##################################################################### */ /*}}}*/ #ifndef PKGLIB_CACHEFILE_H @@ -19,30 +22,32 @@ #endif #include -#include +class pkgPolicy; class pkgCacheFile { protected: MMap *Map; - pkgDepCache *Cache; - pkgDpkgLock *Lock; + pkgCache *Cache; + pkgDepCache *DCache; public: + + pkgPolicy *Policy; // We look pretty much exactly like a pointer to a dep cache - inline operator pkgDepCache &() {return *Cache;}; - inline operator pkgDepCache *() {return Cache;}; - inline pkgDepCache *operator ->() {return Cache;}; - inline pkgDepCache &operator *() {return *Cache;}; - inline pkgDepCache::StateCache &operator [](pkgCache::PkgIterator const &I) {return (*Cache)[I];}; - inline unsigned char &operator [](pkgCache::DepIterator const &I) {return (*Cache)[I];}; + inline operator pkgCache &() {return *Cache;}; + inline operator pkgCache *() {return Cache;}; + inline operator pkgDepCache &() {return *DCache;}; + inline operator pkgDepCache *() {return DCache;}; + inline pkgDepCache *operator ->() {return DCache;}; + inline pkgDepCache &operator *() {return *DCache;}; + inline pkgDepCache::StateCache &operator [](pkgCache::PkgIterator const &I) {return (*DCache)[I];}; + inline unsigned char &operator [](pkgCache::DepIterator const &I) {return (*DCache)[I];}; - // Release the dpkg status lock - inline void ReleaseLock() {Lock->Close();}; - bool Open(OpProgress &Progress,bool WithLock = true); + void Close(); pkgCacheFile(); ~pkgCacheFile(); diff --git a/apt-pkg/cacheiterators.h b/apt-pkg/cacheiterators.h index a3f134e63..e346f49b7 100644 --- a/apt-pkg/cacheiterators.h +++ b/apt-pkg/cacheiterators.h @@ -1,6 +1,6 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ -// $Id: cacheiterators.h,v 1.15 1999/07/30 04:08:42 jgg Exp $ +// $Id: cacheiterators.h,v 1.16 2001/02/20 07:03:17 jgg Exp $ /* ###################################################################### Cache Iterators - Iterators for navigating the cache structure @@ -28,7 +28,6 @@ ##################################################################### */ /*}}}*/ -// Header section: pkglib #ifndef PKGLIB_CACHEITERATORS_H #define PKGLIB_CACHEITERATORS_H @@ -39,10 +38,20 @@ // Package Iterator class pkgCache::PkgIterator { + friend class pkgCache; Package *Pkg; pkgCache *Owner; long HashIndex; + protected: + + // This constructor is the 'begin' constructor, never use it. + inline PkgIterator(pkgCache &Owner) : Owner(&Owner), HashIndex(-1) + { + Pkg = Owner.PkgP; + operator ++(0); + }; + public: enum OkState {NeedsNothing,NeedsUnpack,NeedsConfigure}; @@ -62,10 +71,10 @@ class pkgCache::PkgIterator inline Package const &operator *() const {return *Pkg;}; inline operator Package *() {return Pkg == Owner->PkgP?0:Pkg;}; inline operator Package const *() const {return Pkg == Owner->PkgP?0:Pkg;}; + inline pkgCache *Cache() {return Owner;}; inline const char *Name() const {return Pkg->Name == 0?0:Owner->StrP + Pkg->Name;}; inline const char *Section() const {return Pkg->Section == 0?0:Owner->StrP + Pkg->Section;}; - inline const char *TargetDist() const {return Pkg->TargetDist == 0?0:Owner->StrP + Pkg->TargetDist;}; inline bool Purge() const {return Pkg->CurrentState == pkgCache::State::Purge || (Pkg->CurrentVer == 0 && Pkg->CurrentState == pkgCache::State::NotInstalled);}; inline VerIterator VersionList() const; @@ -77,11 +86,6 @@ class pkgCache::PkgIterator OkState State() const; // Constructors - inline PkgIterator(pkgCache &Owner) : Owner(&Owner), HashIndex(-1) - { - Pkg = Owner.PkgP; - operator ++(0); - }; inline PkgIterator(pkgCache &Owner,Package *Trg) : Pkg(Trg), Owner(&Owner), HashIndex(0) { @@ -119,7 +123,8 @@ class pkgCache::VerIterator inline Version const &operator *() const {return *Ver;}; inline operator Version *() {return Ver == Owner->VerP?0:Ver;}; inline operator Version const *() const {return Ver == Owner->VerP?0:Ver;}; - + inline pkgCache *Cache() {return Owner;}; + inline const char *VerStr() const {return Ver->VerStr == 0?0:Owner->StrP + Ver->VerStr;}; inline const char *Section() const {return Ver->Section == 0?0:Owner->StrP + Ver->Section;}; inline const char *Arch() const {return Ver->Arch == 0?0:Owner->StrP + Ver->Arch;}; @@ -129,8 +134,9 @@ class pkgCache::VerIterator inline VerFileIterator FileList() const; inline unsigned long Index() const {return Ver - Owner->VerP;}; bool Downloadable() const; - const char *PriorityType(); - + inline const char *PriorityType() {return Owner->Priority(Ver->Priority);}; + string RelStr(); + bool Automatic() const; VerFileIterator NewestFile() const; @@ -171,10 +177,11 @@ class pkgCache::DepIterator inline Dependency const &operator *() const {return *Dep;}; inline operator Dependency *() {return Dep == Owner->DepP?0:Dep;}; inline operator Dependency const *() const {return Dep == Owner->DepP?0:Dep;}; + inline pkgCache *Cache() {return Owner;}; inline const char *TargetVer() const {return Dep->Version == 0?0:Owner->StrP + Dep->Version;}; inline PkgIterator TargetPkg() {return PkgIterator(*Owner,Owner->PkgP + Dep->Package);}; - inline PkgIterator SmartTargetPkg() {PkgIterator R(*Owner);SmartTargetPkg(R);return R;}; + inline PkgIterator SmartTargetPkg() {PkgIterator R(*Owner,0);SmartTargetPkg(R);return R;}; inline VerIterator ParentVer() {return VerIterator(*Owner,Owner->VerP + Dep->ParentVer);}; inline PkgIterator ParentPkg() {return PkgIterator(*Owner,Owner->PkgP + Owner->VerP[Dep->ParentVer].ParentPkg);}; inline bool Reverse() {return Type == DepRev;}; @@ -183,8 +190,8 @@ class pkgCache::DepIterator void GlobOr(DepIterator &Start,DepIterator &End); Version **AllTargets(); bool SmartTargetPkg(PkgIterator &Result); - const char *CompType(); - const char *DepType(); + inline const char *CompType() {return Owner->CompType(Dep->CompareOp);}; + inline const char *DepType() {return Owner->DepType(Dep->Type);}; inline DepIterator(pkgCache &Owner,Dependency *Trg,Version * = 0) : Dep(Trg), Type(DepVer), Owner(&Owner) @@ -229,6 +236,7 @@ class pkgCache::PrvIterator inline Provides const &operator *() const {return *Prv;}; inline operator Provides *() {return Prv == Owner->ProvideP?0:Prv;}; inline operator Provides const *() const {return Prv == Owner->ProvideP?0:Prv;}; + inline pkgCache *Cache() {return Owner;}; inline const char *Name() const {return Owner->StrP + Owner->PkgP[Prv->ParentPkg].Name;}; inline const char *ProvideVersion() const {return Prv->ProvideVersion == 0?0:Owner->StrP + Prv->ProvideVersion;}; @@ -274,6 +282,7 @@ class pkgCache::PkgFileIterator inline PackageFile const &operator *() const {return *File;}; inline operator PackageFile *() {return File == Owner->PkgFileP?0:File;}; inline operator PackageFile const *() const {return File == Owner->PkgFileP?0:File;}; + inline pkgCache *Cache() {return Owner;}; inline const char *FileName() const {return File->FileName == 0?0:Owner->StrP + File->FileName;}; inline const char *Archive() const {return File->Archive == 0?0:Owner->StrP + File->Archive;}; @@ -281,14 +290,17 @@ class pkgCache::PkgFileIterator inline const char *Version() const {return File->Version == 0?0:Owner->StrP + File->Version;}; inline const char *Origin() const {return File->Origin == 0?0:Owner->StrP + File->Origin;}; inline const char *Label() const {return File->Origin == 0?0:Owner->StrP + File->Label;}; - inline const char *Architecture() const {return File->Origin == 0?0:Owner->StrP + File->Architecture;}; + inline const char *Site() const {return File->Site == 0?0:Owner->StrP + File->Site;}; + inline const char *Architecture() const {return File->Architecture == 0?0:Owner->StrP + File->Architecture;}; + inline const char *IndexType() const {return File->IndexType == 0?0:Owner->StrP + File->IndexType;}; inline unsigned long Index() const {return File - Owner->PkgFileP;}; bool IsOk(); - + // Constructors - inline PkgFileIterator(pkgCache &Owner) : Owner(&Owner), File(Owner.PkgFileP + Owner.Head().FileList) {}; + inline PkgFileIterator() : Owner(0), File(0) {}; + inline PkgFileIterator(pkgCache &Owner) : Owner(&Owner), File(Owner.PkgFileP) {}; inline PkgFileIterator(pkgCache &Owner,PackageFile *Trg) : Owner(&Owner), File(Trg) {}; }; @@ -315,10 +327,12 @@ class pkgCache::VerFileIterator inline VerFile const &operator *() const {return *FileP;}; inline operator VerFile *() {return FileP == Owner->VerFileP?0:FileP;}; inline operator VerFile const *() const {return FileP == Owner->VerFileP?0:FileP;}; + inline pkgCache *Cache() {return Owner;}; inline PkgFileIterator File() const {return PkgFileIterator(*Owner,FileP->File + Owner->PkgFileP);}; inline unsigned long Index() const {return FileP - Owner->VerFileP;}; + inline VerFileIterator() : Owner(0), FileP(0) {}; inline VerFileIterator(pkgCache &Owner,VerFile *Trg) : Owner(&Owner), FileP(Trg) {}; }; @@ -327,8 +341,6 @@ inline pkgCache::VerIterator pkgCache::PkgIterator::VersionList() const {return VerIterator(*Owner,Owner->VerP + Pkg->VersionList);}; inline pkgCache::VerIterator pkgCache::PkgIterator::CurrentVer() const {return VerIterator(*Owner,Owner->VerP + Pkg->CurrentVer);}; -inline pkgCache::VerIterator pkgCache::PkgIterator::TargetVer() const - {return VerIterator(*Owner,Owner->VerP + Pkg->TargetVer);}; inline pkgCache::DepIterator pkgCache::PkgIterator::RevDependsList() const {return DepIterator(*Owner,Owner->DepP + Pkg->RevDepends,Pkg);}; inline pkgCache::PrvIterator pkgCache::PkgIterator::ProvidesList() const diff --git a/apt-pkg/clean.cc b/apt-pkg/clean.cc index bad824362..0d623d862 100644 --- a/apt-pkg/clean.cc +++ b/apt-pkg/clean.cc @@ -1,6 +1,6 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ -// $Id: clean.cc,v 1.3 1999/10/03 21:09:27 jgg Exp $ +// $Id: clean.cc,v 1.4 2001/02/20 07:03:17 jgg Exp $ /* ###################################################################### Clean - Clean out downloaded directories @@ -17,6 +17,8 @@ #include #include +#include + #include #include #include @@ -29,16 +31,17 @@ bool pkgArchiveCleaner::Go(string Dir,pkgCache &Cache) { bool CleanInstalled = _config->FindB("APT::Clean-Installed",true); - - DIR *D = opendir(Dir.c_str()); + string MyArch = _config->Find("APT::Architecture"); + + DIR *D = opendir(Dir.c_str()); if (D == 0) - return _error->Errno("opendir","Unable to read %s",Dir.c_str()); - + return _error->Errno("opendir",_("Unable to read %s"),Dir.c_str()); + string StartDir = SafeGetCWD(); if (chdir(Dir.c_str()) != 0) { closedir(D); - return _error->Errno("chdir","Unable to change to ",Dir.c_str()); + return _error->Errno("chdir",_("Unable to change to %s"),Dir.c_str()); } for (struct dirent *Dir = readdir(D); Dir != 0; Dir = readdir(D)) @@ -52,8 +55,12 @@ bool pkgArchiveCleaner::Go(string Dir,pkgCache &Cache) struct stat St; if (stat(Dir->d_name,&St) != 0) - return _error->Errno("stat","Unable to stat %s.",Dir->d_name); - + { + chdir(StartDir.c_str()); + closedir(D); + return _error->Errno("stat",_("Unable to stat %s."),Dir->d_name); + } + // Grab the package name const char *I = Dir->d_name; for (; *I != 0 && *I != '_';I++); @@ -74,7 +81,10 @@ bool pkgArchiveCleaner::Go(string Dir,pkgCache &Cache) if (*I != '.') continue; string Arch = DeQuoteString(string(Start,I-Start)); - + + if (Arch != "all" && Arch != MyArch) + continue; + // Lookup the package pkgCache::PkgIterator P = Cache.FindPkg(Pkg); if (P.end() != true) diff --git a/apt-pkg/contrib/cdromutl.cc b/apt-pkg/contrib/cdromutl.cc index dae6f0528..ab170ec5a 100644 --- a/apt-pkg/contrib/cdromutl.cc +++ b/apt-pkg/contrib/cdromutl.cc @@ -1,6 +1,6 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ -// $Id: cdromutl.cc,v 1.11 1999/12/10 23:40:29 jgg Exp $ +// $Id: cdromutl.cc,v 1.12 2001/02/20 07:03:17 jgg Exp $ /* ###################################################################### CDROM Utilities - Some functions to manipulate CDROM mounts. @@ -19,6 +19,8 @@ #include #include +#include + #include #include #include @@ -50,7 +52,7 @@ bool IsMounted(string &Path) struct stat Buf,Buf2; if (stat(Path.c_str(),&Buf) != 0 || stat((Path + "../").c_str(),&Buf2) != 0) - return _error->Errno("stat","Unable to stat the mount point %s",Path.c_str()); + return _error->Errno("stat",_("Unable to stat the mount point %s"),Path.c_str()); if (Buf.st_dev == Buf2.st_dev) return false; @@ -93,7 +95,7 @@ bool UnmountCdrom(string Path) } // Wait for mount - return ExecWait(Child,"mount",true); + return ExecWait(Child,"umount",true); } /*}}}*/ // MountCdrom - Mount a cdrom /*{{{*/ @@ -144,11 +146,11 @@ bool IdentCdrom(string CD,string &Res,unsigned int Version) string StartDir = SafeGetCWD(); if (chdir(CD.c_str()) != 0) - return _error->Errno("chdir","Unable to change to %s",CD.c_str()); + return _error->Errno("chdir",_("Unable to change to %s"),CD.c_str()); DIR *D = opendir("."); if (D == 0) - return _error->Errno("opendir","Unable to read %s",CD.c_str()); + return _error->Errno("opendir",_("Unable to read %s"),CD.c_str()); /* Run over the directory, we assume that the reader order will never change as the media is read-only. In theory if the kernel did @@ -185,7 +187,7 @@ bool IdentCdrom(string CD,string &Res,unsigned int Version) { struct statvfs Buf; if (statvfs(CD.c_str(),&Buf) != 0) - return _error->Errno("statfs","Failed to stat the cdrom"); + return _error->Errno("statfs",_("Failed to stat the cdrom")); // We use a kilobyte block size to advoid overflow sprintf(S,"%lu %lu",(long)(Buf.f_blocks*(Buf.f_bsize/1024)), diff --git a/apt-pkg/contrib/cmndline.cc b/apt-pkg/contrib/cmndline.cc index 36039c3b8..ea15ae05d 100644 --- a/apt-pkg/contrib/cmndline.cc +++ b/apt-pkg/contrib/cmndline.cc @@ -1,6 +1,6 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ -// $Id: cmndline.cc,v 1.10 1999/05/14 02:57:48 jgg Exp $ +// $Id: cmndline.cc,v 1.11 2001/02/20 07:03:17 jgg Exp $ /* ###################################################################### Command Line Class - Sophisticated command line parser @@ -14,6 +14,8 @@ #include #include #include + +#include /*}}}*/ // CommandLine::CommandLine - Constructor /*{{{*/ @@ -68,7 +70,7 @@ bool CommandLine::Parse(int argc,const char **argv) Args *A; for (A = ArgList; A->end() == false && A->ShortOpt != *Opt; A++); if (A->end() == true) - return _error->Error("Command line option '%c' [from %s] is not known.",*Opt,argv[I]); + return _error->Error(_("Command line option '%c' [from %s] is not known."),*Opt,argv[I]); if (HandleOpt(I,argc,argv,Opt,A) == false) return false; @@ -94,7 +96,7 @@ bool CommandLine::Parse(int argc,const char **argv) for (; Opt != OptEnd && *Opt != '-'; Opt++); if (Opt == OptEnd) - return _error->Error("Command line option %s is not understood",argv[I]); + return _error->Error(_("Command line option %s is not understood"),argv[I]); Opt++; for (A = ArgList; A->end() == false && @@ -102,7 +104,7 @@ bool CommandLine::Parse(int argc,const char **argv) // Failed again.. if (A->end() == true && OptEnd - Opt != 1) - return _error->Error("Command line option %s is not understood",argv[I]); + return _error->Error(_("Command line option %s is not understood"),argv[I]); // The option could be a single letter option prefixed by a no-.. if (A->end() == true) @@ -110,12 +112,12 @@ bool CommandLine::Parse(int argc,const char **argv) for (A = ArgList; A->end() == false && A->ShortOpt != *Opt; A++); if (A->end() == true) - return _error->Error("Command line option %s is not understood",argv[I]); + return _error->Error(_("Command line option %s is not understood"),argv[I]); } // The option is not boolean if (A->IsBoolean() == false) - return _error->Error("Command line option %s is not boolean",argv[I]); + return _error->Error(_("Command line option %s is not boolean"),argv[I]); PreceedMatch = true; } @@ -154,7 +156,7 @@ bool CommandLine::HandleOpt(int &I,int argc,const char *argv[], // Equals was specified but we fell off the end! if (Opt[1] == '=' && Argument == 0) - return _error->Error("Option %s requires an argument.",argv[I]); + return _error->Error(_("Option %s requires an argument."),argv[I]); if (Opt[1] == '=') CertainArg = true; @@ -175,7 +177,7 @@ bool CommandLine::HandleOpt(int &I,int argc,const char *argv[], if ((A->Flags & HasArg) == HasArg) { if (Argument == 0) - return _error->Error("Option %s requires an argument.",argv[I]); + return _error->Error(_("Option %s requires an argument."),argv[I]); Opt += strlen(Opt); I += IncI; @@ -189,13 +191,13 @@ bool CommandLine::HandleOpt(int &I,int argc,const char *argv[], const char *J; for (J = Argument; *J != 0 && *J != '='; J++); if (*J == 0) - return _error->Error("Option %s: Configuration item sepecification must have an =.",argv[I]); + return _error->Error(_("Option %s: Configuration item sepecification must have an =."),argv[I]); // = is trailing if (J[1] == 0) { if (I+1 >= argc) - return _error->Error("Option %s: Configuration item sepecification must have an =.",argv[I]); + return _error->Error(_("Option %s: Configuration item sepecification must have an =."),argv[I]); Conf->Set(string(Argument,J-Argument),string(argv[I++ +1])); } else @@ -225,7 +227,7 @@ bool CommandLine::HandleOpt(int &I,int argc,const char *argv[], // Conversion failed and the argument was specified with an =s if (EndPtr == Argument && CertainArg == true) - return _error->Error("Option %s requires an integer argument, not '%s'",argv[I],Argument); + return _error->Error(_("Option %s requires an integer argument, not '%s'"),argv[I],Argument); // Conversion was ok, set the value and return if (EndPtr != 0 && EndPtr != Argument && *EndPtr == 0) @@ -256,7 +258,7 @@ bool CommandLine::HandleOpt(int &I,int argc,const char *argv[], break; if (strlen(argv[I]) >= sizeof(Buffer)) - return _error->Error("Option '%s' is too long",argv[I]); + return _error->Error(_("Option '%s' is too long"),argv[I]); // Skip the leading dash const char *J = argv[I]; @@ -289,7 +291,7 @@ bool CommandLine::HandleOpt(int &I,int argc,const char *argv[], } if (CertainArg == true) - return _error->Error("Sense %s is not understood, try true or false.",Argument); + return _error->Error(_("Sense %s is not understood, try true or false."),Argument); Argument = 0; } @@ -339,7 +341,7 @@ bool CommandLine::DispatchArg(Dispatch *Map,bool NoMatch) if (Map[I].Match == 0) { if (NoMatch == true) - _error->Error("Invalid operation %s",FileList[0]); + _error->Error(_("Invalid operation %s"),FileList[0]); } return false; diff --git a/apt-pkg/contrib/configuration.cc b/apt-pkg/contrib/configuration.cc index 302feee6e..b3b425cda 100644 --- a/apt-pkg/contrib/configuration.cc +++ b/apt-pkg/contrib/configuration.cc @@ -1,6 +1,6 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ -// $Id: configuration.cc,v 1.14 2000/01/16 05:36:17 jgg Exp $ +// $Id: configuration.cc,v 1.15 2001/02/20 07:03:17 jgg Exp $ /* ###################################################################### Configuration Class @@ -18,9 +18,17 @@ #include #include #include +#include +#include +#include +#include +#include + #include -#include +#include +#include +#include /*}}}*/ Configuration *_config = new Configuration; @@ -28,9 +36,45 @@ Configuration *_config = new Configuration; // Configuration::Configuration - Constructor /*{{{*/ // --------------------------------------------------------------------- /* */ -Configuration::Configuration() +Configuration::Configuration() : ToFree(true) { Root = new Item; +} +Configuration::Configuration(const Item *Root) : Root((Item *)Root), ToFree(false) +{ +}; + + /*}}}*/ +// Configuration::~Configuration - Destructor /*{{{*/ +// --------------------------------------------------------------------- +/* */ +Configuration::~Configuration() +{ + if (ToFree == false) + return; + + Item *Top = Root; + for (; Top != 0;) + { + if (Top->Child != 0) + { + Top = Top->Child; + continue; + } + + while (Top != 0 && Top->Next == 0) + { + Item *Parent = Top->Parent; + delete Top; + Top = Parent; + } + if (Top != 0) + { + Item *Next = Top->Next; + delete Top; + Top = Next; + } + } } /*}}}*/ // Configuration::Lookup - Lookup a single item /*{{{*/ @@ -105,9 +149,9 @@ Configuration::Item *Configuration::Lookup(const char *Name,bool Create) // Configuration::Find - Find a value /*{{{*/ // --------------------------------------------------------------------- /* */ -string Configuration::Find(const char *Name,const char *Default) +string Configuration::Find(const char *Name,const char *Default) const { - Item *Itm = Lookup(Name,false); + const Item *Itm = Lookup(Name); if (Itm == 0 || Itm->Value.empty() == true) { if (Default == 0) @@ -124,9 +168,9 @@ string Configuration::Find(const char *Name,const char *Default) /* Directories are stored as the base dir in the Parent node and the sub directory in sub nodes with the final node being the end filename */ -string Configuration::FindFile(const char *Name,const char *Default) +string Configuration::FindFile(const char *Name,const char *Default) const { - Item *Itm = Lookup(Name,false); + const Item *Itm = Lookup(Name); if (Itm == 0 || Itm->Value.empty() == true) { if (Default == 0) @@ -135,26 +179,35 @@ string Configuration::FindFile(const char *Name,const char *Default) return Default; } - // Absolute path - if (Itm->Value[0] == '/' || Itm->Parent == 0) - return Itm->Value; - - // ./ is also considered absolute as is anything with ~ in it - if (Itm->Value[0] != 0 && - ((Itm->Value[0] == '.' && Itm->Value[1] == '/') || - (Itm->Value[0] == '~' && Itm->Value[1] == '/'))) - return Itm->Value; - - if (Itm->Parent->Value.end()[-1] == '/') - return Itm->Parent->Value + Itm->Value; - else - return Itm->Parent->Value + '/' + Itm->Value; + string val = Itm->Value; + while (Itm->Parent != 0 && Itm->Parent->Value.empty() == false) + { + // Absolute + if (val.length() >= 1 && val[0] == '/') + break; + + // ~/foo or ./foo + if (val.length() >= 2 && (val[0] == '~' || val[0] == '.') && val[1] == '/') + break; + + // ../foo + if (val.length() >= 3 && val[0] == '.' && val[1] == '.' && val[2] == '/') + break; + + if (Itm->Parent->Value.end()[-1] != '/') + val.insert(0, "/"); + + val.insert(0, Itm->Parent->Value); + Itm = Itm->Parent; + } + + return val; } /*}}}*/ // Configuration::FindDir - Find a directory name /*{{{*/ // --------------------------------------------------------------------- /* This is like findfile execept the result is terminated in a / */ -string Configuration::FindDir(const char *Name,const char *Default) +string Configuration::FindDir(const char *Name,const char *Default) const { string Res = FindFile(Name,Default); if (Res.end()[-1] != '/') @@ -165,9 +218,9 @@ string Configuration::FindDir(const char *Name,const char *Default) // Configuration::FindI - Find an integer value /*{{{*/ // --------------------------------------------------------------------- /* */ -int Configuration::FindI(const char *Name,int Default) +int Configuration::FindI(const char *Name,int Default) const { - Item *Itm = Lookup(Name,false); + const Item *Itm = Lookup(Name); if (Itm == 0 || Itm->Value.empty() == true) return Default; @@ -182,15 +235,68 @@ int Configuration::FindI(const char *Name,int Default) // Configuration::FindB - Find a boolean type /*{{{*/ // --------------------------------------------------------------------- /* */ -bool Configuration::FindB(const char *Name,bool Default) +bool Configuration::FindB(const char *Name,bool Default) const { - Item *Itm = Lookup(Name,false); + const Item *Itm = Lookup(Name); if (Itm == 0 || Itm->Value.empty() == true) return Default; return StringToBool(Itm->Value,Default); } /*}}}*/ +// Configuration::FindAny - Find an arbitrary type /*{{{*/ +// --------------------------------------------------------------------- +/* a key suffix of /f, /d, /b or /i calls Find{File,Dir,B,I} */ +string Configuration::FindAny(const char *Name,const char *Default) const +{ + string key = Name; + char type = 0; + + if (key.size() > 2 && key.end()[-2] == '/') + { + type = key.end()[-1]; + key.resize(key.size() - 2); + } + + switch (type) + { + // file + case 'f': + return FindFile(key.c_str(), Default); + + // directory + case 'd': + return FindDir(key.c_str(), Default); + + // bool + case 'b': + return FindB(key, Default) ? "true" : "false"; + + // int + case 'i': + { + char buf[16]; + snprintf(buf, sizeof(buf)-1, "%d", FindI(key, Default)); + return buf; + } + } + + // fallback + return Find(Name, Default); +} + /*}}}*/ +// Configuration::CndSet - Conditinal Set a value /*{{{*/ +// --------------------------------------------------------------------- +/* This will not overwrite */ +void Configuration::CndSet(const char *Name,string Value) +{ + Item *Itm = Lookup(Name,true); + if (Itm == 0) + return; + if (Itm->Value.empty() == true) + Itm->Value = Value; +} + /*}}}*/ // Configuration::Set - Set a value /*{{{*/ // --------------------------------------------------------------------- /* */ @@ -215,17 +321,73 @@ void Configuration::Set(const char *Name,int Value) Itm->Value = S; } /*}}}*/ +// Configuration::Clear - Clear an entire tree /*{{{*/ +// --------------------------------------------------------------------- +/* */ +void Configuration::Clear(string Name) +{ + Item *Top = Lookup(Name.c_str(),false); + if (Top == 0) + return; + + Top->Value = string(); + Item *Stop = Top; + Top = Top->Child; + Stop->Child = 0; + for (; Top != 0;) + { + if (Top->Child != 0) + { + Top = Top->Child; + continue; + } + + while (Top != 0 && Top->Next == 0) + { + Item *Tmp = Top; + Top = Top->Parent; + delete Tmp; + + if (Top == Stop) + return; + } + + Item *Tmp = Top; + if (Top != 0) + Top = Top->Next; + delete Tmp; + } +} + /*}}}*/ // Configuration::Exists - Returns true if the Name exists /*{{{*/ // --------------------------------------------------------------------- /* */ -bool Configuration::Exists(const char *Name) +bool Configuration::Exists(const char *Name) const { - Item *Itm = Lookup(Name,false); + const Item *Itm = Lookup(Name); if (Itm == 0) return false; return true; } /*}}}*/ +// Configuration::ExistsAny - Returns true if the Name, possibly /*{{{*/ +// --------------------------------------------------------------------- +/* qualified by /[fdbi] exists */ +bool Configuration::ExistsAny(const char *Name) const +{ + string key = Name; + + if (key.size() > 2 && key.end()[-2] == '/' && + key.find_first_of("fdbi",key.size()-1) < key.size()) + { + key.resize(key.size() - 2); + if (Exists(key.c_str())) + return true; + } + + return Exists(Name); +} + /*}}}*/ // Configuration::Dump - Dump the config /*{{{*/ // --------------------------------------------------------------------- /* Dump the entire configuration space */ @@ -233,7 +395,7 @@ void Configuration::Dump() { /* Write out all of the configuration directives by walking the configuration tree */ - const Configuration::Item *Top = _config->Tree(0); + const Configuration::Item *Top = Tree(0); for (; Top != 0;) { clog << Top->FullTag() << " \"" << Top->Value << "\";" << endl; @@ -248,31 +410,37 @@ void Configuration::Dump() Top = Top->Parent; if (Top != 0) Top = Top->Next; - } + } } /*}}}*/ // Configuration::Item::FullTag - Return the fully scoped tag /*{{{*/ // --------------------------------------------------------------------- -/* */ -string Configuration::Item::FullTag() const +/* Stop sets an optional max recursion depth if this item is being viewed as + part of a sub tree. */ +string Configuration::Item::FullTag(const Item *Stop) const { - if (Parent == 0 || Parent->Parent == 0) + if (Parent == 0 || Parent->Parent == 0 || Parent == Stop) return Tag; - return Parent->FullTag() + "::" + Tag; + return Parent->FullTag(Stop) + "::" + Tag; } /*}}}*/ // ReadConfigFile - Read a configuration file /*{{{*/ // --------------------------------------------------------------------- /* The configuration format is very much like the named.conf format - used in bind8, in fact this routine can parse most named.conf files. */ -bool ReadConfigFile(Configuration &Conf,string FName) -{ + used in bind8, in fact this routine can parse most named.conf files. + Sectional config files are like bind's named.conf where there are + sections like 'zone "foo.org" { .. };' This causes each section to be + added in with a tag like "zone::foo.org" instead of being split + tag/value. */ +bool ReadConfigFile(Configuration &Conf,string FName,bool AsSectional, + unsigned Depth) +{ // Open the stream for reading ifstream F(FName.c_str(),ios::in | ios::nocreate); if (!F != 0) - return _error->Errno("ifstream::ifstream","Opening configuration file %s",FName.c_str()); + return _error->Errno("ifstream::ifstream",_("Opening configuration file %s"),FName.c_str()); char Buffer[300]; string LineBuffer; @@ -366,7 +534,7 @@ bool ReadConfigFile(Configuration &Conf,string FName) if (InQuote == false && (*I == '{' || *I == ';' || *I == '}')) { - // Put the last fragement into the buffer + // Put the last fragment into the buffer char *Start = Buffer; char *Stop = I; for (; Start != I && isspace(*Start) != 0; Start++); @@ -379,51 +547,65 @@ bool ReadConfigFile(Configuration &Conf,string FName) char TermChar = *I; memmove(Buffer,I + 1,strlen(I + 1) + 1); I = Buffer; - - // Move up a tag - if (TermChar == '}') - { - if (StackPos == 0) - ParentTag = string(); - else - ParentTag = Stack[--StackPos]; - } // Syntax Error if (TermChar == '{' && LineBuffer.empty() == true) - return _error->Error("Syntax error %s:%u: Block starts with no name.",FName.c_str(),CurLine); + return _error->Error(_("Syntax error %s:%u: Block starts with no name."),FName.c_str(),CurLine); + // No string on this line if (LineBuffer.empty() == true) + { + if (TermChar == '}') + { + if (StackPos == 0) + ParentTag = string(); + else + ParentTag = Stack[--StackPos]; + } continue; - + } + // Parse off the tag string Tag; const char *Pos = LineBuffer.c_str(); if (ParseQuoteWord(Pos,Tag) == false) - return _error->Error("Syntax error %s:%u: Malformed Tag",FName.c_str(),CurLine); - + return _error->Error(_("Syntax error %s:%u: Malformed Tag"),FName.c_str(),CurLine); + + // Parse off the word + string Word; + if (ParseCWord(Pos,Word) == false && + ParseQuoteWord(Pos,Word) == false) + { + if (TermChar != '{') + { + Word = Tag; + Tag = ""; + } + } + if (strlen(Pos) != 0) + return _error->Error(_("Syntax error %s:%u: Extra junk after value"),FName.c_str(),CurLine); + // Go down a level if (TermChar == '{') { if (StackPos <= 100) Stack[StackPos++] = ParentTag; + + /* Make sectional tags incorperate the section into the + tag string */ + if (AsSectional == true && Word.empty() == false) + { + Tag += "::" ; + Tag += Word; + Word = ""; + } + if (ParentTag.empty() == true) ParentTag = Tag; else ParentTag += string("::") + Tag; Tag = string(); } - - // Parse off the word - string Word; - if (ParseCWord(Pos,Word) == false) - { - if (TermChar != '{') - { - Word = Tag; - Tag = ""; - } - } // Generate the item name string Item; @@ -437,11 +619,50 @@ bool ReadConfigFile(Configuration &Conf,string FName) Item = ParentTag; } - // Set the item in the configuration class - Conf.Set(Item,Word); - + // Specials + if (Tag.length() >= 1 && Tag[0] == '#') + { + if (ParentTag.empty() == false) + return _error->Error(_("Syntax error %s:%u: Directives can only be done at the top level"),FName.c_str(),CurLine); + Tag.erase(Tag.begin()); + if (Tag == "clear") + Conf.Clear(Word); + else if (Tag == "include") + { + if (Depth > 10) + return _error->Error(_("Syntax error %s:%u: Too many nested includes"),FName.c_str(),CurLine); + if (Word.length() > 2 && Word.end()[-1] == '/') + { + if (ReadConfigDir(Conf,Word,AsSectional,Depth+1) == false) + return _error->Error(_("Syntax error %s:%u: Included from here"),FName.c_str(),CurLine); + } + else + { + if (ReadConfigFile(Conf,Word,AsSectional,Depth+1) == false) + return _error->Error(_("Syntax error %s:%u: Included from here"),FName.c_str(),CurLine); + } + } + else + return _error->Error(_("Syntax error %s:%u: Unsupported directive '%s'"),FName.c_str(),CurLine,Tag.c_str()); + } + else + { + // Set the item in the configuration class + Conf.Set(Item,Word); + } + // Empty the buffer LineBuffer = string(); + + // Move up a tag, but only if there is no bit to parse + if (TermChar == '}') + { + if (StackPos == 0) + ParentTag = string(); + else + ParentTag = Stack[--StackPos]; + } + } else I++; @@ -453,7 +674,60 @@ bool ReadConfigFile(Configuration &Conf,string FName) LineBuffer += " "; LineBuffer += Stripd; } + + if (LineBuffer.empty() == false) + return _error->Error(_("Syntax error %s:%u: Extra junk at end of file"),FName.c_str(),CurLine); + return true; +} + /*}}}*/ +// ReadConfigDir - Read a directory of config files /*{{{*/ +// --------------------------------------------------------------------- +/* */ +bool ReadConfigDir(Configuration &Conf,string Dir,bool AsSectional, + unsigned Depth) +{ + static const char *BadExts[] = {".disabled",".dpkg-old",".dpkg-dist", + ".rpmsave",".rpmorig","~",",v",0}; + + DIR *D = opendir(Dir.c_str()); + if (D == 0) + return _error->Errno("opendir",_("Unable to read %s"),Dir.c_str()); + + vector List; + + for (struct dirent *Ent = readdir(D); Ent != 0; Ent = readdir(D)) + { + if (strcmp(Ent->d_name,".") == 0 || + strcmp(Ent->d_name,"..") == 0) + continue; + + // Skip bad extensions + const char **I; + for (I = BadExts; *I != 0; I++) + { + if (strcmp(Ent->d_name + strlen(Ent->d_name) - strlen(*I),*I) == 0) + break; + } + + if (*I != 0) + continue; + + // Make sure it is a file and not something else + string File = flCombine(Dir,Ent->d_name); + struct stat St; + if (stat(File.c_str(),&St) != 0 || S_ISREG(St.st_mode) == 0) + continue; + + List.push_back(File); + } + closedir(D); + sort(List.begin(),List.end()); + + // Read the files + for (vector::const_iterator I = List.begin(); I != List.end(); I++) + if (ReadConfigFile(Conf,*I,AsSectional,Depth) == false) + return false; return true; } /*}}}*/ diff --git a/apt-pkg/contrib/configuration.h b/apt-pkg/contrib/configuration.h index aeb181c7a..643e0f628 100644 --- a/apt-pkg/contrib/configuration.h +++ b/apt-pkg/contrib/configuration.h @@ -1,6 +1,6 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ -// $Id: configuration.h,v 1.11 1999/04/03 00:34:33 jgg Exp $ +// $Id: configuration.h,v 1.12 2001/02/20 07:03:17 jgg Exp $ /* ###################################################################### Configuration Class @@ -36,6 +36,8 @@ class Configuration { + public: + struct Item { string Value; @@ -44,42 +46,61 @@ class Configuration Item *Child; Item *Next; - string FullTag() const; + string FullTag(const Item *Stop = 0) const; Item() : Parent(0), Child(0), Next(0) {}; }; + + private: + Item *Root; + bool ToFree; Item *Lookup(Item *Head,const char *S,unsigned long Len,bool Create); - Item *Lookup(const char *Name,bool Create); - + Item *Lookup(const char *Name,bool Create); + inline const Item *Lookup(const char *Name) const + { + return ((Configuration *)this)->Lookup(Name,false); + } + public: - string Find(const char *Name,const char *Default = 0); - string Find(string Name,const char *Default = 0) {return Find(Name.c_str(),Default);}; - string FindFile(const char *Name,const char *Default = 0); - string FindDir(const char *Name,const char *Default = 0); - int FindI(const char *Name,int Default = 0); - int FindI(string Name,bool Default = 0) {return FindI(Name.c_str(),Default);}; - bool FindB(const char *Name,bool Default = false); - bool FindB(string Name,bool Default = false) {return FindB(Name.c_str(),Default);}; + string Find(const char *Name,const char *Default = 0) const; + string Find(string Name,const char *Default = 0) const {return Find(Name.c_str(),Default);}; + string FindFile(const char *Name,const char *Default = 0) const; + string FindDir(const char *Name,const char *Default = 0) const; + int FindI(const char *Name,int Default = 0) const; + int FindI(string Name,bool Default = 0) const {return FindI(Name.c_str(),Default);}; + bool FindB(const char *Name,bool Default = false) const; + bool FindB(string Name,bool Default = false) const {return FindB(Name.c_str(),Default);}; + string FindAny(const char *Name,const char *Default = 0) const; inline void Set(string Name,string Value) {Set(Name.c_str(),Value);}; + void CndSet(const char *Name,string Value); void Set(const char *Name,string Value); void Set(const char *Name,int Value); - inline bool Exists(string Name) {return Exists(Name.c_str());}; - bool Exists(const char *Name); - - inline const Item *Tree(const char *Name) {return Lookup(Name,false);}; + inline bool Exists(string Name) const {return Exists(Name.c_str());}; + bool Exists(const char *Name) const; + bool ExistsAny(const char *Name) const; - void Dump(); + void Clear(string Name); + inline const Item *Tree(const char *Name) const {return Lookup(Name);}; + + void Dump(); + + Configuration(const Item *Root); Configuration(); + ~Configuration(); }; extern Configuration *_config; -bool ReadConfigFile(Configuration &Conf,string File); +bool ReadConfigFile(Configuration &Conf,string FName,bool AsSectional = false, + unsigned Depth = 0); + +bool ReadConfigDir(Configuration &Conf,string Dir,bool AsSectional = false, + unsigned Depth = 0); #endif diff --git a/apt-pkg/contrib/error.cc b/apt-pkg/contrib/error.cc index e8b71fa7d..b60bd09a7 100644 --- a/apt-pkg/contrib/error.cc +++ b/apt-pkg/contrib/error.cc @@ -1,6 +1,6 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ -// $Id: error.cc,v 1.8 1999/08/08 07:24:54 jgg Exp $ +// $Id: error.cc,v 1.9 2001/02/20 07:03:17 jgg Exp $ /* ###################################################################### Global Erorr Class - Global error mechanism @@ -34,7 +34,7 @@ is compiled to be thread safe otherwise a non-safe version is used. A Per-Thread error object is maintained in much the same manner as libc manages errno */ -#if _POSIX_THREADS == 1 && defined(HAVE_PTHREAD) +#if defined(_POSIX_THREADS) && defined(HAVE_PTHREAD) #include static pthread_key_t ErrorKey; diff --git a/apt-pkg/contrib/error.h b/apt-pkg/contrib/error.h index bb42e73ba..0dc57927a 100644 --- a/apt-pkg/contrib/error.h +++ b/apt-pkg/contrib/error.h @@ -1,6 +1,6 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ -// $Id: error.h,v 1.6 1999/01/18 06:20:08 jgg Exp $ +// $Id: error.h,v 1.7 2001/02/20 07:03:17 jgg Exp $ /* ###################################################################### Global Erorr Class - Global error mechanism @@ -44,6 +44,15 @@ #pragma interface "apt-pkg/error.h" #endif +#ifdef __GNUG__ +// Methods have a hidden this parameter that is visible to this attribute +#define APT_MFORMAT1 __attribute__ ((format (printf, 2, 3))) +#define APT_MFORMAT2 __attribute__ ((format (printf, 3, 4))) +#else +#define APT_MFORMAT1 +#define APT_MFORMAT2 +#endif + #include class GlobalError @@ -62,13 +71,13 @@ class GlobalError public: // Call to generate an error from a library call. - bool Errno(const char *Function,const char *Description,...); - bool WarningE(const char *Function,const char *Description,...); + bool Errno(const char *Function,const char *Description,...) APT_MFORMAT2; + bool WarningE(const char *Function,const char *Description,...) APT_MFORMAT2; /* A warning should be considered less severe than an error, and may be ignored by the client. */ - bool Error(const char *Description,...); - bool Warning(const char *Description,...); + bool Error(const char *Description,...) APT_MFORMAT1; + bool Warning(const char *Description,...) APT_MFORMAT1; // Simple accessors inline bool PendingError() {return PendingFlag;}; @@ -86,4 +95,7 @@ class GlobalError GlobalError *_GetErrorObj(); #define _error _GetErrorObj() +#undef APT_MFORMAT1 +#undef APT_MFORMAT2 + #endif diff --git a/apt-pkg/contrib/fileutl.cc b/apt-pkg/contrib/fileutl.cc index 65c19ea92..0907f4dcd 100644 --- a/apt-pkg/contrib/fileutl.cc +++ b/apt-pkg/contrib/fileutl.cc @@ -1,6 +1,6 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ -// $Id: fileutl.cc,v 1.34 2000/01/17 07:11:49 jgg Exp $ +// $Id: fileutl.cc,v 1.35 2001/02/20 07:03:17 jgg Exp $ /* ###################################################################### File Utilities @@ -19,6 +19,9 @@ #endif #include #include +#include + +#include #include #include @@ -39,7 +42,7 @@ bool CopyFile(FileFd &From,FileFd &To) return false; // Buffered copy between fds - unsigned char *Buf = new unsigned char[64000]; + SPtrArray Buf = new unsigned char[64000]; unsigned long Size = From.Size(); while (Size != 0) { @@ -49,15 +52,11 @@ bool CopyFile(FileFd &From,FileFd &To) if (From.Read(Buf,ToRead) == false || To.Write(Buf,ToRead) == false) - { - delete [] Buf; return false; - } Size -= ToRead; } - delete [] Buf; return true; } /*}}}*/ @@ -72,11 +71,22 @@ int GetLock(string File,bool Errors) int FD = open(File.c_str(),O_RDWR | O_CREAT | O_TRUNC,0640); if (FD < 0) { + // Read only .. cant have locking problems there. + if (errno == EROFS) + { + _error->Warning(_("Not using locking for read only lock file %s"),File.c_str()); + return dup(0); // Need something for the caller to close + } + if (Errors == true) - _error->Errno("open","Could not open lock file %s",File.c_str()); + _error->Errno("open",_("Could not open lock file %s"),File.c_str()); + + // Feh.. We do this to distinguish the lock vs open case.. + errno = EPERM; return -1; } - + SetCloseExec(FD,true); + // Aquire a write lock struct flock fl; fl.l_type = F_WRLCK; @@ -87,12 +97,15 @@ int GetLock(string File,bool Errors) { if (errno == ENOLCK) { - _error->Warning("Not using locking for nfs mounted lock file %s",File.c_str()); - return true; + _error->Warning(_("Not using locking for nfs mounted lock file %s"),File.c_str()); + return dup(0); // Need something for the caller to close } if (Errors == true) - _error->Errno("open","Could not get lock %s",File.c_str()); + _error->Errno("open",_("Could not get lock %s"),File.c_str()); + + int Tmp = errno; close(FD); + errno = Tmp; return -1; } @@ -150,6 +163,18 @@ string flNotFile(string File) return string(File,0,Res); } /*}}}*/ +// flExtension - Return the extension for the file /*{{{*/ +// --------------------------------------------------------------------- +/* */ +string flExtension(string File) +{ + string::size_type Res = File.rfind('.'); + if (Res == string::npos) + return File; + Res++; + return string(File,Res,Res - File.length()); +} + /*}}}*/ // flNoLink - If file is a symlink then deref it /*{{{*/ // --------------------------------------------------------------------- /* If the name is not a link then the returned path is the input. */ @@ -189,6 +214,24 @@ string flNoLink(string File) } } /*}}}*/ +// flCombine - Combine a file and a directory /*{{{*/ +// --------------------------------------------------------------------- +/* If the file is an absolute path then it is just returned, otherwise + the directory is pre-pended to it. */ +string flCombine(string Dir,string File) +{ + if (File.empty() == true) + return string(); + + if (File[0] == '/' || Dir.empty() == true) + return File; + if (File.length() >= 2 && File[0] == '.' && File[1] == '/') + return File; + if (Dir[Dir.length()-1] == '/') + return Dir + File; + return Dir + '/' + File; +} + /*}}}*/ // SetCloseExec - Set the close on exec flag /*{{{*/ // --------------------------------------------------------------------- /* */ @@ -216,7 +259,7 @@ void SetNonBlock(int Fd,bool Block) /*}}}*/ // WaitFd - Wait for a FD to become readable /*{{{*/ // --------------------------------------------------------------------- -/* This waits for a FD to become readable using select. It is usefull for +/* This waits for a FD to become readable using select. It is useful for applications making use of non-blocking sockets. The timeout is in seconds. */ bool WaitFd(int Fd,bool write,unsigned long timeout) @@ -309,7 +352,7 @@ bool ExecWait(int Pid,const char *Name,bool Reap) if (Reap == true) return false; - return _error->Error("Waited, for %s but it wasn't there",Name); + return _error->Error(_("Waited, for %s but it wasn't there"),Name); } @@ -319,12 +362,12 @@ bool ExecWait(int Pid,const char *Name,bool Reap) if (Reap == true) return false; if (WIFSIGNALED(Status) != 0 && WTERMSIG(Status) == SIGSEGV) - return _error->Error("Sub-process %s recieved a segmentation fault.",Name); + return _error->Error(_("Sub-process %s received a segmentation fault."),Name); if (WIFEXITED(Status) != 0) - return _error->Error("Sub-process %s returned an error code (%u)",Name,WEXITSTATUS(Status)); + return _error->Error(_("Sub-process %s returned an error code (%u)"),Name,WEXITSTATUS(Status)); - return _error->Error("Sub-process %s exited unexpectedly",Name); + return _error->Error(_("Sub-process %s exited unexpectedly"),Name); } return true; @@ -363,7 +406,7 @@ bool FileFd::Open(string FileName,OpenMode Mode, unsigned long Perms) } if (iFd < 0) - return _error->Errno("open","Could not open file %s",FileName.c_str()); + return _error->Errno("open",_("Could not open file %s"),FileName.c_str()); this->FileName = FileName; SetCloseExec(iFd,true); @@ -395,7 +438,7 @@ bool FileFd::Read(void *To,unsigned long Size,bool AllowEof) if (Res < 0) { Flags |= Fail; - return _error->Errno("read","Read error"); + return _error->Errno("read",_("Read error")); } To = (char *)To + Res; @@ -414,7 +457,7 @@ bool FileFd::Read(void *To,unsigned long Size,bool AllowEof) } Flags |= Fail; - return _error->Error("read, still have %u to read but none left",Size); + return _error->Error(_("read, still have %lu to read but none left"),Size); } /*}}}*/ // FileFd::Write - Write to the file /*{{{*/ @@ -432,7 +475,7 @@ bool FileFd::Write(const void *From,unsigned long Size) if (Res < 0) { Flags |= Fail; - return _error->Errno("write","Write error"); + return _error->Errno("write",_("Write error")); } From = (char *)From + Res; @@ -444,7 +487,7 @@ bool FileFd::Write(const void *From,unsigned long Size) return true; Flags |= Fail; - return _error->Error("write, still have %u to write but couldn't",Size); + return _error->Error(_("write, still have %lu to write but couldn't"),Size); } /*}}}*/ // FileFd::Seek - Seek in the file /*{{{*/ @@ -455,7 +498,7 @@ bool FileFd::Seek(unsigned long To) if (lseek(iFd,To,SEEK_SET) != (signed)To) { Flags |= Fail; - return _error->Error("Unable to seek to %u",To); + return _error->Error("Unable to seek to %lu",To); } return true; @@ -469,7 +512,7 @@ bool FileFd::Skip(unsigned long Over) if (lseek(iFd,Over,SEEK_CUR) < 0) { Flags |= Fail; - return _error->Error("Unable to seek ahead %u",Over); + return _error->Error("Unable to seek ahead %lu",Over); } return true; @@ -483,7 +526,7 @@ bool FileFd::Truncate(unsigned long To) if (ftruncate(iFd,To) != 0) { Flags |= Fail; - return _error->Error("Unable to truncate to %u",To); + return _error->Error("Unable to truncate to %lu",To); } return true; @@ -519,13 +562,25 @@ bool FileFd::Close() bool Res = true; if ((Flags & AutoClose) == AutoClose) if (iFd >= 0 && close(iFd) != 0) - Res &= _error->Errno("close","Problem closing the file"); + Res &= _error->Errno("close",_("Problem closing the file")); iFd = -1; if ((Flags & Fail) == Fail && (Flags & DelOnFail) == DelOnFail && FileName.empty() == false) if (unlink(FileName.c_str()) != 0) - Res &= _error->Warning("unlnk","Problem unlinking the file"); + Res &= _error->WarningE("unlnk",_("Problem unlinking the file")); return Res; } /*}}}*/ +// FileFd::Sync - Sync the file /*{{{*/ +// --------------------------------------------------------------------- +/* */ +bool FileFd::Sync() +{ +#ifdef _POSIX_SYNCHRONIZED_IO + if (fsync(iFd) != 0) + return _error->Errno("sync",_("Problem syncing the file")); +#endif + return true; +} + /*}}}*/ diff --git a/apt-pkg/contrib/fileutl.h b/apt-pkg/contrib/fileutl.h index 7ad630ce3..9cf351d0b 100644 --- a/apt-pkg/contrib/fileutl.h +++ b/apt-pkg/contrib/fileutl.h @@ -1,6 +1,6 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ -// $Id: fileutl.h,v 1.22 1999/09/30 06:30:34 jgg Exp $ +// $Id: fileutl.h,v 1.23 2001/02/20 07:03:17 jgg Exp $ /* ###################################################################### File Utilities @@ -49,7 +49,8 @@ class FileFd unsigned long Size(); bool Open(string FileName,OpenMode Mode,unsigned long Perms = 0666); bool Close(); - + bool Sync(); + // Simple manipulators inline int Fd() {return iFd;}; inline void Fd(int fd) {iFd = fd;}; @@ -84,5 +85,7 @@ bool ExecWait(int Pid,const char *Name,bool Reap = false); string flNotDir(string File); string flNotFile(string File); string flNoLink(string File); +string flExtension(string File); +string flCombine(string Dir,string File); #endif diff --git a/apt-pkg/contrib/md5.h b/apt-pkg/contrib/md5.h index 19b5bac6c..8b809729b 100644 --- a/apt-pkg/contrib/md5.h +++ b/apt-pkg/contrib/md5.h @@ -1,6 +1,6 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ -// $Id: md5.h,v 1.4 1999/08/02 03:07:47 jgg Exp $ +// $Id: md5.h,v 1.5 2001/02/20 07:03:17 jgg Exp $ /* ###################################################################### MD5SumValue - Storage for a MD5Sum @@ -33,7 +33,7 @@ class MD5Summation; class MD5SumValue { - friend MD5Summation; + friend class MD5Summation; unsigned char Sum[4*4]; public: diff --git a/apt-pkg/contrib/mmap.cc b/apt-pkg/contrib/mmap.cc index 230e133a5..cfe476763 100644 --- a/apt-pkg/contrib/mmap.cc +++ b/apt-pkg/contrib/mmap.cc @@ -1,6 +1,6 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ -// $Id: mmap.cc,v 1.20 1999/10/02 04:14:54 jgg Exp $ +// $Id: mmap.cc,v 1.21 2001/02/20 07:03:17 jgg Exp $ /* ###################################################################### MMap Class - Provides 'real' mmap or a faked mmap using read(). @@ -29,6 +29,8 @@ #include #include +#include + #include #include #include @@ -77,12 +79,12 @@ bool MMap::Map(FileFd &Fd) Map = MAP_PRIVATE; if (iSize == 0) - return _error->Error("Can't mmap an empty file"); + return _error->Error(_("Can't mmap an empty file")); // Map it. Base = mmap(0,iSize,Prot,Map,Fd.Fd(),0); if (Base == (void *)-1) - return _error->Errno("mmap","Couldn't make mmap of %u bytes",iSize); + return _error->Errno("mmap",_("Couldn't make mmap of %lu bytes"),iSize); return true; } @@ -102,6 +104,7 @@ bool MMap::Close(bool DoSync) _error->Warning("Unable to munmap"); iSize = 0; + Base = 0; return true; } /*}}}*/ @@ -150,9 +153,15 @@ DynamicMMap::DynamicMMap(FileFd &F,unsigned long Flags,unsigned long WorkSpace) return; unsigned long EndOfFile = Fd->Size(); - Fd->Seek(WorkSpace); - char C = 0; - Fd->Write(&C,sizeof(C)); + if (EndOfFile > WorkSpace) + WorkSpace = EndOfFile; + else + { + Fd->Seek(WorkSpace); + char C = 0; + Fd->Write(&C,sizeof(C)); + } + Map(F); iSize = EndOfFile; } @@ -182,11 +191,9 @@ DynamicMMap::~DynamicMMap() } unsigned long EndOfFile = iSize; - Sync(); iSize = WorkSpace; Close(false); ftruncate(Fd->Fd(),EndOfFile); - Fd->Close(); } /*}}}*/ // DynamicMMap::RawAllocate - Allocate a raw chunk of unaligned space /*{{{*/ diff --git a/apt-pkg/contrib/progress.cc b/apt-pkg/contrib/progress.cc index dfa978485..70e488d5f 100644 --- a/apt-pkg/contrib/progress.cc +++ b/apt-pkg/contrib/progress.cc @@ -1,6 +1,6 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ -// $Id: progress.cc,v 1.9 2000/06/05 04:22:25 jgg Exp $ +// $Id: progress.cc,v 1.10 2001/02/20 07:03:17 jgg Exp $ /* ###################################################################### OpProgress - Operation Progress @@ -14,6 +14,9 @@ #include #include #include + +#include + #include /*}}}*/ @@ -110,6 +113,9 @@ bool OpProgress::CheckChange(float Interval) if ((int)LastPercent == (int)Percent) return false; + if (Interval == 0) + return false; + // Check time delta struct timeval Now; gettimeofday(&Now,0); @@ -142,9 +148,9 @@ void OpTextProgress::Done() { char S[300]; if (_error->PendingError() == true) - snprintf(S,sizeof(S),"\r%s... Error!",OldOp.c_str()); + snprintf(S,sizeof(S),_("\r%s... Error!"),OldOp.c_str()); else - snprintf(S,sizeof(S),"\r%s... Done",OldOp.c_str()); + snprintf(S,sizeof(S),_("\r%s... Done"),OldOp.c_str()); Write(S); cout << endl; OldOp = string(); @@ -162,7 +168,7 @@ void OpTextProgress::Done() /* */ void OpTextProgress::Update() { - if (CheckChange() == false) + if (CheckChange((NoUpdate == true?0:0.7)) == false) return; // No percent spinner diff --git a/apt-pkg/contrib/sptr.h b/apt-pkg/contrib/sptr.h new file mode 100644 index 000000000..a9347edf9 --- /dev/null +++ b/apt-pkg/contrib/sptr.h @@ -0,0 +1,66 @@ +// -*- mode: cpp; mode: fold -*- +// Description /*{{{*/ +// $Id: sptr.h,v 1.2 2001/02/20 07:03:17 jgg Exp $ +/* ###################################################################### + + Trivial non-ref counted 'smart pointer' + + This is really only good to eliminate + { + delete Foo; + return; + } + + Blocks from functions. + + I think G++ has become good enough that doing this won't have much + code size implications. + + ##################################################################### */ + /*}}}*/ +#ifndef SMART_POINTER_H +#define SMART_POINTER_H + +template +class SPtr +{ + public: + T *Ptr; + + inline T *operator ->() {return Ptr;}; + inline T &operator *() {return *Ptr;}; + inline operator T *() {return Ptr;}; + inline operator void *() {return Ptr;}; + inline T *UnGuard() {T *Tmp = Ptr; Ptr = 0; return Tmp;}; + inline void operator =(T *N) {Ptr = N;}; + inline bool operator ==(T *lhs) const {return Ptr == lhs;}; + inline bool operator !=(T *lhs) const {return Ptr != lhs;}; + inline T*Get() {return Ptr;}; + + inline SPtr(T *Ptr) : Ptr(Ptr) {}; + inline SPtr() : Ptr(0) {}; + inline ~SPtr() {delete Ptr;}; +}; + +template +class SPtrArray +{ + public: + T *Ptr; + + inline T &operator *() {return *Ptr;}; + inline operator T *() {return Ptr;}; + inline operator void *() {return Ptr;}; + inline T *UnGuard() {T *Tmp = Ptr; Ptr = 0; return Tmp;}; + inline T &operator [](signed long I) {return Ptr[I];}; + inline void operator =(T *N) {Ptr = N;}; + inline bool operator ==(T *lhs) const {return Ptr == lhs;}; + inline bool operator !=(T *lhs) const {return Ptr != lhs;}; + inline T*Get() {return Ptr;}; + + inline SPtrArray(T *Ptr) : Ptr(Ptr) {}; + inline SPtrArray() : Ptr(0) {}; + inline ~SPtrArray() {delete []Ptr;}; +}; + +#endif diff --git a/apt-pkg/contrib/strutl.cc b/apt-pkg/contrib/strutl.cc index f8a3f8e2b..c1a1cb4db 100644 --- a/apt-pkg/contrib/strutl.cc +++ b/apt-pkg/contrib/strutl.cc @@ -1,12 +1,12 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ -// $Id: strutl.cc,v 1.34 2000/01/16 05:36:17 jgg Exp $ +// $Id: strutl.cc,v 1.35 2001/02/20 07:03:17 jgg Exp $ /* ###################################################################### - String Util - Some usefull string functions. + String Util - Some useful string functions. - These have been collected from here and there to do all sorts of usefull - things to strings. They are usefull in file parsers, URI handlers and + These have been collected from here and there to do all sorts of useful + things to strings. They are useful in file parsers, URI handlers and especially in APT methods. This source is placed in the Public Domain, do with it what you will @@ -21,12 +21,17 @@ #include #include +#include +#include + #include #include #include #include +#include #include +#include /*}}}*/ // strstrip - Remove white space from the front and back of a string /*{{{*/ @@ -147,9 +152,9 @@ bool ParseQuoteWord(const char *&String,string &Res) /*}}}*/ // ParseCWord - Parses a string like a C "" expression /*{{{*/ // --------------------------------------------------------------------- -/* This expects a series of space seperated strings enclosed in ""'s. +/* This expects a series of space separated strings enclosed in ""'s. It concatenates the ""'s into a single string. */ -bool ParseCWord(const char *String,string &Res) +bool ParseCWord(const char *&String,string &Res) { // Skip leading whitespace const char *C = String; @@ -180,9 +185,10 @@ bool ParseCWord(const char *String,string &Res) if (isspace(*C) == 0) return false; *Buf++ = ' '; - } + } *Buf = 0; Res = Buffer; + String = C; return true; } /*}}}*/ @@ -325,6 +331,13 @@ string SubstVar(string Str,string Subst,string Contents) return Temp + string(Str,OldPos); } + +string SubstVar(string Str,const struct SubstVar *Vars) +{ + for (; Vars->Subst != 0; Vars++) + Str = SubstVar(Str,Vars->Subst,*Vars->Contents); + return Str; +} /*}}}*/ // URItoFileName - Convert the uri into a unique file name /*{{{*/ // --------------------------------------------------------------------- @@ -548,9 +561,11 @@ bool ReadMessages(int Fd, vector &List) return false; // No data - if (Res <= 0) + if (Res < 0 && errno == EAGAIN) return true; - + if (Res < 0) + return false; + End += Res; // Look for the end of the message @@ -749,6 +764,121 @@ bool Hex2Num(const char *Start,const char *End,unsigned char *Num, return true; } /*}}}*/ +// TokSplitString - Split a string up by a given token /*{{{*/ +// --------------------------------------------------------------------- +/* This is intended to be a faster splitter, it does not use dynamic + memories. Input is changed to insert nulls at each token location. */ +bool TokSplitString(char Tok,char *Input,char **List, + unsigned long ListMax) +{ + // Strip any leading spaces + char *Start = Input; + char *Stop = Start + strlen(Start); + for (; *Start != 0 && isspace(*Start) != 0; Start++); + + unsigned long Count = 0; + char *Pos = Start; + while (Pos != Stop) + { + // Skip to the next Token + for (; Pos != Stop && *Pos != Tok; Pos++); + + // Back remove spaces + char *End = Pos; + for (; End > Start && (End[-1] == Tok || isspace(End[-1]) != 0); End--); + *End = 0; + + List[Count++] = Start; + if (Count >= ListMax) + { + List[Count-1] = 0; + return false; + } + + // Advance pos + for (; Pos != Stop && (*Pos == Tok || isspace(*Pos) != 0 || *Pos == 0); Pos++); + Start = Pos; + } + + List[Count] = 0; + return true; +} + /*}}}*/ +// RegexChoice - Simple regex list/list matcher /*{{{*/ +// --------------------------------------------------------------------- +/* */ +unsigned long RegexChoice(RxChoiceList *Rxs,const char **ListBegin, + const char **ListEnd) +{ + for (RxChoiceList *R = Rxs; R->Str != 0; R++) + R->Hit = false; + + unsigned long Hits = 0; + for (; ListBegin != ListEnd; ListBegin++) + { + // Check if the name is a regex + const char *I; + bool Regex = true; + for (I = *ListBegin; *I != 0; I++) + if (*I == '.' || *I == '?' || *I == '*' || *I == '|') + break; + if (*I == 0) + Regex = false; + + // Compile the regex pattern + regex_t Pattern; + if (Regex == true) + if (regcomp(&Pattern,*ListBegin,REG_EXTENDED | REG_ICASE | + REG_NOSUB) != 0) + Regex = false; + + // Search the list + bool Done = false; + for (RxChoiceList *R = Rxs; R->Str != 0; R++) + { + if (R->Str[0] == 0) + continue; + + if (strcasecmp(R->Str,*ListBegin) != 0) + { + if (Regex == false) + continue; + if (regexec(&Pattern,R->Str,0,0,0) != 0) + continue; + } + Done = true; + + if (R->Hit == false) + Hits++; + + R->Hit = true; + } + + if (Regex == true) + regfree(&Pattern); + + if (Done == false) + _error->Warning(_("Selection %s not found"),*ListBegin); + } + + return Hits; +} + /*}}}*/ +// ioprintf - C format string outputter to C++ iostreams /*{{{*/ +// --------------------------------------------------------------------- +/* This is used to make the internationalization strinc easier to translate + and to allow reordering of parameters */ +void ioprintf(ostream &out,const char *format,...) +{ + va_list args; + va_start(args,format); + + // sprintf the description + char S[400]; + vsnprintf(S,sizeof(S),format,args); + out << S; +} + /*}}}*/ // URI::CopyFrom - Copy from an object /*{{{*/ // --------------------------------------------------------------------- @@ -757,7 +887,7 @@ void URI::CopyFrom(string U) { string::const_iterator I = U.begin(); - // Locate the first colon, this seperates the scheme + // Locate the first colon, this separates the scheme for (; I < U.end() && *I != ':' ; I++); string::const_iterator FirstColon = I; @@ -912,3 +1042,16 @@ URI::operator string() return Res; } /*}}}*/ +// URI::SiteOnly - Return the schema and site for the URI /*{{{*/ +// --------------------------------------------------------------------- +/* */ +string URI::SiteOnly(string URI) +{ + ::URI U(URI); + U.User = string(); + U.Password = string(); + U.Path = string(); + U.Port = 0; + return U; +} + /*}}}*/ diff --git a/apt-pkg/contrib/strutl.h b/apt-pkg/contrib/strutl.h index 14293ae05..5549673a1 100644 --- a/apt-pkg/contrib/strutl.h +++ b/apt-pkg/contrib/strutl.h @@ -1,9 +1,9 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ -// $Id: strutl.h,v 1.15 1999/08/02 03:07:48 jgg Exp $ +// $Id: strutl.h,v 1.16 2001/02/20 07:03:17 jgg Exp $ /* ###################################################################### - String Util - These are some usefull string functions + String Util - These are some useful string functions _strstrip is a function to remove whitespace from the front and end of a string. @@ -25,15 +25,21 @@ #include #include +#ifdef __GNUG__ +// Methods have a hidden this parameter that is visible to this attribute +#define APT_FORMAT2 __attribute__ ((format (printf, 2, 3))) +#else +#define APT_FORMAT2 +#endif + char *_strstrip(char *String); char *_strtabexpand(char *String,size_t Len); bool ParseQuoteWord(const char *&String,string &Res); -bool ParseCWord(const char *String,string &Res); +bool ParseCWord(const char *&String,string &Res); string QuoteString(string Str,const char *Bad); string DeQuoteString(string Str); string SizeToStr(double Bytes); string TimeToStr(unsigned long Sec); -string SubstVar(string Str,string Subst,string Contents); string Base64Encode(string Str); string URItoFileName(string URI); string TimeRFC1123(time_t Date); @@ -44,6 +50,9 @@ bool ReadMessages(int Fd, vector &List); bool StrToNum(const char *Str,unsigned long &Res,unsigned Len,unsigned Base = 0); bool Hex2Num(const char *Start,const char *End,unsigned char *Num, unsigned int Length); +bool TokSplitString(char Tok,char *Input,char **List, + unsigned long ListMax); +void ioprintf(ostream &out,const char *format,...) APT_FORMAT2; int stringcmp(const char *A,const char *AEnd,const char *B,const char *BEnd); inline int stringcmp(const char *A,const char *AEnd,const char *B) {return stringcmp(A,AEnd,B,B+strlen(B));}; @@ -51,6 +60,7 @@ inline int stringcmp(string A,const char *B) {return stringcmp(A.begin(),A.end() int stringcasecmp(const char *A,const char *AEnd,const char *B,const char *BEnd); inline int stringcasecmp(const char *A,const char *AEnd,const char *B) {return stringcasecmp(A,AEnd,B,B+strlen(B));}; inline int stringcasecmp(string A,const char *B) {return stringcasecmp(A.begin(),A.end(),B,B+strlen(B));}; +inline int stringcasecmp(string A,string B) {return stringcasecmp(A.begin(),A.end(),B.begin(),B.end());}; class URI { @@ -68,9 +78,29 @@ class URI operator string(); inline void operator =(string From) {CopyFrom(From);}; inline bool empty() {return Access.empty();}; + static string SiteOnly(string URI); URI(string Path) {CopyFrom(Path);}; URI() : Port(0) {}; }; +struct SubstVar +{ + const char *Subst; + const string *Contents; +}; +string SubstVar(string Str,const struct SubstVar *Vars); +string SubstVar(string Str,string Subst,string Contents); + +struct RxChoiceList +{ + void *UserData; + const char *Str; + bool Hit; +}; +unsigned long RegexChoice(RxChoiceList *Rxs,const char **ListBegin, + const char **ListEnd); + +#undef APT_FORMAT2 + #endif diff --git a/apt-pkg/deb/debindexfile.cc b/apt-pkg/deb/debindexfile.cc new file mode 100644 index 000000000..67afc89e6 --- /dev/null +++ b/apt-pkg/deb/debindexfile.cc @@ -0,0 +1,506 @@ +// -*- mode: cpp; mode: fold -*- +// Description /*{{{*/ +// $Id: debindexfile.cc,v 1.2 2001/02/20 07:03:17 jgg Exp $ +/* ###################################################################### + + Debian Specific sources.list types and the three sorts of Debian + index files. + + ##################################################################### */ + /*}}}*/ +// Include Files /*{{{*/ +#ifdef __GNUG__ +#pragma implementation "apt-pkg/debindexfile.h" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + /*}}}*/ + +// SourcesIndex::debSourcesIndex - Constructor /*{{{*/ +// --------------------------------------------------------------------- +/* */ +debSourcesIndex::debSourcesIndex(string URI,string Dist,string Section) : + URI(URI), Dist(Dist), Section(Section) +{ +} + /*}}}*/ +// SourcesIndex::SourceInfo - Short 1 liner describing a source /*{{{*/ +// --------------------------------------------------------------------- +/* The result looks like: + http://foo/ stable/main src 1.1.1 (dsc) */ +string debSourcesIndex::SourceInfo(pkgSrcRecords::Parser const &Record, + pkgSrcRecords::File const &File) const +{ + string Res; + Res = ::URI::SiteOnly(URI) + ' '; + if (Dist[Dist.size() - 1] == '/') + { + if (Dist != "/") + Res += Dist; + } + else + Res += Dist + '/' + Section; + + Res += " "; + Res += Record.Package(); + Res += " "; + Res += Record.Version(); + if (File.Type.empty() == false) + Res += " (" + File.Type + ")"; + return Res; +} + /*}}}*/ +// SourcesIndex::CreateSrcParser - Get a parser for the source files /*{{{*/ +// --------------------------------------------------------------------- +/* */ +pkgSrcRecords::Parser *debSourcesIndex::CreateSrcParser() const +{ + string SourcesURI; + if (Dist[Dist.size() - 1] == '/') + SourcesURI = URI + Dist; + else + SourcesURI = URI + "dists/" + Dist + '/' + Section + + "/source/"; + + SourcesURI += "Sources"; + SourcesURI = URItoFileName(SourcesURI); + return new debSrcRecordParser(_config->FindDir("Dir::State::lists") + + SourcesURI,this); +} + /*}}}*/ +// SourcesIndex::Describe - Give a descriptive path to the index /*{{{*/ +// --------------------------------------------------------------------- +/* */ +string debSourcesIndex::Describe() const +{ + char S[300]; + snprintf(S,sizeof(S),"%s (%s)",Info("Packages").c_str(), + IndexFile("Sources").c_str()); + return S; +} + /*}}}*/ +// SourcesIndex::Info - One liner describing the index URI /*{{{*/ +// --------------------------------------------------------------------- +/* */ +string debSourcesIndex::Info(const char *Type) const +{ + string Info = ::URI::SiteOnly(URI) + ' '; + if (Dist[Dist.size() - 1] == '/') + { + if (Dist != "/") + Info += Dist; + } + else + Info += Dist + '/' + Section; + Info += " "; + Info += Type; + return Info; +} + /*}}}*/ +// SourcesIndex::Index* - Return the URI to the index files /*{{{*/ +// --------------------------------------------------------------------- +/* */ +inline string debSourcesIndex::IndexFile(const char *Type) const +{ + return URItoFileName(IndexURI(Type)); +} +string debSourcesIndex::IndexURI(const char *Type) const +{ + string Res; + if (Dist[Dist.size() - 1] == '/') + { + if (Dist != "/") + Res = URI + Dist; + else + Res = URI; + } + else + Res = URI + "dists/" + Dist + '/' + Section + + "/source/"; + + Res += Type; + return Res; +} + /*}}}*/ +// SourcesIndex::GetIndexes - Fetch the index files /*{{{*/ +// --------------------------------------------------------------------- +/* */ +bool debSourcesIndex::GetIndexes(pkgAcquire *Owner) const +{ + new pkgAcqIndex(Owner,IndexURI("Sources"),Info("Sources"),"Sources"); + new pkgAcqIndexRel(Owner,IndexURI("Release"),Info("Release"),"Release"); + return true; +} + /*}}}*/ +// SourcesIndex::Exists - Check if the index is available /*{{{*/ +// --------------------------------------------------------------------- +/* */ +bool debSourcesIndex::Exists() const +{ + return FileExists(IndexFile("Sources")); +} + /*}}}*/ +// SourcesIndex::Size - Return the size of the index /*{{{*/ +// --------------------------------------------------------------------- +/* */ +unsigned long debSourcesIndex::Size() const +{ + struct stat S; + if (stat(IndexFile("Sources").c_str(),&S) != 0) + return 0; + return S.st_size; +} + /*}}}*/ + +// PackagesIndex::debPackagesIndex - Contructor /*{{{*/ +// --------------------------------------------------------------------- +/* */ +debPackagesIndex::debPackagesIndex(string URI,string Dist,string Section) : + URI(URI), Dist(Dist), Section(Section) +{ +} + /*}}}*/ +// PackagesIndex::ArchiveInfo - Short version of the archive url /*{{{*/ +// --------------------------------------------------------------------- +/* This is a shorter version that is designed to be < 60 chars or so */ +string debPackagesIndex::ArchiveInfo(pkgCache::VerIterator Ver) const +{ + string Res = ::URI::SiteOnly(URI) + ' '; + if (Dist[Dist.size() - 1] == '/') + { + if (Dist != "/") + Res += Dist; + } + else + Res += Dist + '/' + Section; + + Res += " "; + Res += Ver.ParentPkg().Name(); + Res += " "; + Res += Ver.VerStr(); + return Res; +} + /*}}}*/ +// PackagesIndex::Describe - Give a descriptive path to the index /*{{{*/ +// --------------------------------------------------------------------- +/* This should help the user find the index in the sources.list and + in the filesystem for problem solving */ +string debPackagesIndex::Describe() const +{ + char S[300]; + snprintf(S,sizeof(S),"%s (%s)",Info("Packages").c_str(), + IndexFile("Packages").c_str()); + return S; +} + /*}}}*/ +// PackagesIndex::Info - One liner describing the index URI /*{{{*/ +// --------------------------------------------------------------------- +/* */ +string debPackagesIndex::Info(const char *Type) const +{ + string Info = ::URI::SiteOnly(URI) + ' '; + if (Dist[Dist.size() - 1] == '/') + { + if (Dist != "/") + Info += Dist; + } + else + Info += Dist + '/' + Section; + Info += " "; + Info += Type; + return Info; +} + /*}}}*/ +// PackagesIndex::Index* - Return the URI to the index files /*{{{*/ +// --------------------------------------------------------------------- +/* */ +inline string debPackagesIndex::IndexFile(const char *Type) const +{ + return _config->FindDir("Dir::State::lists") + URItoFileName(IndexURI(Type)); +} +string debPackagesIndex::IndexURI(const char *Type) const +{ + string Res; + if (Dist[Dist.size() - 1] == '/') + { + if (Dist != "/") + Res = URI + Dist; + else + Res = URI; + } + else + Res = URI + "dists/" + Dist + '/' + Section + + "/binary-" + _config->Find("APT::Architecture") + '/'; + + Res += Type; + return Res; +} + /*}}}*/ +// PackagesIndex::GetIndexes - Fetch the index files /*{{{*/ +// --------------------------------------------------------------------- +/* */ +bool debPackagesIndex::GetIndexes(pkgAcquire *Owner) const +{ + new pkgAcqIndex(Owner,IndexURI("Packages"),Info("Packages"),"Packages"); + new pkgAcqIndexRel(Owner,IndexURI("Release"),Info("Release"),"Release"); + return true; +} + /*}}}*/ +// PackagesIndex::Exists - Check if the index is available /*{{{*/ +// --------------------------------------------------------------------- +/* */ +bool debPackagesIndex::Exists() const +{ + return FileExists(IndexFile("Packages")); +} + /*}}}*/ +// PackagesIndex::Size - Return the size of the index /*{{{*/ +// --------------------------------------------------------------------- +/* This is really only used for progress reporting. */ +unsigned long debPackagesIndex::Size() const +{ + struct stat S; + if (stat(IndexFile("Packages").c_str(),&S) != 0) + return 0; + return S.st_size; +} + /*}}}*/ +// PackagesIndex::Merge - Load the index file into a cache /*{{{*/ +// --------------------------------------------------------------------- +/* */ +bool debPackagesIndex::Merge(pkgCacheGenerator &Gen,OpProgress &Prog) const +{ + string PackageFile = IndexFile("Packages"); + FileFd Pkg(PackageFile,FileFd::ReadOnly); + debListParser Parser(&Pkg); + if (_error->PendingError() == true) + return _error->Error("Problem opening %s",PackageFile.c_str()); + + Prog.SubProgress(0,Info("Packages")); + ::URI Tmp(URI); + if (Gen.SelectFile(PackageFile,Tmp.Host,*this) == false) + return _error->Error("Problem with SelectFile %s",PackageFile.c_str()); + + // Store the IMS information + pkgCache::PkgFileIterator File = Gen.GetCurFile(); + struct stat St; + if (fstat(Pkg.Fd(),&St) != 0) + return _error->Errno("fstat","Failed to stat"); + File->Size = St.st_size; + File->mtime = St.st_mtime; + + if (Gen.MergeList(Parser) == false) + return _error->Error("Problem with MergeList %s",PackageFile.c_str()); + + // Check the release file + string ReleaseFile = IndexFile("Release"); + if (FileExists(ReleaseFile) == true) + { + FileFd Rel(ReleaseFile,FileFd::ReadOnly); + if (_error->PendingError() == true) + return false; + Parser.LoadReleaseInfo(File,Rel); + } + + return true; +} + /*}}}*/ +// PackagesIndex::FindInCache - Find this index /*{{{*/ +// --------------------------------------------------------------------- +/* */ +pkgCache::PkgFileIterator debPackagesIndex::FindInCache(pkgCache &Cache) const +{ + string FileName = IndexFile("Packages"); + pkgCache::PkgFileIterator File = Cache.FileBegin(); + for (; File.end() == false; File++) + { + if (FileName != File.FileName()) + continue; + + struct stat St; + if (stat(File.FileName(),&St) != 0) + return pkgCache::PkgFileIterator(Cache); + if ((unsigned)St.st_size != File->Size || St.st_mtime != File->mtime) + return pkgCache::PkgFileIterator(Cache); + return File; + } + + return File; +} + /*}}}*/ + +// StatusIndex::debStatusIndex - Constructor /*{{{*/ +// --------------------------------------------------------------------- +/* */ +debStatusIndex::debStatusIndex(string File) : File(File) +{ +} + /*}}}*/ +// StatusIndex::Size - Return the size of the index /*{{{*/ +// --------------------------------------------------------------------- +/* */ +unsigned long debStatusIndex::Size() const +{ + struct stat S; + if (stat(File.c_str(),&S) != 0) + return 0; + return S.st_size; +} + /*}}}*/ +// StatusIndex::Merge - Load the index file into a cache /*{{{*/ +// --------------------------------------------------------------------- +/* */ +bool debStatusIndex::Merge(pkgCacheGenerator &Gen,OpProgress &Prog) const +{ + FileFd Pkg(File,FileFd::ReadOnly); + if (_error->PendingError() == true) + return false; + debListParser Parser(&Pkg); + if (_error->PendingError() == true) + return false; + + Prog.SubProgress(0,File); + if (Gen.SelectFile(File,string(),*this,pkgCache::Flag::NotSource) == false) + return _error->Error("Problem with SelectFile %s",File.c_str()); + + // Store the IMS information + pkgCache::PkgFileIterator CFile = Gen.GetCurFile(); + struct stat St; + if (fstat(Pkg.Fd(),&St) != 0) + return _error->Errno("fstat","Failed to stat"); + CFile->Size = St.st_size; + CFile->mtime = St.st_mtime; + CFile->Archive = Gen.WriteUniqString("now"); + + if (Gen.MergeList(Parser) == false) + return _error->Error("Problem with MergeList %s",File.c_str()); + return true; +} + /*}}}*/ +// StatusIndex::FindInCache - Find this index /*{{{*/ +// --------------------------------------------------------------------- +/* */ +pkgCache::PkgFileIterator debStatusIndex::FindInCache(pkgCache &Cache) const +{ + pkgCache::PkgFileIterator File = Cache.FileBegin(); + for (; File.end() == false; File++) + { + if (this->File != File.FileName()) + continue; + + struct stat St; + if (stat(File.FileName(),&St) != 0) + return pkgCache::PkgFileIterator(Cache); + if ((unsigned)St.st_size != File->Size || St.st_mtime != File->mtime) + return pkgCache::PkgFileIterator(Cache); + return File; + } + return File; +} + /*}}}*/ +// StatusIndex::Exists - Check if the index is available /*{{{*/ +// --------------------------------------------------------------------- +/* */ +bool debStatusIndex::Exists() const +{ + // Abort if the file does not exist. + return true; +} + /*}}}*/ + +// Source List types for Debian /*{{{*/ +class debSLTypeDeb : public pkgSourceList::Type +{ + public: + + bool CreateItem(vector &List,string URI, + string Dist,string Section) const + { + List.push_back(new debPackagesIndex(URI,Dist,Section)); + return true; + }; + + debSLTypeDeb() + { + Name = "deb"; + Label = "Standard Debian binary tree"; + } +}; + +class debSLTypeDebSrc : public pkgSourceList::Type +{ + public: + + bool CreateItem(vector &List,string URI, + string Dist,string Section) const + { + List.push_back(new debSourcesIndex(URI,Dist,Section)); + return true; + }; + + debSLTypeDebSrc() + { + Name = "deb-src"; + Label = "Standard Debian source tree"; + } +}; + +debSLTypeDeb _apt_DebType; +debSLTypeDebSrc _apt_DebSrcType; + /*}}}*/ +// Index File types for Debian /*{{{*/ +class debIFTypeSrc : public pkgIndexFile::Type +{ + public: + + debIFTypeSrc() {Label = "Debian Source Index";}; +}; +class debIFTypePkg : public pkgIndexFile::Type +{ + public: + + virtual pkgRecords::Parser *CreatePkgParser(pkgCache::PkgFileIterator File) const + { + return new debRecordParser(File.FileName(),*File.Cache()); + }; + debIFTypePkg() {Label = "Debian Package Index";}; +}; +class debIFTypeStatus : public pkgIndexFile::Type +{ + public: + + virtual pkgRecords::Parser *CreatePkgParser(pkgCache::PkgFileIterator File) const + { + return new debRecordParser(File.FileName(),*File.Cache()); + }; + debIFTypeStatus() {Label = "Debian dpkg status file";}; +}; +static debIFTypeSrc _apt_Src; +static debIFTypePkg _apt_Pkg; +static debIFTypeStatus _apt_Status; + +const pkgIndexFile::Type *debSourcesIndex::GetType() const +{ + return &_apt_Src; +} +const pkgIndexFile::Type *debPackagesIndex::GetType() const +{ + return &_apt_Pkg; +} +const pkgIndexFile::Type *debStatusIndex::GetType() const +{ + return &_apt_Status; +} + + /*}}}*/ diff --git a/apt-pkg/deb/debindexfile.h b/apt-pkg/deb/debindexfile.h new file mode 100644 index 000000000..b4dee3c22 --- /dev/null +++ b/apt-pkg/deb/debindexfile.h @@ -0,0 +1,112 @@ +// -*- mode: cpp; mode: fold -*- +// Description /*{{{*/ +// $Id: debindexfile.h,v 1.2 2001/02/20 07:03:17 jgg Exp $ +/* ###################################################################### + + Debian Index Files + + There are three sorts currently + + Package files that have File: tags + Package files that don't (/var/lib/dpkg/status) + Source files + + ##################################################################### */ + /*}}}*/ +#ifndef PKGLIB_DEBINDEXFILE_H +#define PKGLIB_DEBINDEXFILE_H + +#ifdef __GNUG__ +#pragma interface "apt-pkg/debindexfile.h" +#endif + +#include + +class debStatusIndex : public pkgIndexFile +{ + string File; + + public: + + virtual const Type *GetType() const; + + // Interface for acquire + virtual string Describe() const {return File;}; + + // Interface for the Cache Generator + virtual bool Exists() const; + virtual bool HasPackages() const {return true;}; + virtual unsigned long Size() const; + virtual bool Merge(pkgCacheGenerator &Gen,OpProgress &Prog) const; + virtual pkgCache::PkgFileIterator FindInCache(pkgCache &Cache) const; + + debStatusIndex(string File); +}; + +class debPackagesIndex : public pkgIndexFile +{ + string URI; + string Dist; + string Section; + + string Info(const char *Type) const; + string IndexFile(const char *Type) const; + string IndexURI(const char *Type) const; + + public: + + virtual const Type *GetType() const; + + // Stuff for accessing files on remote items + virtual string ArchiveInfo(pkgCache::VerIterator Ver) const; + virtual string ArchiveURI(string File) const {return URI + File;}; + + // Interface for acquire + virtual string Describe() const; + virtual bool GetIndexes(pkgAcquire *Owner) const; + + // Interface for the Cache Generator + virtual bool Exists() const; + virtual bool HasPackages() const {return true;}; + virtual unsigned long Size() const; + virtual bool Merge(pkgCacheGenerator &Gen,OpProgress &Prog) const; + virtual pkgCache::PkgFileIterator FindInCache(pkgCache &Cache) const; + + debPackagesIndex(string URI,string Dist,string Section); +}; + +class debSourcesIndex : public pkgIndexFile +{ + string URI; + string Dist; + string Section; + + string Info(const char *Type) const; + string IndexFile(const char *Type) const; + string IndexURI(const char *Type) const; + + public: + + virtual const Type *GetType() const; + + // Stuff for accessing files on remote items + virtual string SourceInfo(pkgSrcRecords::Parser const &Record, + pkgSrcRecords::File const &File) const; + virtual string ArchiveURI(string File) const {return URI + File;}; + + // Interface for acquire + virtual string Describe() const; + virtual bool GetIndexes(pkgAcquire *Owner) const; + + // Interface for the record parsers + virtual pkgSrcRecords::Parser *CreateSrcParser() const; + + // Interface for the Cache Generator + virtual bool Exists() const; + virtual bool HasPackages() const {return false;}; + virtual unsigned long Size() const; + + debSourcesIndex(string URI,string Dist,string Section); +}; + +#endif diff --git a/apt-pkg/deb/deblistparser.cc b/apt-pkg/deb/deblistparser.cc index 9da03a7f6..2b3dfaf6e 100644 --- a/apt-pkg/deb/deblistparser.cc +++ b/apt-pkg/deb/deblistparser.cc @@ -1,6 +1,6 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ -// $Id: deblistparser.cc,v 1.23 1999/09/30 06:30:34 jgg Exp $ +// $Id: deblistparser.cc,v 1.24 2001/02/20 07:03:17 jgg Exp $ /* ###################################################################### Package Cache Generator - Generator for the cache structure. @@ -19,10 +19,17 @@ #include /*}}}*/ +static debListParser::WordList PrioList[] = {{"important",pkgCache::State::Important}, + {"required",pkgCache::State::Required}, + {"standard",pkgCache::State::Standard}, + {"optional",pkgCache::State::Optional}, + {"extra",pkgCache::State::Extra}, + {}}; + // ListParser::debListParser - Constructor /*{{{*/ // --------------------------------------------------------------------- /* */ -debListParser::debListParser(FileFd &File) : Tags(File) +debListParser::debListParser(FileFd *File) : Tags(File) { Arch = _config->Find("APT::architecture"); } @@ -80,14 +87,8 @@ bool debListParser::NewVersion(pkgCache::VerIterator Ver) const char *Start; const char *Stop; if (Section.Find("Priority",Start,Stop) == true) - { - WordList PrioList[] = {{"important",pkgCache::State::Important}, - {"required",pkgCache::State::Required}, - {"standard",pkgCache::State::Standard}, - {"optional",pkgCache::State::Optional}, - {"extra",pkgCache::State::Extra}}; - if (GrabWord(string(Start,Stop-Start),PrioList, - _count(PrioList),Ver->Priority) == false) + { + if (GrabWord(string(Start,Stop-Start),PrioList,Ver->Priority) == false) Ver->Priority = pkgCache::State::Extra; } @@ -104,6 +105,10 @@ bool debListParser::NewVersion(pkgCache::VerIterator Ver) if (ParseDepends(Ver,"Replaces",pkgCache::Dep::Replaces) == false) return false; + // Obsolete. + if (ParseDepends(Ver,"Optional",pkgCache::Dep::Suggests) == false) + return false; + if (ParseProvides(Ver) == false) return false; @@ -205,9 +210,9 @@ bool debListParser::ParseStatus(pkgCache::PkgIterator Pkg, {"install",pkgCache::State::Install}, {"hold",pkgCache::State::Hold}, {"deinstall",pkgCache::State::DeInstall}, - {"purge",pkgCache::State::Purge}}; - if (GrabWord(string(Start,I-Start),WantList, - _count(WantList),Pkg->SelectedState) == false) + {"purge",pkgCache::State::Purge}, + {}}; + if (GrabWord(string(Start,I-Start),WantList,Pkg->SelectedState) == false) return _error->Error("Malformed 1st word in the Status line"); // Isloate the next word @@ -221,9 +226,9 @@ bool debListParser::ParseStatus(pkgCache::PkgIterator Pkg, WordList FlagList[] = {{"ok",pkgCache::State::Ok}, {"reinstreq",pkgCache::State::ReInstReq}, {"hold",pkgCache::State::HoldInst}, - {"hold-reinstreq",pkgCache::State::HoldReInstReq}}; - if (GrabWord(string(Start,I-Start),FlagList, - _count(FlagList),Pkg->InstState) == false) + {"hold-reinstreq",pkgCache::State::HoldReInstReq}, + {}}; + if (GrabWord(string(Start,I-Start),FlagList,Pkg->InstState) == false) return _error->Error("Malformed 2nd word in the Status line"); // Isloate the last word @@ -241,9 +246,9 @@ bool debListParser::ParseStatus(pkgCache::PkgIterator Pkg, {"half-installed",pkgCache::State::HalfInstalled}, {"config-files",pkgCache::State::ConfigFiles}, {"post-inst-failed",pkgCache::State::HalfConfigured}, - {"removal-failed",pkgCache::State::HalfInstalled}}; - if (GrabWord(string(Start,I-Start),StatusList, - _count(StatusList),Pkg->CurrentState) == false) + {"removal-failed",pkgCache::State::HalfInstalled}, + {}}; + if (GrabWord(string(Start,I-Start),StatusList,Pkg->CurrentState) == false) return _error->Error("Malformed 3rd word in the Status line"); /* A Status line marks the package as indicating the current @@ -266,9 +271,67 @@ bool debListParser::ParseStatus(pkgCache::PkgIterator Pkg, // --------------------------------------------------------------------- /* This parses the dependency elements out of a standard string in place, bit by bit. */ +const char *debListParser::ConvertRelation(const char *I,unsigned int &Op) +{ + // Determine the operator + switch (*I) + { + case '<': + I++; + if (*I == '=') + { + I++; + Op = pkgCache::Dep::LessEq; + break; + } + + if (*I == '<') + { + I++; + Op = pkgCache::Dep::Less; + break; + } + + // < is the same as <= and << is really Cs < for some reason + Op = pkgCache::Dep::LessEq; + break; + + case '>': + I++; + if (*I == '=') + { + I++; + Op = pkgCache::Dep::GreaterEq; + break; + } + + if (*I == '>') + { + I++; + Op = pkgCache::Dep::Greater; + break; + } + + // > is the same as >= and >> is really Cs > for some reason + Op = pkgCache::Dep::GreaterEq; + break; + + case '=': + Op = pkgCache::Dep::Equals; + I++; + break; + + // HACK around bad package definitions + default: + Op = pkgCache::Dep::Equals; + break; + } + return I; +} + const char *debListParser::ParseDepends(const char *Start,const char *Stop, string &Package,string &Ver, - unsigned int &Op) + unsigned int &Op, bool ParseArchFlags) { // Strip off leading space for (;Start != Stop && isspace(*Start) != 0; Start++); @@ -298,60 +361,7 @@ const char *debListParser::ParseDepends(const char *Start,const char *Stop, for (I++; I != Stop && isspace(*I) != 0 ; I++); if (I + 3 >= Stop) return 0; - - // Determine the operator - switch (*I) - { - case '<': - I++; - if (*I == '=') - { - I++; - Op = pkgCache::Dep::LessEq; - break; - } - - if (*I == '<') - { - I++; - Op = pkgCache::Dep::Less; - break; - } - - // < is the same as <= and << is really Cs < for some reason - Op = pkgCache::Dep::LessEq; - break; - - case '>': - I++; - if (*I == '=') - { - I++; - Op = pkgCache::Dep::GreaterEq; - break; - } - - if (*I == '>') - { - I++; - Op = pkgCache::Dep::Greater; - break; - } - - // > is the same as >= and >> is really Cs > for some reason - Op = pkgCache::Dep::GreaterEq; - break; - - case '=': - Op = pkgCache::Dep::Equals; - I++; - break; - - // HACK around bad package definitions - default: - Op = pkgCache::Dep::Equals; - break; - } + I = ConvertRelation(I,Op); // Skip whitespace for (;I != Stop && isspace(*I) != 0; I++); @@ -375,6 +385,50 @@ const char *debListParser::ParseDepends(const char *Start,const char *Stop, // Skip whitespace for (;I != Stop && isspace(*I) != 0; I++); + + if (ParseArchFlags == true) + { + string arch = _config->Find("APT::Architecture"); + + // Parse an architecture + if (I != Stop && *I == '[') + { + // malformed + I++; + if (I == Stop) + return 0; + + const char *End = I; + bool Found = false; + while (I != Stop) + { + // look for whitespace or ending ']' + while (End != Stop && !isspace(*End) && *End != ']') + End++; + + if (End == Stop) + return 0; + + if (stringcmp(I,End,arch.begin(),arch.end()) == 0) + Found = true; + + if (*End++ == ']') { + I = End; + break; + } + + I = End; + for (;I != Stop && isspace(*I) != 0; I++); + } + + if (Found == false) + Package = ""; /* not for this arch */ + } + + // Skip whitespace + for (;I != Stop && isspace(*I) != 0; I++); + } + if (I != Stop && *I == '|') Op |= pkgCache::Dep::Or; @@ -453,10 +507,9 @@ bool debListParser::ParseProvides(pkgCache::VerIterator Ver) // ListParser::GrabWord - Matches a word and returns /*{{{*/ // --------------------------------------------------------------------- /* Looks for a word in a list of words - for ParseStatus */ -bool debListParser::GrabWord(string Word,WordList *List,int Count, - unsigned char &Out) +bool debListParser::GrabWord(string Word,WordList *List,unsigned char &Out) { - for (int C = 0; C != Count; C++) + for (unsigned int C = 0; List[C].Str != 0; C++) { if (strcasecmp(Word.c_str(),List[C].Str) == 0) { @@ -500,7 +553,7 @@ bool debListParser::Step() bool debListParser::LoadReleaseInfo(pkgCache::PkgFileIterator FileI, FileFd &File) { - pkgTagFile Tags(File); + pkgTagFile Tags(&File); pkgTagSection Section; if (Tags.Step(Section) == false) return false; @@ -527,3 +580,15 @@ bool debListParser::LoadReleaseInfo(pkgCache::PkgFileIterator FileI, return !_error->PendingError(); } /*}}}*/ +// ListParser::GetPrio - Convert the priority from a string /*{{{*/ +// --------------------------------------------------------------------- +/* */ +unsigned char debListParser::GetPrio(string Str) +{ + unsigned char Out; + if (GrabWord(Str,PrioList,Out) == false) + Out = pkgCache::State::Extra; + + return Out; +} + /*}}}*/ diff --git a/apt-pkg/deb/deblistparser.h b/apt-pkg/deb/deblistparser.h index 6e2c5ef94..9f305211a 100644 --- a/apt-pkg/deb/deblistparser.h +++ b/apt-pkg/deb/deblistparser.h @@ -1,6 +1,6 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ -// $Id: deblistparser.h,v 1.8 1999/07/26 17:46:08 jgg Exp $ +// $Id: deblistparser.h,v 1.9 2001/02/20 07:03:17 jgg Exp $ /* ###################################################################### Debian Package List Parser - This implements the abstract parser @@ -8,7 +8,6 @@ ##################################################################### */ /*}}}*/ -// Header section: pkglib #ifndef PKGLIB_DEBLISTPARSER_H #define PKGLIB_DEBLISTPARSER_H @@ -17,29 +16,33 @@ class debListParser : public pkgCacheGenerator::ListParser { - pkgTagFile Tags; - pkgTagSection Section; - unsigned long iOffset; - string Arch; - + public: + // Parser Helper struct WordList { - char *Str; + const char *Str; unsigned char Val; }; + private: + + pkgTagFile Tags; + pkgTagSection Section; + unsigned long iOffset; + string Arch; + unsigned long UniqFindTagWrite(const char *Tag); bool ParseStatus(pkgCache::PkgIterator Pkg,pkgCache::VerIterator Ver); - const char *ParseDepends(const char *Start,const char *Stop, - string &Package,string &Ver,unsigned int &Op); bool ParseDepends(pkgCache::VerIterator Ver,const char *Tag, unsigned int Type); bool ParseProvides(pkgCache::VerIterator Ver); - bool GrabWord(string Word,WordList *List,int Count,unsigned char &Out); + static bool GrabWord(string Word,WordList *List,unsigned char &Out); public: - + + static unsigned char GetPrio(string Str); + // These all operate against the current section virtual string Package(); virtual string Version(); @@ -51,10 +54,15 @@ class debListParser : public pkgCacheGenerator::ListParser virtual unsigned long Size() {return Section.size();}; virtual bool Step(); - + bool LoadReleaseInfo(pkgCache::PkgFileIterator FileI,FileFd &File); - debListParser(FileFd &File); + static const char *ParseDepends(const char *Start,const char *Stop, + string &Package,string &Ver,unsigned int &Op, + bool ParseArchFlags = false); + static const char *ConvertRelation(const char *I,unsigned int &Op); + + debListParser(FileFd *File); }; #endif diff --git a/apt-pkg/deb/debrecords.cc b/apt-pkg/deb/debrecords.cc index 49e3d02c8..0196992c6 100644 --- a/apt-pkg/deb/debrecords.cc +++ b/apt-pkg/deb/debrecords.cc @@ -1,6 +1,6 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ -// $Id: debrecords.cc,v 1.8 1999/05/18 05:28:03 jgg Exp $ +// $Id: debrecords.cc,v 1.9 2001/02/20 07:03:17 jgg Exp $ /* ###################################################################### Debian Package Records - Parser for debian package records @@ -18,8 +18,9 @@ // RecordParser::debRecordParser - Constructor /*{{{*/ // --------------------------------------------------------------------- /* */ -debRecordParser::debRecordParser(FileFd &File,pkgCache &Cache) : - Tags(File,Cache.Head().MaxVerFileSize + 20) +debRecordParser::debRecordParser(string FileName,pkgCache &Cache) : + File(FileName,FileFd::ReadOnly), + Tags(&File,Cache.Head().MaxVerFileSize + 200) { } /*}}}*/ @@ -39,6 +40,14 @@ string debRecordParser::FileName() return Section.FindS("Filename"); } /*}}}*/ +// RecordParser::Name - Return the package name /*{{{*/ +// --------------------------------------------------------------------- +/* */ +string debRecordParser::Name() +{ + return Section.FindS("Package"); +} + /*}}}*/ // RecordParser::MD5Hash - Return the archive hash /*{{{*/ // --------------------------------------------------------------------- /* */ @@ -87,3 +96,11 @@ string debRecordParser::SourcePkg() return string(Res,0,Pos); } /*}}}*/ +// RecordParser::GetRec - Return the whole record /*{{{*/ +// --------------------------------------------------------------------- +/* */ +void debRecordParser::GetRec(const char *&Start,const char *&Stop) +{ + Section.GetSection(Start,Stop); +} + /*}}}*/ diff --git a/apt-pkg/deb/debrecords.h b/apt-pkg/deb/debrecords.h index 9191ebcda..fd1c380dc 100644 --- a/apt-pkg/deb/debrecords.h +++ b/apt-pkg/deb/debrecords.h @@ -1,6 +1,6 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ -// $Id: debrecords.h,v 1.6 1999/04/07 05:30:18 jgg Exp $ +// $Id: debrecords.h,v 1.7 2001/02/20 07:03:17 jgg Exp $ /* ###################################################################### Debian Package Records - Parser for debian package records @@ -11,7 +11,6 @@ ##################################################################### */ /*}}}*/ -// Header section: pkglib #ifndef PKGLIB_DEBRECORDS_H #define PKGLIB_DEBRECORDS_H @@ -24,9 +23,10 @@ class debRecordParser : public pkgRecords::Parser { + FileFd File; pkgTagFile Tags; pkgTagSection Section; - + protected: virtual bool Jump(pkgCache::VerFileIterator const &Ver); @@ -42,9 +42,11 @@ class debRecordParser : public pkgRecords::Parser virtual string Maintainer(); virtual string ShortDesc(); virtual string LongDesc(); + virtual string Name(); + + virtual void GetRec(const char *&Start,const char *&Stop); - debRecordParser(FileFd &File,pkgCache &Cache); + debRecordParser(string FileName,pkgCache &Cache); }; - #endif diff --git a/apt-pkg/deb/debsrcrecords.cc b/apt-pkg/deb/debsrcrecords.cc index 7a06e30b9..d452095cd 100644 --- a/apt-pkg/deb/debsrcrecords.cc +++ b/apt-pkg/deb/debsrcrecords.cc @@ -1,6 +1,6 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ -// $Id: debsrcrecords.cc,v 1.3 1999/04/07 05:30:18 jgg Exp $ +// $Id: debsrcrecords.cc,v 1.4 2001/02/20 07:03:17 jgg Exp $ /* ###################################################################### Debian Source Package Records - Parser implementation for Debian style @@ -13,9 +13,11 @@ #pragma implementation "apt-pkg/debsrcrecords.h" #endif +#include #include #include #include +#include /*}}}*/ // SrcRecordParser::Binaries - Return the binaries field /*{{{*/ @@ -23,43 +25,63 @@ /* This member parses the binaries field into a pair of class arrays and returns a list of strings representing all of the components of the binaries field. The returned array need not be freed and will be - reused by the next Binaries function call. */ + reused by the next Binaries function call. This function is commonly + used during scanning to find the right package */ const char **debSrcRecordParser::Binaries() { + // This should use Start/Stop too, it is supposed to be efficient after all. string Bins = Sect.FindS("Binary"); - char *Buf = Buffer; - unsigned int Bin = 0; - if (Bins.empty() == true) + if (Bins.empty() == true || Bins.length() >= sizeof(Buffer)) return 0; - // Strip any leading spaces - string::const_iterator Start = Bins.begin(); - for (; Start != Bins.end() && isspace(*Start) != 0; Start++); + strcpy(Buffer,Bins.c_str()); + if (TokSplitString(',',Buffer,StaticBinList, + sizeof(StaticBinList)/sizeof(StaticBinList[0])) == false) + return 0; + return (const char **)StaticBinList; +} + /*}}}*/ +// SrcRecordParser::BuildDepends - Return the Build-Depends information /*{{{*/ +// --------------------------------------------------------------------- +/* This member parses the build-depends information and returns a list of + package/version records representing the build dependency. The returned + array need not be freed and will be reused by the next call to this + function */ +bool debSrcRecordParser::BuildDepends(vector &BuildDeps) +{ + unsigned int I; + const char *Start, *Stop; + BuildDepRec rec; + const char *fields[] = {"Build-Depends", + "Build-Depends-Indep", + "Build-Conflicts", + "Build-Conflicts-Indep"}; + + BuildDeps.clear(); - string::const_iterator Pos = Start; - while (Pos != Bins.end()) + for (I = 0; I < 4; I++) { - // Skip to the next ',' - for (; Pos != Bins.end() && *Pos != ','; Pos++); + if (Sect.Find(fields[I], Start, Stop) == false) + continue; - // Back remove spaces - string::const_iterator End = Pos; - for (; End > Start && (End[-1] == ',' || isspace(End[-1]) != 0); End--); - - // Stash the string - memcpy(Buf,Start,End-Start); - StaticBinList[Bin] = Buf; - Bin++; - Buf += End-Start; - *Buf++ = 0; - - // Advance pos - for (; Pos != Bins.end() && (*Pos == ',' || isspace(*Pos) != 0); Pos++); - Start = Pos; + while (1) + { + Start = debListParser::ParseDepends(Start, Stop, + rec.Package,rec.Version,rec.Op,true); + + if (Start == 0) + return _error->Error("Problem parsing dependency: %s", fields[I]); + rec.Type = I; + + if (rec.Package != "") + BuildDeps.push_back(rec); + + if (Start == Stop) + break; + } } - StaticBinList[Bin] = 0; - return StaticBinList; + return true; } /*}}}*/ // SrcRecordParser::Files - Return a list of files for this source /*{{{*/ @@ -95,6 +117,25 @@ bool debSrcRecordParser::Files(vector &List) // Parse the size and append the directory F.Size = atoi(Size.c_str()); F.Path = Base + F.Path; + + // Try to guess what sort of file it is we are getting. + string::size_type Pos = F.Path.length()-1; + while (1) + { + string::size_type Tmp = F.Path.rfind('.',Pos); + if (Tmp == string::npos) + break; + F.Type = string(F.Path,Tmp+1,Pos-Tmp); + + if (F.Type == "gz" || F.Type == "bz2") + { + Pos = Tmp-1; + continue; + } + + break; + } + List.push_back(F); } diff --git a/apt-pkg/deb/debsrcrecords.h b/apt-pkg/deb/debsrcrecords.h index 50488d4b6..477fe4fe3 100644 --- a/apt-pkg/deb/debsrcrecords.h +++ b/apt-pkg/deb/debsrcrecords.h @@ -1,6 +1,6 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ -// $Id: debsrcrecords.h,v 1.5 1999/10/18 04:15:25 jgg Exp $ +// $Id: debsrcrecords.h,v 1.6 2001/02/20 07:03:17 jgg Exp $ /* ###################################################################### Debian Source Package Records - Parser implementation for Debian style @@ -17,13 +17,15 @@ #include #include +#include class debSrcRecordParser : public pkgSrcRecords::Parser { + FileFd Fd; pkgTagFile Tags; pkgTagSection Sect; char Buffer[10000]; - const char *StaticBinList[400]; + char *StaticBinList[400]; unsigned long iOffset; public: @@ -32,11 +34,12 @@ class debSrcRecordParser : public pkgSrcRecords::Parser virtual bool Step() {iOffset = Tags.Offset(); return Tags.Step(Sect);}; virtual bool Jump(unsigned long Off) {iOffset = Off; return Tags.Jump(Sect,Off);}; - virtual string Package() {return Sect.FindS("Package");}; - virtual string Version() {return Sect.FindS("Version");}; - virtual string Maintainer() {return Sect.FindS("Maintainer");}; - virtual string Section() {return Sect.FindS("Section");}; + virtual string Package() const {return Sect.FindS("Package");}; + virtual string Version() const {return Sect.FindS("Version");}; + virtual string Maintainer() const {return Sect.FindS("Maintainer");}; + virtual string Section() const {return Sect.FindS("Section");}; virtual const char **Binaries(); + virtual bool BuildDepends(vector &BuildDeps); virtual unsigned long Offset() {return iOffset;}; virtual string AsStr() { @@ -45,10 +48,11 @@ class debSrcRecordParser : public pkgSrcRecords::Parser return string(Start,Stop); }; virtual bool Files(vector &F); - - debSrcRecordParser(FileFd *File,pkgSourceList::const_iterator SrcItem) : - Parser(File,SrcItem), - Tags(*File,sizeof(Buffer)) {}; + + debSrcRecordParser(string File,pkgIndexFile const *Index) : + Parser(Index), + Fd(File,FileFd::ReadOnly), + Tags(&Fd,sizeof(Buffer)) {}; }; #endif diff --git a/apt-pkg/deb/debsystem.cc b/apt-pkg/deb/debsystem.cc new file mode 100644 index 000000000..0abd4c8aa --- /dev/null +++ b/apt-pkg/deb/debsystem.cc @@ -0,0 +1,197 @@ +// -*- mode: cpp; mode: fold -*- +// Description /*{{{*/ +// $Id: debsystem.cc,v 1.2 2001/02/20 07:03:17 jgg Exp $ +/* ###################################################################### + + System - Abstraction for running on different systems. + + Basic general structure.. + + ##################################################################### */ + /*}}}*/ +// Include Files /*{{{*/ +#ifdef __GNUG__ +#pragma implementation "apt-pkg/debsystem.h" +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + /*}}}*/ + +debSystem debSys; + +// System::debSystem - Constructor /*{{{*/ +// --------------------------------------------------------------------- +/* */ +debSystem::debSystem() +{ + LockFD = -1; + LockCount = 0; + + Label = "Debian dpkg interface"; + VS = &debVS; +} + /*}}}*/ +// System::Lock - Get the lock /*{{{*/ +// --------------------------------------------------------------------- +/* This mirrors the operations dpkg does when it starts up. Note the + checking of the updates directory. */ +bool debSystem::Lock() +{ + // Disable file locking + if (_config->FindB("Debug::NoLocking",false) == true || LockCount > 1) + { + LockCount++; + return true; + } + + // Create the lockfile + string AdminDir = flNotFile(_config->Find("Dir::State::status")); + LockFD = GetLock(AdminDir + "lock"); + if (LockFD == -1) + { + if (errno == EACCES || errno == EAGAIN) + return _error->Error("Unable to lock the administration directory (%s), " + "is another process using it?",AdminDir.c_str()); + else + return _error->Error("Unable to lock the administration directory (%s), " + "are you root?",AdminDir.c_str()); + } + + // See if we need to abort with a dirty journal + if (CheckUpdates() == true) + { + close(LockFD); + LockFD = -1; + return _error->Error("dpkg was interrupted, you must manually " + "run 'dpkg --configure -a' to correct the problem. "); + } + + LockCount++; + + return true; +} + /*}}}*/ +// System::UnLock - Drop a lock /*{{{*/ +// --------------------------------------------------------------------- +/* */ +bool debSystem::UnLock(bool NoErrors) +{ + if (LockCount == 0 && NoErrors == true) + return false; + + if (LockCount < 1) + return _error->Error("Not locked"); + if (--LockCount == 0) + { + close(LockFD); + LockCount = 0; + } + + return true; +} + /*}}}*/ +// System::CheckUpdates - Check if the updates dir is dirty /*{{{*/ +// --------------------------------------------------------------------- +/* This does a check of the updates directory (dpkg journal) to see if it has + any entries in it. */ +bool debSystem::CheckUpdates() +{ + // Check for updates.. (dirty) + string File = flNotFile(_config->Find("Dir::State::status")) + "updates/"; + DIR *DirP = opendir(File.c_str()); + if (DirP == 0) + return false; + + /* We ignore any files that are not all digits, this skips .,.. and + some tmp files dpkg will leave behind.. */ + bool Damaged = false; + for (struct dirent *Ent = readdir(DirP); Ent != 0; Ent = readdir(DirP)) + { + Damaged = true; + for (unsigned int I = 0; Ent->d_name[I] != 0; I++) + { + // Check if its not a digit.. + if (isdigit(Ent->d_name[I]) == 0) + { + Damaged = false; + break; + } + } + if (Damaged == true) + break; + } + closedir(DirP); + + return Damaged; +} + /*}}}*/ +// System::CreatePM - Create the underlying package manager /*{{{*/ +// --------------------------------------------------------------------- +/* */ +pkgPackageManager *debSystem::CreatePM(pkgDepCache *Cache) const +{ + return new pkgDPkgPM(Cache); +} + /*}}}*/ +// System::Initialize - Setup the configuration space.. /*{{{*/ +// --------------------------------------------------------------------- +/* These are the Debian specific configuration variables.. */ +bool debSystem::Initialize(Configuration &Cnf) +{ + /* These really should be jammed into a generic 'Local Database' engine + which is yet to be determined. The functions in pkgcachegen should + be the only users of these */ + Cnf.CndSet("Dir::State::userstatus","status.user"); // Defunct + Cnf.CndSet("Dir::State::status","/var/lib/dpkg/status"); + Cnf.CndSet("Dir::Bin::dpkg","/usr/bin/dpkg"); + + return true; +} + /*}}}*/ +// System::ArchiveSupported - Is a file format supported /*{{{*/ +// --------------------------------------------------------------------- +/* The standard name for a deb is 'deb'.. There are no seperate versions + of .deb to worry about.. */ +bool debSystem::ArchiveSupported(const char *Type) +{ + if (strcmp(Type,"deb") == 0) + return true; + return false; +} + /*}}}*/ +// System::Score - Determine how 'Debiany' this sys is.. /*{{{*/ +// --------------------------------------------------------------------- +/* We check some files that are sure tell signs of this being a Debian + System.. */ +signed debSystem::Score(Configuration const &Cnf) +{ + signed Score = 0; + if (FileExists(Cnf.FindFile("Dir::State::status","/var/lib/dpkg/status")) == true) + Score += 10; + if (FileExists(Cnf.FindFile("Dir::Bin::dpkg","/usr/bin/dpkg")) == true) + Score += 10; + if (FileExists("/etc/debian_version") == true) + Score += 10; + return Score; +} + /*}}}*/ +// System::AddStatusFiles - Register the status files /*{{{*/ +// --------------------------------------------------------------------- +/* */ +bool debSystem::AddStatusFiles(vector &List) +{ + List.push_back(new debStatusIndex(_config->FindFile("Dir::State::status"))); + return true; +} + /*}}}*/ diff --git a/apt-pkg/deb/debsystem.h b/apt-pkg/deb/debsystem.h new file mode 100644 index 000000000..4fd267f77 --- /dev/null +++ b/apt-pkg/deb/debsystem.h @@ -0,0 +1,41 @@ +// -*- mode: cpp; mode: fold -*- +// Description /*{{{*/ +// $Id: debsystem.h,v 1.2 2001/02/20 07:03:17 jgg Exp $ +/* ###################################################################### + + System - Debian version of the System Class + + ##################################################################### */ + /*}}}*/ +#ifndef PKGLIB_DEBSYSTEM_H +#define PKGLIB_DEBSYSTEM_H + +#ifdef __GNUG__ +#pragma interface "apt-pkg/debsystem.h" +#endif + +#include + +class debSystem : public pkgSystem +{ + // For locking support + int LockFD; + unsigned LockCount; + bool CheckUpdates(); + + public: + + virtual bool Lock(); + virtual bool UnLock(bool NoErrors = false); + virtual pkgPackageManager *CreatePM(pkgDepCache *Cache) const; + virtual bool Initialize(Configuration &Cnf); + virtual bool ArchiveSupported(const char *Type); + virtual signed Score(Configuration const &Cnf); + virtual bool AddStatusFiles(vector &List); + + debSystem(); +}; + +extern debSystem debSys; + +#endif diff --git a/apt-pkg/deb/debversion.cc b/apt-pkg/deb/debversion.cc new file mode 100644 index 000000000..e7c42fd11 --- /dev/null +++ b/apt-pkg/deb/debversion.cc @@ -0,0 +1,266 @@ +// -*- mode: cpp; mode: fold -*- +// Description /*{{{*/ +// $Id: debversion.cc,v 1.2 2001/02/20 07:03:17 jgg Exp $ +/* ###################################################################### + + Debian Version - Versioning system for Debian + + This implements the standard Debian versioning system. + + ##################################################################### */ + /*}}}*/ +// Include Files /*{{{*/ +#define APT_COMPATIBILITY 986 +#ifdef __GNUG__ +#pragma implementation "apt-pkg/debversion.h" +#endif + +#include +#include + +#include + /*}}}*/ + +debVersioningSystem debVS; + +// debVS::debVersioningSystem - Constructor /*{{{*/ +// --------------------------------------------------------------------- +/* */ +debVersioningSystem::debVersioningSystem() +{ + Label = "Standard .deb"; +} + /*}}}*/ +// StrToLong - Convert the string between two iterators to a long /*{{{*/ +// --------------------------------------------------------------------- +/* */ +static unsigned long StrToLong(const char *begin,const char *end) +{ + char S[40]; + char *I = S; + for (; begin != end && I < S + 40;) + *I++ = *begin++; + *I = 0; + return strtoul(S,0,10); +} + /*}}}*/ +// debVS::CmpFragment - Compare versions /*{{{*/ +// --------------------------------------------------------------------- +/* This compares a fragment of the version. Dpkg has a really short + version of this, but it is uh.. interesting to grok. */ +int debVersioningSystem::CmpFragment(const char *A,const char *AEnd, + const char *B,const char *BEnd) +{ + if (A >= AEnd && B >= BEnd) + return 0; + if (A >= AEnd) + return -1; + if (B >= BEnd) + return 1; + + /* Iterate over the whole string + What this does is to spilt the whole string into groups of + numeric and non numeric portions. For instance: + a67bhgs89 + Has 4 portions 'a', '67', 'bhgs', '89'. A more normal: + 2.7.2-linux-1 + Has '2', '.', '7', '.' ,'-linux-','1' */ + const char *lhs = A; + const char *rhs = B; + while (lhs != AEnd && rhs != BEnd) + { + // Starting points + const char *Slhs = lhs; + const char *Srhs = rhs; + + // Compute ending points were we have passed over the portion + bool Digit = (isdigit(*lhs) > 0?true:false); + for (;lhs != AEnd && (isdigit(*lhs) > 0?true:false) == Digit; lhs++); + for (;rhs != BEnd && (isdigit(*rhs) > 0?true:false) == Digit; rhs++); + + if (Digit == true) + { + // If the lhs has a digit and the rhs does not then < + if (rhs - Srhs == 0) + return -1; + + // Generate integers from the strings. + unsigned long Ilhs = StrToLong(Slhs,lhs); + unsigned long Irhs = StrToLong(Srhs,rhs); + if (Ilhs != Irhs) + { + if (Ilhs > Irhs) + return 1; + return -1; + } + } + else + { + // They are equal length so do a straight text compare + for (;Slhs != lhs && Srhs != rhs; Slhs++, Srhs++) + { + if (*Slhs != *Srhs) + { + /* We need to compare non alpha chars as higher than alpha + chars (a < !) */ + int lc = *Slhs; + int rc = *Srhs; + if (isalpha(lc) == 0) lc += 256; + if (isalpha(rc) == 0) rc += 256; + if (lc > rc) + return 1; + return -1; + } + } + + // If the lhs is shorter than the right it is 'less' + if (lhs - Slhs < rhs - Srhs) + return -1; + + // If the lhs is longer than the right it is 'more' + if (lhs - Slhs > rhs - Srhs) + return 1; + } + } + + // The strings must be equal + if (lhs == AEnd && rhs == BEnd) + return 0; + + // lhs is shorter + if (lhs == AEnd) + return -1; + + // rhs is shorter + if (rhs == BEnd) + return 1; + + // Shouldnt happen + return 1; +} + /*}}}*/ +// debVS::CmpVersion - Comparison for versions /*{{{*/ +// --------------------------------------------------------------------- +/* This fragments the version into E:V-R triples and compares each + portion separately. */ +int debVersioningSystem::DoCmpVersion(const char *A,const char *AEnd, + const char *B,const char *BEnd) +{ + // Strip off the epoch and compare it + const char *lhs = A; + const char *rhs = B; + for (;lhs != AEnd && *lhs != ':'; lhs++); + for (;rhs != BEnd && *rhs != ':'; rhs++); + if (lhs == AEnd) + lhs = A; + if (rhs == BEnd) + rhs = B; + + // Compare the epoch + int Res = CmpFragment(A,lhs,B,rhs); + if (Res != 0) + return Res; + + // Skip the : + if (lhs != A) + lhs++; + if (rhs != B) + rhs++; + + // Find the last - + const char *dlhs = AEnd-1; + const char *drhs = BEnd-1; + for (;dlhs > lhs && *dlhs != '-'; dlhs--); + for (;drhs > rhs && *drhs != '-'; drhs--); + + if (dlhs == lhs) + dlhs = AEnd; + if (drhs == rhs) + drhs = BEnd; + + // Compare the main version + Res = CmpFragment(lhs,dlhs,rhs,drhs); + if (Res != 0) + return Res; + + // Skip the - + if (dlhs != lhs) + dlhs++; + if (drhs != rhs) + drhs++; + + return CmpFragment(dlhs,AEnd,drhs,BEnd); +} + /*}}}*/ +// debVS::CheckDep - Check a single dependency /*{{{*/ +// --------------------------------------------------------------------- +/* This simply preforms the version comparison and switch based on + operator. If DepVer is 0 then we are comparing against a provides + with no version. */ +bool debVersioningSystem::CheckDep(const char *PkgVer, + int Op,const char *DepVer) +{ + if (DepVer == 0 || DepVer[0] == 0) + return true; + if (PkgVer == 0 || PkgVer[0] == 0) + return false; + + // Perform the actual comparision. + int Res = CmpVersion(PkgVer,DepVer); + switch (Op & 0x0F) + { + case pkgCache::Dep::LessEq: + if (Res <= 0) + return true; + break; + + case pkgCache::Dep::GreaterEq: + if (Res >= 0) + return true; + break; + + case pkgCache::Dep::Less: + if (Res < 0) + return true; + break; + + case pkgCache::Dep::Greater: + if (Res > 0) + return true; + break; + + case pkgCache::Dep::Equals: + if (Res == 0) + return true; + break; + + case pkgCache::Dep::NotEquals: + if (Res != 0) + return true; + break; + } + + return false; +} + /*}}}*/ +// debVS::UpstreamVersion - Return the upstream version string /*{{{*/ +// --------------------------------------------------------------------- +/* This strips all the debian specific information from the version number */ +string debVersioningSystem::UpstreamVersion(const char *Ver) +{ + // Strip off the bit before the first colon + const char *I = Ver; + for (; *I != 0 && *I != ':'; I++); + if (*I == ':') + Ver = I + 1; + + // Chop off the trailing - + I = Ver; + unsigned Last = strlen(Ver); + for (; *I != 0; I++) + if (*I == '-') + Last = I - Ver; + + return string(Ver,Last); +} + /*}}}*/ diff --git a/apt-pkg/deb/debversion.h b/apt-pkg/deb/debversion.h new file mode 100644 index 000000000..d313f78a6 --- /dev/null +++ b/apt-pkg/deb/debversion.h @@ -0,0 +1,72 @@ +// -*- mode: cpp; mode: fold -*- +// Description /*{{{*/ +// $Id: debversion.h,v 1.2 2001/02/20 07:03:17 jgg Exp $ +/* ###################################################################### + + Debian Version - Versioning system for Debian + + This implements the standard Debian versioning system. + + ##################################################################### */ + /*}}}*/ +#ifndef PKGLIB_DEBVERSION_H +#define PKGLIB_DEBVERSION_H + +#ifdef __GNUG__ +#pragma interface "apt-pkg/debversion.h" +#endif + +#include + +class debVersioningSystem : public pkgVersioningSystem +{ + static int CmpFragment(const char *A, const char *AEnd, const char *B, + const char *BEnd); + + public: + + // Compare versions.. + virtual int DoCmpVersion(const char *A,const char *Aend, + const char *B,const char *Bend); + virtual bool CheckDep(const char *PkgVer,int Op,const char *DepVer); + virtual int DoCmpReleaseVer(const char *A,const char *Aend, + const char *B,const char *Bend) + { + return DoCmpVersion(A,Aend,B,Bend); + } + virtual string UpstreamVersion(const char *A); + + debVersioningSystem(); +}; + +extern debVersioningSystem debVS; + +#ifdef APT_COMPATIBILITY +#if APT_COMPATIBILITY != 986 +#warning "Using APT_COMPATIBILITY" +#endif + +inline int pkgVersionCompare(const char *A, const char *B) +{ + return debVS.CmpVersion(A,B); +} +inline int pkgVersionCompare(const char *A, const char *AEnd, + const char *B, const char *BEnd) +{ + return debVS.DoCmpVersion(A,AEnd,B,BEnd); +} +inline int pkgVersionCompare(string A,string B) +{ + return debVS.CmpVersion(A,B); +} +inline bool pkgCheckDep(const char *DepVer,const char *PkgVer,int Op) +{ + return debVS.CheckDep(PkgVer,Op,DepVer); +} +inline string pkgBaseVersion(const char *Ver) +{ + return debVS.UpstreamVersion(Ver); +} +#endif + +#endif diff --git a/apt-pkg/deb/dpkginit.cc b/apt-pkg/deb/dpkginit.cc deleted file mode 100644 index 576e1967a..000000000 --- a/apt-pkg/deb/dpkginit.cc +++ /dev/null @@ -1,119 +0,0 @@ -// -*- mode: cpp; mode: fold -*- -// Description /*{{{*/ -// $Id: dpkginit.cc,v 1.5 1999/08/03 05:21:19 jgg Exp $ -/* ###################################################################### - - DPKG init - Initialize the dpkg stuff - - This class provides the locking mechanism used by dpkg for its - database area. It does the proper consistency checks and acquires the - correct kind of lock. - - ##################################################################### */ - /*}}}*/ -// Includes /*{{{*/ -#ifdef __GNUG__ -#pragma implementation "apt-pkg/dpkginit.h" -#endif -#include -#include -#include -#include - -#include -#include -#include - /*}}}*/ - -// DpkgLock::pkgDpkgLock - Constructor /*{{{*/ -// --------------------------------------------------------------------- -/* */ -pkgDpkgLock::pkgDpkgLock(bool WithUpdates) -{ - LockFD = -1; - GetLock(WithUpdates); -} - /*}}}*/ -// DpkgLock::~pkgDpkgLock - Destructor /*{{{*/ -// --------------------------------------------------------------------- -/* */ -pkgDpkgLock::~pkgDpkgLock() -{ - Close(); -} - /*}}}*/ -// DpkgLock::GetLock - Get the lock /*{{{*/ -// --------------------------------------------------------------------- -/* This mirrors the operations dpkg does when it starts up. Note the - checking of the updates directory. */ -bool pkgDpkgLock::GetLock(bool WithUpdates) -{ - // Disable file locking - if (_config->FindB("Debug::NoLocking",false) == true) - return true; - - Close(); - - // Create the lockfile - string AdminDir = flNotFile(_config->Find("Dir::State::status")); - LockFD = ::GetLock(AdminDir + "lock"); - if (LockFD == -1) - return _error->Error("Unable to lock the administration directory, " - "are you root?"); - - // See if we need to abort with a dirty journal - if (WithUpdates == true && CheckUpdates() == true) - { - Close(); - return _error->Error("dpkg was interrupted, you must manually " - "run 'dpkg --configure -a' to correct the problem. "); - } - - return true; -} - /*}}}*/ -// DpkgLock::Close - Close the lock /*{{{*/ -// --------------------------------------------------------------------- -/* */ -void pkgDpkgLock::Close() -{ - close(LockFD); - LockFD = -1; -} - /*}}}*/ -// DpkgLock::CheckUpdates - Check if the updates dir is dirty /*{{{*/ -// --------------------------------------------------------------------- -/* This does a check of the updates directory to see if it has any entries - in it. */ -bool pkgDpkgLock::CheckUpdates() -{ - // Check for updates.. (dirty) - string File = flNotFile(_config->Find("Dir::State::status")) + "updates/"; - DIR *DirP = opendir(File.c_str()); - if (DirP == 0) - return false; - - /* We ignore any files that are not all digits, this skips .,.. and - some tmp files dpkg will leave behind.. */ - bool Damaged = false; - for (struct dirent *Ent = readdir(DirP); Ent != 0; Ent = readdir(DirP)) - { - Damaged = true; - for (unsigned int I = 0; Ent->d_name[I] != 0; I++) - { - // Check if its not a digit.. - if (isdigit(Ent->d_name[I]) == 0) - { - Damaged = false; - break; - } - } - if (Damaged == true) - break; - } - closedir(DirP); - - return Damaged; -} - /*}}}*/ - diff --git a/apt-pkg/deb/dpkginit.h b/apt-pkg/deb/dpkginit.h deleted file mode 100644 index 532ff6236..000000000 --- a/apt-pkg/deb/dpkginit.h +++ /dev/null @@ -1,34 +0,0 @@ -// -*- mode: cpp; mode: fold -*- -// Description /*{{{*/ -// $Id: dpkginit.h,v 1.2 1999/07/26 17:46:08 jgg Exp $ -/* ###################################################################### - - DPKG init - Initialize the dpkg stuff - - This basically gets a lock in /var/lib/dpkg and checks the updates - directory - - ##################################################################### */ - /*}}}*/ -#ifndef PKGLIB_DPKGINIT_H -#define PKGLIB_DPKGINIT_H - -#ifdef __GNUG__ -#pragma interface "apt-pkg/dpkginit.h" -#endif - -class pkgDpkgLock -{ - int LockFD; - - public: - - bool CheckUpdates(); - bool GetLock(bool WithUpdates); - void Close(); - - pkgDpkgLock(bool WithUpdates = true); - ~pkgDpkgLock(); -}; - -#endif diff --git a/apt-pkg/deb/dpkgpm.cc b/apt-pkg/deb/dpkgpm.cc index 09cf20440..34c19ef4b 100644 --- a/apt-pkg/deb/dpkgpm.cc +++ b/apt-pkg/deb/dpkgpm.cc @@ -1,6 +1,6 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ -// $Id: dpkgpm.cc,v 1.17 2000/05/13 01:52:38 jgg Exp $ +// $Id: dpkgpm.cc,v 1.18 2001/02/20 07:03:17 jgg Exp $ /* ###################################################################### DPKG Package Manager - Provide an interface to dpkg @@ -14,7 +14,9 @@ #include #include #include - +#include +#include + #include #include #include @@ -28,7 +30,7 @@ // DPkgPM::pkgDPkgPM - Constructor /*{{{*/ // --------------------------------------------------------------------- /* */ -pkgDPkgPM::pkgDPkgPM(pkgDepCache &Cache) : pkgPackageManager(Cache) +pkgDPkgPM::pkgDPkgPM(pkgDepCache *Cache) : pkgPackageManager(Cache) { } /*}}}*/ @@ -141,6 +143,90 @@ bool pkgDPkgPM::RunScripts(const char *Cnf) } /*}}}*/ +// DPkgPM::SendV2Pkgs - Send version 2 package info /*{{{*/ +// --------------------------------------------------------------------- +/* This is part of the helper script communication interface, it sends + very complete information down to the other end of the pipe.*/ +bool pkgDPkgPM::SendV2Pkgs(FILE *F) +{ + fprintf(F,"VERSION 2\n"); + + /* Write out all of the configuration directives by walking the + configuration tree */ + const Configuration::Item *Top = _config->Tree(0); + for (; Top != 0;) + { + if (Top->Value.empty() == false) + { + fprintf(F,"%s=%s\n", + QuoteString(Top->FullTag(),"=\"\n").c_str(), + QuoteString(Top->Value,"\n").c_str()); + } + + if (Top->Child != 0) + { + Top = Top->Child; + continue; + } + + while (Top != 0 && Top->Next == 0) + Top = Top->Parent; + if (Top != 0) + Top = Top->Next; + } + fprintf(F,"\n"); + + // Write out the package actions in order. + for (vector::iterator I = List.begin(); I != List.end(); I++) + { + pkgDepCache::StateCache &S = Cache[I->Pkg]; + + fprintf(F,"%s ",I->Pkg.Name()); + // Current version + if (I->Pkg->CurrentVer == 0) + fprintf(F,"- "); + else + fprintf(F,"%s ",I->Pkg.CurrentVer().VerStr()); + + // Show the compare operator + // Target version + if (S.InstallVer != 0) + { + int Comp = 2; + if (I->Pkg->CurrentVer != 0) + Comp = S.InstVerIter(Cache).CompareVer(I->Pkg.CurrentVer()); + if (Comp < 0) + fprintf(F,"> "); + if (Comp == 0) + fprintf(F,"= "); + if (Comp > 0) + fprintf(F,"< "); + fprintf(F,"%s ",S.InstVerIter(Cache).VerStr()); + } + else + fprintf(F,"> - "); + + // Show the filename/operation + if (I->Op == Item::Install) + { + // No errors here.. + if (I->File[0] != '/') + fprintf(F,"**ERROR**\n"); + else + fprintf(F,"%s\n",I->File.c_str()); + } + if (I->Op == Item::Configure) + fprintf(F,"**CONFIGURE**\n"); + if (I->Op == Item::Remove || + I->Op == Item::Purge) + fprintf(F,"**REMOVE**\n"); + + if (ferror(F) != 0) + return false; + } + return true; +} + /*}}}*/ // DPkgPM::RunScriptsWithPkgs - Run scripts with package names on stdin /*{{{*/ // --------------------------------------------------------------------- /* This looks for a list of scripts to run from the configuration file @@ -158,7 +244,18 @@ bool pkgDPkgPM::RunScriptsWithPkgs(const char *Cnf) { if (Opts->Value.empty() == true) continue; - + + // Determine the protocol version + string OptSec = Opts->Value; + string::size_type Pos; + if ((Pos = OptSec.find(' ')) == string::npos || Pos == 0) + Pos = OptSec.length(); + else + Pos--; + OptSec = "DPkg::Tools::Options::" + string(Opts->Value.c_str(),Pos); + + unsigned int Version = _config->FindI(OptSec+"::Version",1); + // Create the pipes int Pipes[2]; if (pipe(Pipes) != 0) @@ -185,31 +282,44 @@ bool pkgDPkgPM::RunScriptsWithPkgs(const char *Cnf) _exit(100); } close(Pipes[0]); - FileFd Fd(Pipes[1]); - + FILE *F = fdopen(Pipes[1],"w"); + if (F == 0) + return _error->Errno("fdopen","Faild to open new FD"); + // Feed it the filenames. - for (vector::iterator I = List.begin(); I != List.end(); I++) + bool Die = false; + if (Version <= 1) { - // Only deal with packages to be installed from .deb - if (I->Op != Item::Install) - continue; - - // No errors here.. - if (I->File[0] != '/') - continue; - - /* Feed the filename of each package that is pending install - into the pipe. */ - if (Fd.Write(I->File.begin(),I->File.length()) == false || - Fd.Write("\n",1) == false) + for (vector::iterator I = List.begin(); I != List.end(); I++) { - kill(Process,SIGINT); - Fd.Close(); - ExecWait(Process,Opts->Value.c_str(),true); - return _error->Error("Failure running script %s",Opts->Value.c_str()); + // Only deal with packages to be installed from .deb + if (I->Op != Item::Install) + continue; + + // No errors here.. + if (I->File[0] != '/') + continue; + + /* Feed the filename of each package that is pending install + into the pipe. */ + fprintf(F,"%s\n",I->File.c_str()); + if (ferror(F) != 0) + { + Die = true; + break; + } } } - Fd.Close(); + else + Die = !SendV2Pkgs(F); + + fclose(F); + if (Die == true) + { + kill(Process,SIGINT); + ExecWait(Process,Opts->Value.c_str(),true); + return _error->Error("Failure running script %s",Opts->Value.c_str()); + } // Clean up the sub process if (ExecWait(Process,Opts->Value.c_str()) == false) @@ -384,8 +494,8 @@ bool pkgDPkgPM::Go() { RunScripts("DPkg::Post-Invoke"); if (WIFSIGNALED(Status) != 0 && WTERMSIG(Status) == SIGSEGV) - return _error->Error("Sub-process %s recieved a segmentation fault.",Args[0]); - + return _error->Error("Sub-process %s received a segmentation fault.",Args[0]); + if (WIFEXITED(Status) != 0) return _error->Error("Sub-process %s returned an error code (%u)",Args[0],WEXITSTATUS(Status)); diff --git a/apt-pkg/deb/dpkgpm.h b/apt-pkg/deb/dpkgpm.h index 0cc32f731..761aac76b 100644 --- a/apt-pkg/deb/dpkgpm.h +++ b/apt-pkg/deb/dpkgpm.h @@ -1,6 +1,6 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ -// $Id: dpkgpm.h,v 1.6 1999/07/30 06:15:14 jgg Exp $ +// $Id: dpkgpm.h,v 1.7 2001/02/20 07:03:17 jgg Exp $ /* ###################################################################### DPKG Package Manager - Provide an interface to dpkg @@ -16,6 +16,7 @@ #include #include +#include class pkgDPkgPM : public pkgPackageManager { @@ -26,7 +27,7 @@ class pkgDPkgPM : public pkgPackageManager enum Ops {Install, Configure, Remove, Purge} Op; string File; PkgIterator Pkg; - Item(Ops Op,PkgIterator Pkg,string File = "") : Op(Op), + Item(Ops Op,PkgIterator Pkg,string File = "") : Op(Op), File(File), Pkg(Pkg) {}; Item() {}; @@ -36,6 +37,7 @@ class pkgDPkgPM : public pkgPackageManager // Helpers bool RunScripts(const char *Cnf); bool RunScriptsWithPkgs(const char *Cnf); + bool SendV2Pkgs(FILE *F); // The Actuall installation implementation virtual bool Install(PkgIterator Pkg,string File); @@ -46,7 +48,7 @@ class pkgDPkgPM : public pkgPackageManager public: - pkgDPkgPM(pkgDepCache &Cache); + pkgDPkgPM(pkgDepCache *Cache); virtual ~pkgDPkgPM(); }; diff --git a/apt-pkg/depcache.cc b/apt-pkg/depcache.cc index 1469126d2..d410413d4 100644 --- a/apt-pkg/depcache.cc +++ b/apt-pkg/depcache.cc @@ -1,6 +1,6 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ -// $Id: depcache.cc,v 1.22 2000/05/31 02:49:37 jgg Exp $ +// $Id: depcache.cc,v 1.23 2001/02/20 07:03:17 jgg Exp $ /* ###################################################################### Dependency Cache - Caches Dependency information. @@ -12,25 +12,24 @@ #pragma implementation "apt-pkg/depcache.h" #endif #include - #include #include +#include +#include + +#include /*}}}*/ // DepCache::pkgDepCache - Constructors /*{{{*/ // --------------------------------------------------------------------- /* */ -pkgDepCache::pkgDepCache(MMap &Map,OpProgress &Prog) : - pkgCache(Map), PkgState(0), DepState(0) +pkgDepCache::pkgDepCache(pkgCache *pCache,Policy *Plcy) : + Cache(pCache), PkgState(0), DepState(0) { - if (_error->PendingError() == false) - Init(&Prog); -} -pkgDepCache::pkgDepCache(MMap &Map) : - pkgCache(Map), PkgState(0), DepState(0) -{ - if (_error->PendingError() == false) - Init(0); + delLocalPolicy = 0; + LocalPolicy = Plcy; + if (LocalPolicy == 0) + delLocalPolicy = LocalPolicy = new Policy; } /*}}}*/ // DepCache::~pkgDepCache - Destructor /*{{{*/ @@ -40,6 +39,7 @@ pkgDepCache::~pkgDepCache() { delete [] PkgState; delete [] DepState; + delete delLocalPolicy; } /*}}}*/ // DepCache::Init - Generate the initial extra structures. /*{{{*/ @@ -53,12 +53,12 @@ bool pkgDepCache::Init(OpProgress *Prog) DepState = new unsigned char[Head().DependsCount]; memset(PkgState,0,sizeof(*PkgState)*Head().PackageCount); memset(DepState,0,sizeof(*DepState)*Head().DependsCount); - + if (Prog != 0) { Prog->OverallProgress(0,2*Head().PackageCount,Head().PackageCount, - "Building Dependency Tree"); - Prog->SubProgress(Head().PackageCount,"Candidate Versions"); + _("Building Dependency Tree")); + Prog->SubProgress(Head().PackageCount,_("Candidate Versions")); } /* Set the current state of everything. In this state all of the @@ -86,8 +86,8 @@ bool pkgDepCache::Init(OpProgress *Prog) Prog->OverallProgress(Head().PackageCount,2*Head().PackageCount, Head().PackageCount, - "Building Dependency Tree"); - Prog->SubProgress(Head().PackageCount,"Dependency Generation"); + _("Building Dependency Tree")); + Prog->SubProgress(Head().PackageCount,_("Dependency Generation")); } Update(Prog); @@ -95,29 +95,6 @@ bool pkgDepCache::Init(OpProgress *Prog) return true; } /*}}}*/ -// DepCache::GetCandidateVer - Returns the Candidate install version /*{{{*/ -// --------------------------------------------------------------------- -/* The default just returns the target version if it exists or the - highest version. */ -pkgDepCache::VerIterator pkgDepCache::GetCandidateVer(PkgIterator Pkg, - bool AllowCurrent) -{ - // Try to use an explicit target - if (Pkg->TargetVer == 0 || - (AllowCurrent == false && Pkg.TargetVer() == Pkg.CurrentVer())) - return pkgCache::GetCandidateVer(Pkg,AllowCurrent); - else - return Pkg.TargetVer(); -} - /*}}}*/ -// DepCache::IsImportantDep - True if the dependency is important /*{{{*/ -// --------------------------------------------------------------------- -/* */ -bool pkgDepCache::IsImportantDep(DepIterator Dep) -{ - return Dep.IsCritical(); -} - /*}}}*/ // DepCache::CheckDep - Checks a single dependency /*{{{*/ // --------------------------------------------------------------------- @@ -132,28 +109,30 @@ bool pkgDepCache::CheckDep(DepIterator Dep,int Type,PkgIterator &Res) /* Check simple depends. A depends -should- never self match but we allow it anyhow because dpkg does. Technically it is a packaging bug. Conflicts may never self match */ - if (Dep.TargetPkg() != Dep.ParentPkg() || Dep->Type != Dep::Conflicts) + if (Dep.TargetPkg() != Dep.ParentPkg() || + (Dep->Type != Dep::Conflicts && Dep->Type != Dep::Obsoletes)) { PkgIterator Pkg = Dep.TargetPkg(); // Check the base package if (Type == NowVersion && Pkg->CurrentVer != 0) - if (pkgCheckDep(Dep.TargetVer(), - Pkg.CurrentVer().VerStr(),Dep->CompareOp) == true) + if (VS().CheckDep(Pkg.CurrentVer().VerStr(),Dep->CompareOp, + Dep.TargetVer()) == true) return true; if (Type == InstallVersion && PkgState[Pkg->ID].InstallVer != 0) - if (pkgCheckDep(Dep.TargetVer(), - PkgState[Pkg->ID].InstVerIter(*this).VerStr(), - Dep->CompareOp) == true) + if (VS().CheckDep(PkgState[Pkg->ID].InstVerIter(*this).VerStr(), + Dep->CompareOp,Dep.TargetVer()) == true) return true; if (Type == CandidateVersion && PkgState[Pkg->ID].CandidateVer != 0) - if (pkgCheckDep(Dep.TargetVer(), - PkgState[Pkg->ID].CandidateVerIter(*this).VerStr(), - Dep->CompareOp) == true) + if (VS().CheckDep(PkgState[Pkg->ID].CandidateVerIter(*this).VerStr(), + Dep->CompareOp,Dep.TargetVer()) == true) return true; } + if (Dep->Type == Dep::Obsoletes) + return false; + // Check the providing packages PrvIterator P = Dep.TargetPkg().ProvidesList(); PkgIterator Pkg = Dep.ParentPkg(); @@ -186,7 +165,7 @@ bool pkgDepCache::CheckDep(DepIterator Dep,int Type,PkgIterator &Res) } // Compare the versions. - if (pkgCheckDep(Dep.TargetVer(),P.ProvideVersion(),Dep->CompareOp) == true) + if (VS().CheckDep(P.ProvideVersion(),Dep->CompareOp,Dep.TargetVer()) == true) { Res = P.OwnerPkg(); return true; @@ -199,7 +178,7 @@ bool pkgDepCache::CheckDep(DepIterator Dep,int Type,PkgIterator &Res) // DepCache::AddSizes - Add the packages sizes to the counters /*{{{*/ // --------------------------------------------------------------------- /* Call with Mult = -1 to preform the inverse opration */ -void pkgDepCache::AddSizes(const PkgIterator &Pkg,long Mult) +void pkgDepCache::AddSizes(const PkgIterator &Pkg,signed long Mult) { StateCache &P = PkgState[Pkg->ID]; @@ -210,8 +189,8 @@ void pkgDepCache::AddSizes(const PkgIterator &Pkg,long Mult) // Compute the size data if (P.NewInstall() == true) { - iUsrSize += Mult*P.InstVerIter(*this)->InstalledSize; - iDownloadSize += Mult*P.InstVerIter(*this)->Size; + iUsrSize += (signed)(Mult*P.InstVerIter(*this)->InstalledSize); + iDownloadSize += (signed)(Mult*P.InstVerIter(*this)->Size); return; } @@ -220,9 +199,9 @@ void pkgDepCache::AddSizes(const PkgIterator &Pkg,long Mult) (P.InstallVer != (Version *)Pkg.CurrentVer() || (P.iFlags & ReInstall) == ReInstall) && P.InstallVer != 0) { - iUsrSize += Mult*((signed)P.InstVerIter(*this)->InstalledSize - - (signed)Pkg.CurrentVer()->InstalledSize); - iDownloadSize += Mult*P.InstVerIter(*this)->Size; + iUsrSize += (signed)(Mult*((signed)P.InstVerIter(*this)->InstalledSize - + (signed)Pkg.CurrentVer()->InstalledSize)); + iDownloadSize += (signed)(Mult*P.InstVerIter(*this)->Size); return; } @@ -230,14 +209,14 @@ void pkgDepCache::AddSizes(const PkgIterator &Pkg,long Mult) if (Pkg.State() == pkgCache::PkgIterator::NeedsUnpack && P.Delete() == false) { - iDownloadSize += Mult*P.InstVerIter(*this)->Size; + iDownloadSize += (signed)(Mult*P.InstVerIter(*this)->Size); return; } // Removing if (Pkg->CurrentVer != 0 && P.InstallVer == 0) { - iUsrSize -= Mult*Pkg.CurrentVer()->InstalledSize; + iUsrSize -= (signed)(Mult*Pkg.CurrentVer()->InstalledSize); return; } } @@ -310,7 +289,7 @@ void pkgDepCache::BuildGroupOrs(VerIterator const &V) /* Invert for Conflicts. We have to do this twice to get the right sense for a conflicts group */ - if (D->Type == Dep::Conflicts) + if (D->Type == Dep::Conflicts || D->Type == Dep::Obsoletes) State = ~State; // Add to the group if we are within an or.. @@ -321,7 +300,7 @@ void pkgDepCache::BuildGroupOrs(VerIterator const &V) Group = 0; // Invert for Conflicts - if (D->Type == Dep::Conflicts) + if (D->Type == Dep::Conflicts || D->Type == Dep::Obsoletes) State = ~State; } } @@ -445,7 +424,7 @@ void pkgDepCache::Update(OpProgress *Prog) { // Build the dependency state. unsigned char &State = DepState[D->ID]; - State = DependencyState(D);; + State = DependencyState(D); // Add to the group if we are within an or.. Group |= State; @@ -454,7 +433,7 @@ void pkgDepCache::Update(OpProgress *Prog) Group = 0; // Invert for Conflicts - if (D->Type == Dep::Conflicts) + if (D->Type == Dep::Conflicts || D->Type == Dep::Obsoletes) State = ~State; } } @@ -482,9 +461,9 @@ void pkgDepCache::Update(DepIterator D) State = DependencyState(D); // Invert for Conflicts - if (D->Type == Dep::Conflicts) + if (D->Type == Dep::Conflicts || D->Type == Dep::Obsoletes) State = ~State; - + RemoveStates(D.ParentPkg()); BuildGroupOrs(D.ParentVer()); UpdateVerState(D.ParentPkg()); @@ -497,7 +476,7 @@ void pkgDepCache::Update(DepIterator D) /* This is called whenever the state of a package changes. It updates all cached dependencies related to this package. */ void pkgDepCache::Update(PkgIterator const &Pkg) -{ +{ // Recompute the dep of the package RemoveStates(Pkg); UpdateVerState(Pkg); @@ -610,8 +589,12 @@ void pkgDepCache::MarkDelete(PkgIterator const &Pkg, bool rPurge) // DepCache::MarkInstall - Put the package in the install state /*{{{*/ // --------------------------------------------------------------------- /* */ -void pkgDepCache::MarkInstall(PkgIterator const &Pkg,bool AutoInst) -{ +void pkgDepCache::MarkInstall(PkgIterator const &Pkg,bool AutoInst, + unsigned long Depth) +{ + if (Depth > 100) + return; + // Simplifies other routines. if (Pkg.end() == true) return; @@ -627,6 +610,10 @@ void pkgDepCache::MarkInstall(PkgIterator const &Pkg,bool AutoInst) MarkKeep(Pkg); return; } + + // See if there is even any possible instalation candidate + if (P.CandidateVer == 0) + return; // We dont even try to install virtual packages.. if (Pkg->VersionList == 0) @@ -657,7 +644,8 @@ void pkgDepCache::MarkInstall(PkgIterator const &Pkg,bool AutoInst) // Grok or groups DepIterator Start = Dep; bool Result = true; - for (bool LastOR = true; Dep.end() == false && LastOR == true; Dep++) + unsigned Ors = 0; + for (bool LastOR = true; Dep.end() == false && LastOR == true; Dep++,Ors++) { LastOR = (Dep->CompareOp & Dep::Or) == Dep::Or; @@ -676,24 +664,62 @@ void pkgDepCache::MarkInstall(PkgIterator const &Pkg,bool AutoInst) continue; if (Pkg->CurrentVer != 0 && Start.IsCritical() == false) continue; - - // Now we have to take action... - PkgIterator P = Start.SmartTargetPkg(); + + /* If we are in an or group locate the first or that can + succeed. We have already cached this.. */ + for (; Ors > 1 && (DepState[Start->ID] & DepCVer) != DepCVer; Ors--) + Start++; + + /* This bit is for processing the possibilty of an install/upgrade + fixing the problem */ + SPtrArray List = Start.AllTargets(); if ((DepState[Start->ID] & DepCVer) == DepCVer) { - MarkInstall(P,true); + // Right, find the best version to install.. + Version **Cur = List; + PkgIterator P = Start.TargetPkg(); + PkgIterator InstPkg(*Cache,0); - // Set the autoflag, after MarkInstall because MarkInstall unsets it - if (P->CurrentVer == 0) - PkgState[P->ID].Flags |= Flag::Auto; + // See if there are direct matches (at the start of the list) + for (; *Cur != 0 && (*Cur)->ParentPkg == P.Index(); Cur++) + { + PkgIterator Pkg(*Cache,Cache->PkgP + (*Cur)->ParentPkg); + if (PkgState[Pkg->ID].CandidateVer != *Cur) + continue; + InstPkg = Pkg; + break; + } + + // Select the highest priority providing package + if (InstPkg.end() == false) + { + pkgPrioSortList(*Cache,Cur); + for (; *Cur != 0; Cur++) + { + PkgIterator Pkg(*Cache,Cache->PkgP + (*Cur)->ParentPkg); + if (PkgState[Pkg->ID].CandidateVer != *Cur) + continue; + InstPkg = Pkg; + break; + } + } + + if (InstPkg.end() == false) + { + MarkInstall(InstPkg,true,Depth + 1); + // Set the autoflag, after MarkInstall because MarkInstall unsets it + if (P->CurrentVer == 0) + PkgState[InstPkg->ID].Flags |= Flag::Auto; + } + continue; } - // For conflicts we just de-install the package and mark as auto - if (Start->Type == Dep::Conflicts) + /* For conflicts we just de-install the package and mark as auto, + Conflicts may not have or groups */ + if (Start->Type == Dep::Conflicts || Start->Type == Dep::Obsoletes) { - Version **List = Start.AllTargets(); for (Version **I = List; *I != 0; I++) { VerIterator Ver(*this,*I); @@ -702,7 +728,6 @@ void pkgDepCache::MarkInstall(PkgIterator const &Pkg,bool AutoInst) MarkDelete(Pkg); PkgState[Pkg->ID].Flags |= Flag::Auto; } - delete [] List; continue; } } @@ -726,6 +751,27 @@ void pkgDepCache::SetReInstall(PkgIterator const &Pkg,bool To) AddSizes(Pkg); } /*}}}*/ +// DepCache::SetCandidateVersion - Change the candidate version /*{{{*/ +// --------------------------------------------------------------------- +/* */ +void pkgDepCache::SetCandidateVersion(VerIterator TargetVer) +{ + pkgCache::PkgIterator Pkg = TargetVer.ParentPkg(); + StateCache &P = PkgState[Pkg->ID]; + + RemoveSizes(Pkg); + RemoveStates(Pkg); + + if (P.CandidateVer == P.InstallVer) + P.InstallVer = (Version *)TargetVer; + P.CandidateVer = (Version *)TargetVer; + P.Update(Pkg,*this); + + AddStates(Pkg); + Update(Pkg); + AddSizes(Pkg); +} + /*}}}*/ // StateCache::Update - Compute the various static display things /*{{{*/ // --------------------------------------------------------------------- /* This is called whenever the Candidate version changes. */ @@ -770,21 +816,48 @@ const char *pkgDepCache::StateCache::StripEpoch(const char *Ver) return Ver; } /*}}}*/ -// StateCache::SetCandidateVersion - Change the candidate version /*{{{*/ + +// Policy::GetCandidateVer - Returns the Candidate install version /*{{{*/ // --------------------------------------------------------------------- -/* */ -void pkgDepCache::SetCandidateVersion(VerIterator TargetVer) +/* The default just returns the highest available version that is not + a source and automatic. */ +pkgCache::VerIterator pkgDepCache::Policy::GetCandidateVer(PkgIterator Pkg) { - pkgCache::PkgIterator I = TargetVer.ParentPkg(); - - RemoveSizes(I); - RemoveStates(I); + /* Not source/not automatic versions cannot be a candidate version + unless they are already installed */ + VerIterator Last(*(pkgCache *)this,0); - PkgState[I->ID].CandidateVer = (Version *) TargetVer; - PkgState[I->ID].Update(I, *this); + for (VerIterator I = Pkg.VersionList(); I.end() == false; I++) + { + if (Pkg.CurrentVer() == I) + return I; + + for (VerFileIterator J = I.FileList(); J.end() == false; J++) + { + if ((J.File()->Flags & Flag::NotSource) != 0) + continue; + + /* Stash the highest version of a not-automatic source, we use it + if there is nothing better */ + if ((J.File()->Flags & Flag::NotAutomatic) != 0) + { + if (Last.end() == true) + Last = I; + continue; + } + + return I; + } + } - AddStates(I); - Update(I); - AddSizes(I); + return Last; +} + /*}}}*/ +// Policy::IsImportantDep - True if the dependency is important /*{{{*/ +// --------------------------------------------------------------------- +/* */ +bool pkgDepCache::Policy::IsImportantDep(DepIterator Dep) +{ + return Dep.IsCritical(); } /*}}}*/ diff --git a/apt-pkg/depcache.h b/apt-pkg/depcache.h index 3bb677dc1..6d51920e9 100644 --- a/apt-pkg/depcache.h +++ b/apt-pkg/depcache.h @@ -1,6 +1,6 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ -// $Id: depcache.h,v 1.13 2000/05/31 02:49:37 jgg Exp $ +// $Id: depcache.h,v 1.14 2001/02/20 07:03:17 jgg Exp $ /* ###################################################################### DepCache - Dependency Extension data for the cache @@ -35,7 +35,6 @@ ##################################################################### */ /*}}}*/ -// Header section: pkglib #ifndef PKGLIB_DEPCACHE_H #define PKGLIB_DEPCACHE_H @@ -46,7 +45,7 @@ #include #include -class pkgDepCache : public pkgCache +class pkgDepCache : protected pkgCache::Namespace { public: @@ -75,16 +74,16 @@ class pkgDepCache : public pkgCache // Pointer to the install version. Version *InstallVer; + + // Copy of Package::Flags + unsigned short Flags; + unsigned short iFlags; // Internal flags // Various tree indicators signed char Status; // -1,0,1,2 unsigned char Mode; // ModeList unsigned char DepState; // DepState Flags - // Copy of Package::Flags - unsigned short Flags; - unsigned short iFlags; // Internal flags - // Update of candidate version const char *StripEpoch(const char *Ver); void Update(PkgIterator Pkg,pkgCache &Cache); @@ -110,29 +109,42 @@ class pkgDepCache : public pkgCache void BuildGroupOrs(VerIterator const &V); void UpdateVerState(PkgIterator Pkg); - bool Init(OpProgress *Prog); - + // User Policy control + class Policy + { + public: + + virtual VerIterator GetCandidateVer(PkgIterator Pkg); + virtual bool IsImportantDep(DepIterator Dep); + + virtual ~Policy() {}; + }; + protected: // State information + pkgCache *Cache; StateCache *PkgState; unsigned char *DepState; - signed long iUsrSize; - unsigned long iDownloadSize; + double iUsrSize; + double iDownloadSize; unsigned long iInstCount; unsigned long iDelCount; unsigned long iKeepCount; unsigned long iBrokenCount; unsigned long iBadCount; - + + Policy *delLocalPolicy; // For memory clean up.. + Policy *LocalPolicy; + // Check for a matching provides bool CheckDep(DepIterator Dep,int Type,PkgIterator &Res); inline bool CheckDep(DepIterator Dep,int Type) { - PkgIterator Res(*this); + PkgIterator Res(*this,0); return CheckDep(Dep,Type,Res); - } + } // Computes state information for deps and versions (w/o storing) unsigned char DependencyState(DepIterator &D); @@ -145,17 +157,27 @@ class pkgDepCache : public pkgCache void Update(PkgIterator const &P); // Count manipulators - void AddSizes(const PkgIterator &Pkg,long Mult = 1); + void AddSizes(const PkgIterator &Pkg,signed long Mult = 1); inline void RemoveSizes(const PkgIterator &Pkg) {AddSizes(Pkg,-1);}; void AddStates(const PkgIterator &Pkg,int Add = 1); inline void RemoveStates(const PkgIterator &Pkg) {AddStates(Pkg,-1);}; - + public: + // Legacy.. We look like a pkgCache + inline operator pkgCache &() {return *Cache;}; + inline Header &Head() {return *Cache->HeaderP;}; + inline PkgIterator PkgBegin() {return Cache->PkgBegin();}; + inline PkgIterator FindPkg(string const &Name) {return Cache->FindPkg(Name);}; + + inline pkgCache &GetCache() {return *Cache;}; + inline pkgVersioningSystem &VS() {return *Cache->VS;}; + // Policy implementation - virtual VerIterator GetCandidateVer(PkgIterator Pkg,bool AllowCurrent = true); - virtual bool IsImportantDep(DepIterator Dep); - + inline VerIterator GetCandidateVer(PkgIterator Pkg) {return LocalPolicy->GetCandidateVer(Pkg);}; + inline bool IsImportantDep(DepIterator Dep) {return LocalPolicy->IsImportantDep(Dep);}; + inline Policy &GetPolicy() {return *LocalPolicy;}; + // Accessors inline StateCache &operator [](PkgIterator const &I) {return PkgState[I->ID];}; inline unsigned char &operator [](DepIterator const &I) {return DepState[I->ID];}; @@ -163,7 +185,8 @@ class pkgDepCache : public pkgCache // Manipulators void MarkKeep(PkgIterator const &Pkg,bool Soft = false); void MarkDelete(PkgIterator const &Pkg,bool Purge = false); - void MarkInstall(PkgIterator const &Pkg,bool AutoInst = true); + void MarkInstall(PkgIterator const &Pkg,bool AutoInst = true, + unsigned long Depth = 0); void SetReInstall(PkgIterator const &Pkg,bool To); void SetCandidateVersion(VerIterator TargetVer); @@ -171,16 +194,17 @@ class pkgDepCache : public pkgCache void Update(OpProgress *Prog = 0); // Size queries - inline signed long UsrSize() {return iUsrSize;}; - inline unsigned long DebSize() {return iDownloadSize;}; + inline double UsrSize() {return iUsrSize;}; + inline double DebSize() {return iDownloadSize;}; inline unsigned long DelCount() {return iDelCount;}; inline unsigned long KeepCount() {return iKeepCount;}; inline unsigned long InstCount() {return iInstCount;}; inline unsigned long BrokenCount() {return iBrokenCount;}; inline unsigned long BadCount() {return iBadCount;}; + + bool Init(OpProgress *Prog); - pkgDepCache(MMap &Map,OpProgress &Prog); - pkgDepCache(MMap &Map); + pkgDepCache(pkgCache *Cache,Policy *Plcy = 0); virtual ~pkgDepCache(); }; diff --git a/apt-pkg/indexfile.cc b/apt-pkg/indexfile.cc new file mode 100644 index 000000000..f59387c1a --- /dev/null +++ b/apt-pkg/indexfile.cc @@ -0,0 +1,77 @@ +// -*- mode: cpp; mode: fold -*- +// Description /*{{{*/ +// $Id: indexfile.cc,v 1.2 2001/02/20 07:03:17 jgg Exp $ +/* ###################################################################### + + Index File - Abstraction for an index of archive/souce file. + + ##################################################################### */ + /*}}}*/ +// Include Files /*{{{*/ +#ifdef __GNUG__ +#pragma implementation "apt-pkg/indexfile.h" +#endif + +#include +#include + /*}}}*/ + +// Global list of Item supported +static pkgIndexFile::Type *ItmList[10]; +pkgIndexFile::Type **pkgIndexFile::Type::GlobalList = ItmList; +unsigned long pkgIndexFile::Type::GlobalListLen = 0; + +// Type::Type - Constructor /*{{{*/ +// --------------------------------------------------------------------- +/* */ +pkgIndexFile::Type::Type() +{ + ItmList[GlobalListLen] = this; + GlobalListLen++; +} + /*}}}*/ +// Type::GetType - Locate the type by name /*{{{*/ +// --------------------------------------------------------------------- +/* */ +pkgIndexFile::Type *pkgIndexFile::Type::GetType(const char *Type) +{ + for (unsigned I = 0; I != GlobalListLen; I++) + if (strcmp(GlobalList[I]->Label,Type) == 0) + return GlobalList[I]; + return 0; +} + /*}}}*/ + +// IndexFile::GetIndexes - Stub /*{{{*/ +// --------------------------------------------------------------------- +/* */ +bool pkgIndexFile::GetIndexes(pkgAcquire *Owner) const +{ + return _error->Error("Internal Error, this index file is not downloadable"); +} + /*}}}*/ +// IndexFile::ArchiveInfo - Stub /*{{{*/ +// --------------------------------------------------------------------- +/* */ +string pkgIndexFile::ArchiveInfo(pkgCache::VerIterator Ver) const +{ + return string(); +} + /*}}}*/ +// IndexFile::FindInCache - Stub /*{{{*/ +// --------------------------------------------------------------------- +/* */ +pkgCache::PkgFileIterator pkgIndexFile::FindInCache(pkgCache &Cache) const +{ + return pkgCache::PkgFileIterator(Cache); +} + /*}}}*/ +// IndexFile::SourceIndex - Stub /*{{{*/ +// --------------------------------------------------------------------- +/* */ +string pkgIndexFile::SourceInfo(pkgSrcRecords::Parser const &Record, + pkgSrcRecords::File const &File) const +{ + return string(); +} + /*}}}*/ diff --git a/apt-pkg/indexfile.h b/apt-pkg/indexfile.h new file mode 100644 index 000000000..d264a3aba --- /dev/null +++ b/apt-pkg/indexfile.h @@ -0,0 +1,80 @@ +// -*- mode: cpp; mode: fold -*- +// Description /*{{{*/ +// $Id: indexfile.h,v 1.2 2001/02/20 07:03:17 jgg Exp $ +/* ###################################################################### + + Index File - Abstraction for an index of archive/source file. + + There are 3 primary sorts of index files, all represented by this + class: + + Binary index files + Bianry index files decribing the local system + Source index files + + They are all bundled together here, and the interfaces for + sources.list, acquire, cache gen and record parsing all use this class + to acess the underlying representation. + + ##################################################################### */ + /*}}}*/ +#ifndef PKGLIB_INDEXFILE_H +#define PKGLIB_INDEXFILE_H + +#ifdef __GNUG__ +#pragma interface "apt-pkg/indexfile.h" +#endif + +#include +#include +#include +#include + +class pkgAcquire; +class pkgCacheGenerator; +class OpProgress; +class pkgIndexFile +{ + public: + + class Type + { + public: + + // Global list of Items supported + static Type **GlobalList; + static unsigned long GlobalListLen; + static Type *GetType(const char *Type); + + const char *Label; + + virtual pkgRecords::Parser *CreatePkgParser(pkgCache::PkgFileIterator File) const {return 0;}; + Type(); + }; + + virtual const Type *GetType() const = 0; + + // Return descriptive strings of various sorts + virtual string ArchiveInfo(pkgCache::VerIterator Ver) const; + virtual string SourceInfo(pkgSrcRecords::Parser const &Record, + pkgSrcRecords::File const &File) const; + virtual string Describe() const = 0; + + // Interface for acquire + virtual string ArchiveURI(string File) const {return string();}; + virtual bool GetIndexes(pkgAcquire *Owner) const; + + // Interface for the record parsers + virtual pkgSrcRecords::Parser *CreateSrcParser() const {return 0;}; + + // Interface for the Cache Generator + virtual bool Exists() const = 0; + virtual bool HasPackages() const = 0; + virtual unsigned long Size() const = 0; + virtual bool Merge(pkgCacheGenerator &Gen,OpProgress &Prog) const {return false;}; + virtual pkgCache::PkgFileIterator FindInCache(pkgCache &Cache) const; + + virtual ~pkgIndexFile() {}; +}; + +#endif diff --git a/apt-pkg/init.cc b/apt-pkg/init.cc index 29926b97a..01b9d8665 100644 --- a/apt-pkg/init.cc +++ b/apt-pkg/init.cc @@ -1,6 +1,6 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ -// $Id: init.cc,v 1.14 1998/11/25 23:54:06 jgg Exp $ +// $Id: init.cc,v 1.15 2001/02/20 07:03:17 jgg Exp $ /* ###################################################################### Init - Initialize the package library @@ -10,61 +10,120 @@ // Include files /*{{{*/ #include #include +#include + +#include #include +#include /*}}}*/ -// pkgInitialize - Initialize the configuration class /*{{{*/ +#define Stringfy_(x) # x +#define Stringfy(x) Stringfy_(x) +const char *pkgVersion = VERSION; +const char *pkgLibVersion = Stringfy(APT_PKG_MAJOR) "." + Stringfy(APT_PKG_MINOR) "." + Stringfy(APT_PKG_RELEASE); +const char *pkgCPU = COMMON_CPU; +const char *pkgOS = COMMON_OS; + +// pkgInitConfig - Initialize the configuration class /*{{{*/ // --------------------------------------------------------------------- /* Directories are specified in such a way that the FindDir function will understand them. That is, if they don't start with a / then their parent is prepended, this allows a fair degree of flexability. */ -bool pkgInitialize(Configuration &Cnf) +bool pkgInitConfig(Configuration &Cnf) { // General APT things - Cnf.Set("APT::Architecture",ARCHITECTURE); - - // State - Cnf.Set("Dir::State","/var/state/apt/"); - Cnf.Set("Dir::State::lists","lists/"); + if (strcmp(COMMON_OS,"linux") == 0 || + strcmp(COMMON_OS,"unknown") == 0) + Cnf.Set("APT::Architecture",COMMON_CPU); + else + Cnf.Set("APT::Architecture",COMMON_OS "-" COMMON_CPU); + Cnf.Set("Dir","/"); - /* These really should be jammed into a generic 'Local Database' engine - which is yet to be determined. The functions in pkgcachegen should - be the only users of these */ - Cnf.Set("Dir::State::xstatus","xstatus"); - Cnf.Set("Dir::State::userstatus","status.user"); - Cnf.Set("Dir::State::status","/var/lib/dpkg/status"); + // State + Cnf.Set("Dir::State","var/lib/apt/"); + + /* Just in case something goes horribly wrong, we can fall back to the + old /var/state paths.. */ + struct stat St; + if (stat("/var/lib/apt/.",&St) != 0 && + stat("/var/state/apt/.",&St) == 0) + Cnf.Set("Dir::State","var/state/apt/"); + + Cnf.Set("Dir::State::lists","lists/"); Cnf.Set("Dir::State::cdroms","cdroms.list"); // Cache - Cnf.Set("Dir::Cache","/var/cache/apt/"); + Cnf.Set("Dir::Cache","var/cache/apt/"); Cnf.Set("Dir::Cache::archives","archives/"); Cnf.Set("Dir::Cache::srcpkgcache","srcpkgcache.bin"); Cnf.Set("Dir::Cache::pkgcache","pkgcache.bin"); // Configuration - Cnf.Set("Dir::Etc","/etc/apt/"); + Cnf.Set("Dir::Etc","etc/apt/"); Cnf.Set("Dir::Etc::sourcelist","sources.list"); Cnf.Set("Dir::Etc::main","apt.conf"); + Cnf.Set("Dir::Etc::parts","apt.conf.d"); + Cnf.Set("Dir::Etc::preferences","preferences"); Cnf.Set("Dir::Bin::methods","/usr/lib/apt/methods"); - Cnf.Set("Dir::Bin::dpkg","/usr/bin/dpkg"); - - // Read the main config file - string FName = Cnf.FindFile("Dir::Etc::main"); + bool Res = true; - if (FileExists(FName) == true) - Res &= ReadConfigFile(Cnf,FName); // Read an alternate config file const char *Cfg = getenv("APT_CONFIG"); if (Cfg != 0 && FileExists(Cfg) == true) Res &= ReadConfigFile(Cnf,Cfg); + // Read the configuration parts dir + string Parts = Cnf.FindDir("Dir::Etc::parts"); + if (FileExists(Parts) == true) + Res &= ReadConfigDir(Cnf,Parts); + + // Read the main config file + string FName = Cnf.FindFile("Dir::Etc::main"); + if (FileExists(FName) == true) + Res &= ReadConfigFile(Cnf,FName); + if (Res == false) return false; - if (Cnf.FindB("Debug::pkgInitialize",false) == true) + if (Cnf.FindB("Debug::pkgInitConfig",false) == true) Cnf.Dump(); return true; } /*}}}*/ +// pkgInitSystem - Initialize the _system calss /*{{{*/ +// --------------------------------------------------------------------- +/* */ +bool pkgInitSystem(Configuration &Cnf,pkgSystem *&Sys) +{ + Sys = 0; + string Label = Cnf.Find("Apt::System",""); + if (Label.empty() == false) + { + Sys = pkgSystem::GetSystem(Label.c_str()); + if (Sys == 0) + return _error->Error(_("Packaging system '%s' is not supported"),Label.c_str()); + } + else + { + signed MaxScore = 0; + for (unsigned I = 0; I != pkgSystem::GlobalListLen; I++) + { + signed Score = pkgSystem::GlobalList[I]->Score(Cnf); + if (Score > MaxScore) + { + MaxScore = Score; + Sys = pkgSystem::GlobalList[I]; + } + } + + if (Sys == 0) + return _error->Error(_("Unable to determine a suitable system type")); + } + + return Sys->Initialize(Cnf); +} + /*}}}*/ diff --git a/apt-pkg/init.h b/apt-pkg/init.h index 27bfd8868..ac256cba2 100644 --- a/apt-pkg/init.h +++ b/apt-pkg/init.h @@ -1,6 +1,6 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ -// $Id: init.h,v 1.3 1998/07/16 06:08:37 jgg Exp $ +// $Id: init.h,v 1.4 2001/02/20 07:03:17 jgg Exp $ /* ###################################################################### Init - Initialize the package library @@ -10,12 +10,34 @@ ##################################################################### */ /*}}}*/ -// Header section: pkglib #ifndef PKGLIB_INIT_H #define PKGLIB_INIT_H #include +#include -bool pkgInitialize(Configuration &Cnf); +// See the makefile +#define APT_PKG_MAJOR 3 +#define APT_PKG_MINOR 1 +#define APT_PKG_RELEASE 0 + +extern const char *pkgVersion; +extern const char *pkgLibVersion; +extern const char *pkgOS; +extern const char *pkgCPU; + +bool pkgInitConfig(Configuration &Cnf); +bool pkgInitSystem(Configuration &Cnf,pkgSystem *&Sys); + +#ifdef APT_COMPATIBILITY +#if APT_COMPATIBILITY != 986 +#warning "Using APT_COMPATIBILITY" +#endif + +inline bool pkgInitialize(Configuration &Cnf) +{ + return pkgInitConfig(Cnf) && pkgInitSystem(Cnf,_system); +}; +#endif #endif diff --git a/apt-pkg/makefile b/apt-pkg/makefile index d5e20374d..cc3e47597 100644 --- a/apt-pkg/makefile +++ b/apt-pkg/makefile @@ -9,36 +9,41 @@ HEADER_TARGETDIRS = apt-pkg # Bring in the default rules include ../buildlib/defaults.mak -# The library name +# The library name, don't forget to update init.h LIBRARY=apt-pkg -MAJOR=2.7 -MINOR=2 +MAJOR=3.1 +MINOR=0 SLIBS=$(PTHREADLIB) # Source code for the contributed non-core things SOURCE = contrib/mmap.cc contrib/error.cc contrib/strutl.cc \ contrib/configuration.cc contrib/progress.cc contrib/cmndline.cc \ - contrib/md5.cc contrib/cdromutl.cc contrib/crc-16.cc + contrib/md5.cc contrib/cdromutl.cc contrib/crc-16.cc \ + contrib/fileutl.cc +HEADERS = mmap.h error.h configuration.h fileutl.h cmndline.h \ + md5.h crc-16.h cdromutl.h strutl.h sptr.h -# Source code for the main library -SOURCE+= pkgcache.cc version.cc fileutl.cc pkgcachegen.cc depcache.cc \ +# Source code for the core main library +SOURCE+= pkgcache.cc version.cc depcache.cc \ orderlist.cc tagfile.cc sourcelist.cc packagemanager.cc \ - pkgrecords.cc algorithms.cc acquire.cc acquire-item.cc \ + pkgrecords.cc algorithms.cc acquire.cc\ acquire-worker.cc acquire-method.cc init.cc clean.cc \ - srcrecords.cc cachefile.cc + srcrecords.cc cachefile.cc versionmatch.cc policy.cc \ + pkgsystem.cc indexfile.cc pkgcachegen.cc acquire-item.cc +HEADERS+= algorithms.h depcache.h pkgcachegen.h cacheiterators.h \ + orderlist.h sourcelist.h packagemanager.h tagfile.h \ + init.h pkgcache.h version.h progress.h pkgrecords.h \ + acquire.h acquire-worker.h acquire-item.h acquire-method.h \ + clean.h srcrecords.h cachefile.h versionmatch.h policy.h \ + pkgsystem.h indexfile.h # Source code for the debian specific components -SOURCE+= deb/deblistparser.cc deb/debrecords.cc deb/dpkgpm.cc deb/dpkginit.cc \ - deb/debsrcrecords.cc - -# Public apt-pkg header files -HEADERS = algorithms.h depcache.h mmap.h pkgcachegen.h cacheiterators.h \ - error.h orderlist.h sourcelist.h configuration.h fileutl.h \ - packagemanager.h tagfile.h deblistparser.h init.h pkgcache.h \ - version.h progress.h pkgrecords.h debrecords.h cmndline.h \ - acquire.h acquire-worker.h acquire-item.h acquire-method.h md5.h \ - dpkgpm.h dpkginit.h cdromutl.h strutl.h clean.h srcrecords.h \ - debsrcrecords.h cachefile.h crc-16.h +# In theory the deb headers do not need to be exported.. +SOURCE+= deb/deblistparser.cc deb/debrecords.cc deb/dpkgpm.cc \ + deb/debsrcrecords.cc deb/debversion.cc deb/debsystem.cc \ + deb/debindexfile.cc deb/debindexfile.cc +HEADERS+= debversion.h debsrcrecords.h dpkgpm.h debrecords.h \ + deblistparser.h debsystem.h debindexfile.h HEADERS := $(addprefix apt-pkg/,$(HEADERS)) diff --git a/apt-pkg/orderlist.cc b/apt-pkg/orderlist.cc index b46056128..4bd603726 100644 --- a/apt-pkg/orderlist.cc +++ b/apt-pkg/orderlist.cc @@ -1,13 +1,13 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ -// $Id: orderlist.cc,v 1.11 2000/01/16 08:45:47 jgg Exp $ +// $Id: orderlist.cc,v 1.12 2001/02/20 07:03:17 jgg Exp $ /* ###################################################################### Order List - Represents and Manipulates an ordered list of packages. A list of packages can be ordered by a number of conflicting criteria each given a specific priority. Each package also has a set of flags - indicating some usefull things about it that are derived in the + indicating some useful things about it that are derived in the course of sorting. The pkgPackageManager class uses this class for all of it's installation ordering needs. @@ -54,6 +54,12 @@ after flag set. This forces them and all their dependents to be ordered toward the end. + There are complications in this algorithm when presented with cycles. + For all known practical cases it works, all cases where it doesn't work + is fixable by tweaking the package descriptions. However, it should be + possible to impove this further to make some better choices when + presented with cycles. + ##################################################################### */ /*}}}*/ // Include Files /*{{{*/ @@ -64,6 +70,8 @@ #include #include #include +#include +#include /*}}}*/ pkgOrderList *pkgOrderList::Me = 0; @@ -71,7 +79,7 @@ pkgOrderList *pkgOrderList::Me = 0; // OrderList::pkgOrderList - Constructor /*{{{*/ // --------------------------------------------------------------------- /* */ -pkgOrderList::pkgOrderList(pkgDepCache &Cache) : Cache(Cache) +pkgOrderList::pkgOrderList(pkgDepCache *pCache) : Cache(*pCache) { FileList = 0; Primary = 0; @@ -79,10 +87,11 @@ pkgOrderList::pkgOrderList(pkgDepCache &Cache) : Cache(Cache) RevDepends = 0; Remove = 0; LoopCount = -1; - + Debug = _config->FindB("Debug::pkgOrderList",false); + /* Construct the arrays, egcs 1.0.1 bug requires the package count hack */ - unsigned long Size = Cache.HeaderP->PackageCount; + unsigned long Size = Cache.Head().PackageCount; Flags = new unsigned short[Size]; End = List = new Package *[Size]; memset(Flags,0,sizeof(*Flags)*Size); @@ -123,9 +132,9 @@ bool pkgOrderList::IsMissing(PkgIterator Pkg) bool pkgOrderList::DoRun() { // Temp list - unsigned long Size = Cache.HeaderP->PackageCount; - Package **NList = new Package *[Size]; - AfterList = new Package *[Size]; + unsigned long Size = Cache.Head().PackageCount; + SPtrArray NList = new Package *[Size]; + SPtrArray AfterList = new Package *[Size]; AfterEnd = AfterList; Depth = 0; @@ -141,8 +150,6 @@ bool pkgOrderList::DoRun() if (VisitNode(PkgIterator(Cache,*I)) == false) { End = OldEnd; - delete [] NList; - delete [] AfterList; return false; } @@ -152,8 +159,7 @@ bool pkgOrderList::DoRun() // Swap the main list to the new list delete [] List; - delete [] AfterList; - List = NList; + List = NList.UnGuard(); return true; } /*}}}*/ @@ -216,32 +222,43 @@ bool pkgOrderList::OrderUnpack(string *FileList) Me = this; qsort(List,End - List,sizeof(*List),&OrderCompareA); + if (Debug == true) + clog << "** Pass A" << endl; if (DoRun() == false) return false; + if (Debug == true) + clog << "** Pass B" << endl; Secondary = 0; if (DoRun() == false) return false; + if (Debug == true) + clog << "** Pass C" << endl; LoopCount = 0; RevDepends = 0; Remove = 0; // Otherwise the libreadline remove problem occures if (DoRun() == false) return false; - + + if (Debug == true) + clog << "** Pass D" << endl; LoopCount = 0; Primary = &pkgOrderList::DepUnPackPre; if (DoRun() == false) return false; -/* cout << "----------END" << endl; - - for (iterator I = List; I != End; I++) + if (Debug == true) { - PkgIterator P(Cache,*I); - if (IsNow(P) == true) - cout << P.Name() << ' ' << IsMissing(P) << ',' << IsFlag(P,After) << endl; - }*/ + clog << "** Unpack ordering done" << endl; + + for (iterator I = List; I != End; I++) + { + PkgIterator P(Cache,*I); + if (IsNow(P) == true) + clog << P.Name() << ' ' << IsMissing(P) << ',' << IsFlag(P,After) << endl; + } + } return true; } @@ -279,6 +296,9 @@ int pkgOrderList::Score(PkgIterator Pkg) if ((Pkg->Flags & pkgCache::Flag::Essential) == pkgCache::Flag::Essential) Score += 100; + if (IsFlag(Pkg,Immediate) == true) + Score += 10; + for (DepIterator D = Cache[Pkg].InstVerIter(Cache).DependsList(); D.end() == false; D++) if (D->Type == pkgCache::Dep::PreDepends) @@ -375,7 +395,7 @@ int pkgOrderList::OrderCompareA(const void *a, const void *b) /*}}}*/ // OrderList::OrderCompareB - Order the installation by source /*{{{*/ // --------------------------------------------------------------------- -/* This orders by installation source. This is usefull to handle +/* This orders by installation source. This is useful to handle inter-source breaks */ int pkgOrderList::OrderCompareB(const void *a, const void *b) { @@ -454,7 +474,7 @@ bool pkgOrderList::VisitRProvides(DepFunc F,VerIterator Ver) /* This routine calls visit on all providing packages. */ bool pkgOrderList::VisitProvides(DepIterator D,bool Critical) { - Version **List = D.AllTargets(); + SPtrArray List = D.AllTargets(); for (Version **I = List; *I != 0; I++) { VerIterator Ver(Cache,*I); @@ -463,10 +483,14 @@ bool pkgOrderList::VisitProvides(DepIterator D,bool Critical) if (Cache[Pkg].Keep() == true && Pkg.State() == PkgIterator::NeedsNothing) continue; - if (D->Type != pkgCache::Dep::Conflicts && Cache[Pkg].InstallVer != *I) + if (D->Type != pkgCache::Dep::Conflicts && + D->Type != pkgCache::Dep::Obsoletes && + Cache[Pkg].InstallVer != *I) continue; - if (D->Type == pkgCache::Dep::Conflicts && (Version *)Pkg.CurrentVer() != *I) + if ((D->Type == pkgCache::Dep::Conflicts || + D->Type == pkgCache::Dep::Obsoletes) && + (Version *)Pkg.CurrentVer() != *I) continue; // Skip over missing files @@ -474,12 +498,8 @@ bool pkgOrderList::VisitProvides(DepIterator D,bool Critical) continue; if (VisitNode(Pkg) == false) - { - delete [] List; return false; - } } - delete [] List; return true; } /*}}}*/ @@ -496,8 +516,12 @@ bool pkgOrderList::VisitNode(PkgIterator Pkg) IsFlag(Pkg,AddPending) == true || IsFlag(Pkg,InList) == false) return true; -/* for (int j = 0; j != Depth; j++) cout << ' '; - cout << "Visit " << Pkg.Name() << endl;*/ + if (Debug == true) + { + for (int j = 0; j != Depth; j++) clog << ' '; + clog << "Visit " << Pkg.Name() << endl; + } + Depth++; // Color grey @@ -550,10 +574,13 @@ bool pkgOrderList::VisitNode(PkgIterator Pkg) Primary = Old; Depth--; - -/* for (int j = 0; j != Depth; j++) cout << ' '; - cout << "Leave " << Pkg.Name() << ' ' << IsFlag(Pkg,Added) << ',' << IsFlag(Pkg,AddPending) << endl;*/ + if (Debug == true) + { + for (int j = 0; j != Depth; j++) clog << ' '; + clog << "Leave " << Pkg.Name() << ' ' << IsFlag(Pkg,Added) << ',' << IsFlag(Pkg,AddPending) << endl; + } + return true; } /*}}}*/ @@ -573,7 +600,8 @@ bool pkgOrderList::DepUnPackCrit(DepIterator D) { /* Reverse depenanices are only interested in conflicts, predepend breakage is ignored here */ - if (D->Type != pkgCache::Dep::Conflicts) + if (D->Type != pkgCache::Dep::Conflicts && + D->Type != pkgCache::Dep::Obsoletes) continue; // Duplication elimination, consider only the current version @@ -594,7 +622,9 @@ bool pkgOrderList::DepUnPackCrit(DepIterator D) { /* Forward critical dependencies MUST be correct before the package can be unpacked. */ - if (D->Type != pkgCache::Dep::Conflicts && D->Type != pkgCache::Dep::PreDepends) + if (D->Type != pkgCache::Dep::Conflicts && + D->Type != pkgCache::Dep::Obsoletes && + D->Type != pkgCache::Dep::PreDepends) continue; /* We wish to check if the dep is okay in the now state of the @@ -702,7 +732,7 @@ bool pkgOrderList::DepUnPackPre(DepIterator D) else continue; } - + /* We wish to check if the dep is okay in the now state of the target package against the install state of this package. */ if (CheckDep(D) == true) @@ -712,7 +742,7 @@ bool pkgOrderList::DepUnPackPre(DepIterator D) if (IsFlag(D.TargetPkg(),AddPending) == false) continue; } - + // This is the loop detection if (IsFlag(D.TargetPkg(),Added) == true || IsFlag(D.TargetPkg(),AddPending) == true) @@ -875,7 +905,7 @@ bool pkgOrderList::AddLoop(DepIterator D) /* */ void pkgOrderList::WipeFlags(unsigned long F) { - unsigned long Size = Cache.HeaderP->PackageCount; + unsigned long Size = Cache.Head().PackageCount; for (unsigned long I = 0; I != Size; I++) Flags[I] &= ~F; } @@ -889,7 +919,7 @@ void pkgOrderList::WipeFlags(unsigned long F) this fails to produce a suitable result. */ bool pkgOrderList::CheckDep(DepIterator D) { - Version **List = D.AllTargets(); + SPtrArray List = D.AllTargets(); bool Hit = false; for (Version **I = List; *I != 0; I++) { @@ -912,10 +942,11 @@ bool pkgOrderList::CheckDep(DepIterator D) if ((Version *)Pkg.CurrentVer() != *I || Pkg.State() != PkgIterator::NeedsNothing) continue; - + /* Conflicts requires that all versions are not present, depends just needs one */ - if (D->Type != pkgCache::Dep::Conflicts) + if (D->Type != pkgCache::Dep::Conflicts && + D->Type != pkgCache::Dep::Obsoletes) { /* Try to find something that does not have the after flag set if at all possible */ @@ -925,7 +956,6 @@ bool pkgOrderList::CheckDep(DepIterator D) continue; } - delete [] List; return true; } else @@ -933,11 +963,9 @@ bool pkgOrderList::CheckDep(DepIterator D) if (IsFlag(Pkg,After) == true) Flag(D.ParentPkg(),After); - delete [] List; return false; } } - delete [] List; // We found a hit, but it had the after flag set if (Hit == true && D->Type == pkgCache::Dep::PreDepends) @@ -948,7 +976,8 @@ bool pkgOrderList::CheckDep(DepIterator D) /* Conflicts requires that all versions are not present, depends just needs one */ - if (D->Type == pkgCache::Dep::Conflicts) + if (D->Type == pkgCache::Dep::Conflicts || + D->Type == pkgCache::Dep::Obsoletes) return true; return false; } diff --git a/apt-pkg/orderlist.h b/apt-pkg/orderlist.h index 59949f106..d13301bcf 100644 --- a/apt-pkg/orderlist.h +++ b/apt-pkg/orderlist.h @@ -1,19 +1,18 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ -// $Id: orderlist.h,v 1.8 2000/01/16 08:45:47 jgg Exp $ +// $Id: orderlist.h,v 1.9 2001/02/20 07:03:17 jgg Exp $ /* ###################################################################### Order List - Represents and Manipulates an ordered list of packages. A list of packages can be ordered by a number of conflicting criteria each given a specific priority. Each package also has a set of flags - indicating some usefull things about it that are derived in the + indicating some useful things about it that are derived in the course of sorting. The pkgPackageManager class uses this class for all of it's installation ordering needs. ##################################################################### */ /*}}}*/ -// Header section: pkglib #ifndef PKGLIB_ORDERLIST_H #define PKGLIB_ORDERLIST_H @@ -24,19 +23,11 @@ #include class pkgDepCache; -class pkgOrderList +class pkgOrderList : protected pkgCache::Namespace { protected: - pkgDepCache &Cache; - - // Bring some usefull types into the local scope - typedef pkgCache::PkgIterator PkgIterator; - typedef pkgCache::VerIterator VerIterator; - typedef pkgCache::DepIterator DepIterator; - typedef pkgCache::PrvIterator PrvIterator; - typedef pkgCache::Package Package; - typedef pkgCache::Version Version; + pkgDepCache &Cache; typedef bool (pkgOrderList::*DepFunc)(DepIterator D); // These are the currently selected ordering functions @@ -48,13 +39,13 @@ class pkgOrderList // State Package **End; Package **List; - Package **AfterList; Package **AfterEnd; string *FileList; DepIterator Loops[20]; int LoopCount; int Depth; unsigned short *Flags; + bool Debug; // Main visit function bool VisitNode(PkgIterator Pkg); @@ -122,7 +113,7 @@ class pkgOrderList int Score(PkgIterator Pkg); - pkgOrderList(pkgDepCache &Cache); + pkgOrderList(pkgDepCache *Cache); ~pkgOrderList(); }; diff --git a/apt-pkg/packagemanager.cc b/apt-pkg/packagemanager.cc index 99710469b..6101b618f 100644 --- a/apt-pkg/packagemanager.cc +++ b/apt-pkg/packagemanager.cc @@ -1,6 +1,6 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ -// $Id: packagemanager.cc,v 1.25 2000/05/12 04:26:42 jgg Exp $ +// $Id: packagemanager.cc,v 1.26 2001/02/20 07:03:17 jgg Exp $ /* ###################################################################### Package Manager - Abstacts the package manager @@ -16,6 +16,7 @@ #ifdef __GNUG__ #pragma implementation "apt-pkg/packagemanager.h" #endif + #include #include #include @@ -24,12 +25,15 @@ #include #include #include +#include + +#include /*}}}*/ // PM::PackageManager - Constructor /*{{{*/ // --------------------------------------------------------------------- /* */ -pkgPackageManager::pkgPackageManager(pkgDepCache &Cache) : Cache(Cache) +pkgPackageManager::pkgPackageManager(pkgDepCache *pCache) : Cache(*pCache) { FileNames = new string[Cache.Head().PackageCount]; List = 0; @@ -88,7 +92,7 @@ bool pkgPackageManager::GetArchives(pkgAcquire *Owner,pkgSourceList *Sources, be downloaded. */ bool pkgPackageManager::FixMissing() { - pkgProblemResolver Resolve(Cache); + pkgProblemResolver Resolve(&Cache); List->SetFileList(FileNames); bool Bad = false; @@ -124,7 +128,7 @@ bool pkgPackageManager::CreateOrderList() return true; delete List; - List = new pkgOrderList(Cache); + List = new pkgOrderList(&Cache); bool NoImmConfigure = _config->FindB("APT::Immediate-Configure",false); @@ -193,7 +197,8 @@ bool pkgPackageManager::CheckRConflicts(PkgIterator Pkg,DepIterator D, { for (;D.end() == false; D++) { - if (D->Type != pkgCache::Dep::Conflicts) + if (D->Type != pkgCache::Dep::Conflicts && + D->Type != pkgCache::Dep::Obsoletes) continue; // The package hasnt been changed @@ -204,9 +209,9 @@ bool pkgPackageManager::CheckRConflicts(PkgIterator Pkg,DepIterator D, if (D.ParentPkg() == Pkg || D.ParentVer() != D.ParentPkg().CurrentVer()) continue; - if (pkgCheckDep(D.TargetVer(),Ver,D->CompareOp) == false) + if (Cache.VS().CheckDep(Ver,D->CompareOp,D.TargetVer()) == false) continue; - + if (EarlyRemove(D.ParentPkg()) == false) return _error->Error("Reverse conflicts early remove for package '%s' failed", Pkg.Name()); @@ -220,7 +225,7 @@ bool pkgPackageManager::CheckRConflicts(PkgIterator Pkg,DepIterator D, that the final configuration is valid. */ bool pkgPackageManager::ConfigureAll() { - pkgOrderList OList(Cache); + pkgOrderList OList(&Cache); // Populate the order list for (pkgOrderList::iterator I = List->begin(); I != List->end(); I++) @@ -251,14 +256,14 @@ bool pkgPackageManager::ConfigureAll() of it's dependents. */ bool pkgPackageManager::SmartConfigure(PkgIterator Pkg) { - pkgOrderList OList(Cache); + pkgOrderList OList(&Cache); if (DepAdd(OList,Pkg) == false) return false; if (OList.OrderConfigure() == false) return false; - + // Perform the configuring for (pkgOrderList::iterator I = OList.begin(); I != OList.end(); I++) { @@ -288,8 +293,7 @@ bool pkgPackageManager::DepAdd(pkgOrderList &OList,PkgIterator Pkg,int Depth) return true; if (List->IsFlag(Pkg,pkgOrderList::UnPacked) == false) return false; - - + // Put the package on the list OList.push_back(Pkg); OList.Flag(Pkg,pkgOrderList::Added); @@ -314,7 +318,7 @@ bool pkgPackageManager::DepAdd(pkgOrderList &OList,PkgIterator Pkg,int Depth) if (Bad == false) continue; - Version **VList = D.AllTargets(); + SPtrArray VList = D.AllTargets(); for (Version **I = VList; *I != 0 && Bad == true; I++) { VerIterator Ver(Cache,*I); @@ -332,12 +336,12 @@ bool pkgPackageManager::DepAdd(pkgOrderList &OList,PkgIterator Pkg,int Depth) if (Cache[Pkg].InstallVer != *I || (Cache[Pkg].Keep() == true && Pkg.State() == PkgIterator::NeedsNothing)) continue; + if (List->IsFlag(Pkg,pkgOrderList::UnPacked) == true) Bad = !DepAdd(OList,Pkg,Depth); if (List->IsFlag(Pkg,pkgOrderList::Configured) == true) Bad = false; } - delete [] VList; } if (Bad == true) @@ -388,11 +392,11 @@ bool pkgPackageManager::EarlyRemove(PkgIterator Pkg) if (IsEssential == true) { if (_config->FindB("APT::Force-LoopBreak",false) == false) - return _error->Error("This installation run will require temporarily " - "removing the essential package %s due to a " - "Conflicts/Pre-Depends loop. This is often bad, " - "but if you really want to do it, activate the " - "APT::Force-LoopBreak option.",Pkg.Name()); + return _error->Error(_("This installation run will require temporarily " + "removing the essential package %s due to a " + "Conflicts/Pre-Depends loop. This is often bad, " + "but if you really want to do it, activate the " + "APT::Force-LoopBreak option."),Pkg.Name()); } bool Res = SmartRemove(Pkg); @@ -426,7 +430,7 @@ bool pkgPackageManager::SmartUnPack(PkgIterator Pkg) List->Flag(Pkg,pkgOrderList::UnPacked,pkgOrderList::States); if (List->IsFlag(Pkg,pkgOrderList::Immediate) == true) if (SmartConfigure(Pkg) == false) - return _error->Error("Internal Error, Could not perform immediate configuration"); + return _error->Error("Internal Error, Could not perform immediate configuration (1) on %s",Pkg.Name()); return true; } @@ -443,7 +447,7 @@ bool pkgPackageManager::SmartUnPack(PkgIterator Pkg) while (End->Type == pkgCache::Dep::PreDepends) { // Look for possible ok targets. - Version **VList = Start.AllTargets(); + SPtrArray VList = Start.AllTargets(); bool Bad = true; for (Version **I = VList; *I != 0 && Bad == true; I++) { @@ -473,8 +477,6 @@ bool pkgPackageManager::SmartUnPack(PkgIterator Pkg) Bad = !SmartConfigure(Pkg); } - delete [] VList; - /* If this or element did not match then continue on to the next or element until a matching element is found*/ if (Bad == true) @@ -487,11 +489,12 @@ bool pkgPackageManager::SmartUnPack(PkgIterator Pkg) break; } - if (End->Type == pkgCache::Dep::Conflicts) + if (End->Type == pkgCache::Dep::Conflicts || + End->Type == pkgCache::Dep::Obsoletes) { /* Look for conflicts. Two packages that are both in the install state cannot conflict so we don't check.. */ - Version **VList = End.AllTargets(); + SPtrArray VList = End.AllTargets(); for (Version **I = VList; *I != 0; I++) { VerIterator Ver(Cache,*I); @@ -504,7 +507,6 @@ bool pkgPackageManager::SmartUnPack(PkgIterator Pkg) return _error->Error("Internal Error, Could not early remove %s",Pkg.Name()); } } - delete [] VList; } } @@ -525,7 +527,7 @@ bool pkgPackageManager::SmartUnPack(PkgIterator Pkg) // Perform immedate configuration of the package. if (List->IsFlag(Pkg,pkgOrderList::Immediate) == true) if (SmartConfigure(Pkg) == false) - return _error->Error("Internal Error, Could not perform immediate configuration"); + return _error->Error("Internal Error, Could not perform immediate configuration (2) on %s",Pkg.Name()); return true; } diff --git a/apt-pkg/packagemanager.h b/apt-pkg/packagemanager.h index d8a09f65a..e46f8808b 100644 --- a/apt-pkg/packagemanager.h +++ b/apt-pkg/packagemanager.h @@ -1,6 +1,6 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ -// $Id: packagemanager.h,v 1.10 1999/07/20 05:53:33 jgg Exp $ +// $Id: packagemanager.h,v 1.11 2001/02/20 07:03:17 jgg Exp $ /* ###################################################################### Package Manager - Abstacts the package manager @@ -20,7 +20,6 @@ ##################################################################### */ /*}}}*/ -// Header section: pkglib #ifndef PKGLIB_PACKAGEMANAGER_H #define PKGLIB_PACKAGEMANAGER_H @@ -36,7 +35,7 @@ class pkgDepCache; class pkgSourceList; class pkgOrderList; class pkgRecords; -class pkgPackageManager +class pkgPackageManager : protected pkgCache::Namespace { public: @@ -47,15 +46,7 @@ class pkgPackageManager pkgDepCache &Cache; pkgOrderList *List; bool Debug; - - // Bring some usefull types into the local scope - typedef pkgCache::PkgIterator PkgIterator; - typedef pkgCache::VerIterator VerIterator; - typedef pkgCache::DepIterator DepIterator; - typedef pkgCache::PrvIterator PrvIterator; - typedef pkgCache::Version Version; - typedef pkgCache::Package Package; - + bool DepAdd(pkgOrderList &Order,PkgIterator P,int Depth = 0); OrderResult OrderInstall(); bool CheckRConflicts(PkgIterator Pkg,DepIterator Dep,const char *Ver); @@ -71,10 +62,10 @@ class pkgPackageManager bool SmartRemove(PkgIterator Pkg); bool EarlyRemove(PkgIterator Pkg); - // The Actuall installation implementation - virtual bool Install(PkgIterator /*Pkg*/,string /*File*/) {return false;}; - virtual bool Configure(PkgIterator /*Pkg*/) {return false;}; - virtual bool Remove(PkgIterator /*Pkg*/,bool /*Purge*/=false) {return false;}; + // The Actual installation implementation + virtual bool Install(PkgIterator Pkg,string File) {return false;}; + virtual bool Configure(PkgIterator Pkg) {return false;}; + virtual bool Remove(PkgIterator Pkg,bool Purge=false) {return false;}; virtual bool Go() {return true;}; virtual void Reset() {}; @@ -86,7 +77,7 @@ class pkgPackageManager OrderResult DoInstall(); bool FixMissing(); - pkgPackageManager(pkgDepCache &Cache); + pkgPackageManager(pkgDepCache *Cache); virtual ~pkgPackageManager(); }; diff --git a/apt-pkg/pkgcache.cc b/apt-pkg/pkgcache.cc index 37a9c3aab..aa3e8565e 100644 --- a/apt-pkg/pkgcache.cc +++ b/apt-pkg/pkgcache.cc @@ -1,6 +1,6 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ -// $Id: pkgcache.cc,v 1.31 1999/12/10 23:40:29 jgg Exp $ +// $Id: pkgcache.cc,v 1.32 2001/02/20 07:03:17 jgg Exp $ /* ###################################################################### Package Cache - Accessor code for the cache @@ -24,11 +24,15 @@ #pragma implementation "apt-pkg/pkgcache.h" #pragma implementation "apt-pkg/cacheiterators.h" #endif + #include #include #include #include +#include +#include + #include #include #include @@ -48,7 +52,7 @@ pkgCache::Header::Header() whenever the generator changes the minor version should be bumped. */ MajorVersion = 3; MinorVersion = 5; - Dirty = true; + Dirty = false; HeaderSz = sizeof(pkgCache::Header); PackageSz = sizeof(pkgCache::Package); @@ -68,6 +72,8 @@ pkgCache::Header::Header() FileList = 0; StringList = 0; + VerSysName = 0; + Architecture = 0; memset(HashTable,0,sizeof(HashTable)); memset(Pools,0,sizeof(Pools)); } @@ -92,9 +98,10 @@ bool pkgCache::Header::CheckSizes(Header &Against) const // Cache::pkgCache - Constructor /*{{{*/ // --------------------------------------------------------------------- /* */ -pkgCache::pkgCache(MMap &Map) : Map(Map) +pkgCache::pkgCache(MMap *Map, bool DoMap) : Map(*Map) { - ReMap(); + if (DoMap == true) + ReMap(); } /*}}}*/ // Cache::ReMap - Reopen the cache file /*{{{*/ @@ -113,20 +120,29 @@ bool pkgCache::ReMap() StringItemP = (StringItem *)Map.Data(); StrP = (char *)Map.Data(); - if (Map.Size() == 0) - return false; + if (Map.Size() == 0 || HeaderP == 0) + return _error->Error(_("Empty package cache")); // Check the header Header DefHeader; if (HeaderP->Signature != DefHeader.Signature || HeaderP->Dirty == true) - return _error->Error("The package cache file is corrupted"); + return _error->Error(_("The package cache file is corrupted")); if (HeaderP->MajorVersion != DefHeader.MajorVersion || HeaderP->MinorVersion != DefHeader.MinorVersion || HeaderP->CheckSizes(DefHeader) == false) - return _error->Error("The package cache file is an incompatible version"); - + return _error->Error(_("The package cache file is an incompatible version")); + + // Locate our VS.. + if (HeaderP->VerSysName == 0 || + (VS = pkgVersioningSystem::GetVS(StrP + HeaderP->VerSysName)) == 0) + return _error->Error(_("This APT does not support the Versioning System '%s'"),StrP + HeaderP->VerSysName); + + // Chcek the arhcitecture + if (HeaderP->Architecture == 0 || + _config->Find("APT::Architecture") != StrP + HeaderP->Architecture) + return _error->Error(_("The package cache was build for a different architecture")); return true; } /*}}}*/ @@ -168,54 +184,55 @@ pkgCache::PkgIterator pkgCache::FindPkg(string Name) return PkgIterator(*this,0); } /*}}}*/ +// Cache::CompTypeDeb - Return a string describing the compare type /*{{{*/ +// --------------------------------------------------------------------- +/* This returns a string representation of the dependency compare + type in the weird debian style.. */ +const char *pkgCache::CompTypeDeb(unsigned char Comp) +{ + const char *Ops[] = {"","<=",">=","<<",">>","=","!="}; + if ((unsigned)(Comp & 0xF) < 7) + return Ops[Comp & 0xF]; + return ""; +} + /*}}}*/ +// Cache::CompType - Return a string describing the compare type /*{{{*/ +// --------------------------------------------------------------------- +/* This returns a string representation of the dependency compare + type */ +const char *pkgCache::CompType(unsigned char Comp) +{ + const char *Ops[] = {"","<=",">=","<",">","=","!="}; + if ((unsigned)(Comp & 0xF) < 7) + return Ops[Comp & 0xF]; + return ""; +} + /*}}}*/ +// Cache::DepType - Return a string describing the dep type /*{{{*/ +// --------------------------------------------------------------------- +/* */ +const char *pkgCache::DepType(unsigned char Type) +{ + const char *Types[] = {"",_("Depends"),_("PreDepends"),_("Suggests"), + _("Recommends"),_("Conflicts"),_("Replaces"), + _("Obsoletes")}; + if (Type < 8) + return Types[Type]; + return ""; +} + /*}}}*/ // Cache::Priority - Convert a priority value to a string /*{{{*/ // --------------------------------------------------------------------- /* */ const char *pkgCache::Priority(unsigned char Prio) { - const char *Mapping[] = {0,"important","required","standard","optional","extra"}; + const char *Mapping[] = {0,_("important"),_("required"),_("standard"), + _("optional"),_("extra")}; if (Prio < _count(Mapping)) return Mapping[Prio]; return 0; } /*}}}*/ -// Cache::GetCandidateVer - Returns the Candidate install version /*{{{*/ -// --------------------------------------------------------------------- -/* The default just returns the highest available version that is not - a source and automatic */ -pkgCache::VerIterator pkgCache::GetCandidateVer(PkgIterator Pkg, - bool AllowCurrent) -{ - /* Not source/not automatic versions cannot be a candidate version - unless they are already installed */ - VerIterator Last(*this,0); - - for (VerIterator I = Pkg.VersionList(); I.end() == false; I++) - { - if (Pkg.CurrentVer() == I && AllowCurrent == true) - return I; - - for (VerFileIterator J = I.FileList(); J.end() == false; J++) - { - if ((J.File()->Flags & Flag::NotSource) != 0) - continue; - - /* Stash the highest version of a not-automatic source, we use it - if there is nothing better */ - if ((J.File()->Flags & Flag::NotAutomatic) != 0) - { - if (Last.end() == true) - Last = I; - continue; - } - - return I; - } - } - - return Last; -} - /*}}}*/ // Bases for iterator classes /*{{{*/ void pkgCache::VerIterator::_dummy() {} @@ -230,9 +247,9 @@ void pkgCache::PkgIterator::operator ++(int) // Follow the current links if (Pkg != Owner->PkgP) Pkg = Owner->PkgP + Pkg->NextPackage; - + // Follow the hash table - while (Pkg == Owner->PkgP && HashIndex < (signed)_count(Owner->HeaderP->HashTable)) + while (Pkg == Owner->PkgP && (HashIndex+1) < (signed)_count(Owner->HeaderP->HashTable)) { HashIndex++; Pkg = Owner->PkgP + Owner->HeaderP->HashTable[HashIndex]; @@ -265,7 +282,8 @@ pkgCache::PkgIterator::OkState pkgCache::PkgIterator::State() const conflicts. */ bool pkgCache::DepIterator::IsCritical() { - if (Dep->Type == pkgCache::Dep::Conflicts || + if (Dep->Type == pkgCache::Dep::Conflicts || + Dep->Type == pkgCache::Dep::Obsoletes || Dep->Type == pkgCache::Dep::Depends || Dep->Type == pkgCache::Dep::PreDepends) return true; @@ -280,7 +298,11 @@ bool pkgCache::DepIterator::IsCritical() then it returned. Otherwise the providing list is looked at to see if there is one one unique providing package if so it is returned. Otherwise true is returned and the target package is set. The return - result indicates whether the node should be expandable */ + result indicates whether the node should be expandable + + In Conjunction with the DepCache the value of Result may not be + super-good since the policy may have made it uninstallable. Using + AllTargets is better in this case. */ bool pkgCache::DepIterator::SmartTargetPkg(PkgIterator &Result) { Result = TargetPkg(); @@ -314,17 +336,19 @@ bool pkgCache::DepIterator::SmartTargetPkg(PkgIterator &Result) if (PStart.OwnerPkg() != P.OwnerPkg()) break; } + + Result = PStart.OwnerPkg(); // Check for non dups if (P.end() != true) return true; - Result = PStart.OwnerPkg(); + return false; } /*}}}*/ // DepIterator::AllTargets - Returns the set of all possible targets /*{{{*/ // --------------------------------------------------------------------- -/* This is a more usefull version of TargetPkg() that follows versioned +/* This is a more useful version of TargetPkg() that follows versioned provides. It includes every possible package-version that could satisfy the dependency. The last item in the list has a 0. The resulting pointer must be delete [] 'd */ @@ -340,10 +364,11 @@ pkgCache::Version **pkgCache::DepIterator::AllTargets() // Walk along the actual package providing versions for (VerIterator I = DPkg.VersionList(); I.end() == false; I++) { - if (pkgCheckDep(TargetVer(),I.VerStr(),Dep->CompareOp) == false) + if (Owner->VS->CheckDep(I.VerStr(),Dep->CompareOp,TargetVer()) == false) continue; - if (Dep->Type == pkgCache::Dep::Conflicts && + if ((Dep->Type == pkgCache::Dep::Conflicts || + Dep->Type == pkgCache::Dep::Obsoletes) && ParentPkg() == I.ParentPkg()) continue; @@ -355,10 +380,11 @@ pkgCache::Version **pkgCache::DepIterator::AllTargets() // Follow all provides for (PrvIterator I = DPkg.ProvidesList(); I.end() == false; I++) { - if (pkgCheckDep(TargetVer(),I.ProvideVersion(),Dep->CompareOp) == false) + if (Owner->VS->CheckDep(I.ProvideVersion(),Dep->CompareOp,TargetVer()) == false) continue; - if (Dep->Type == pkgCache::Dep::Conflicts && + if ((Dep->Type == pkgCache::Dep::Conflicts || + Dep->Type == pkgCache::Dep::Obsoletes) && ParentPkg() == I.OwnerPkg()) continue; @@ -383,30 +409,6 @@ pkgCache::Version **pkgCache::DepIterator::AllTargets() return Res; } /*}}}*/ -// DepIterator::CompType - Return a string describing the compare type /*{{{*/ -// --------------------------------------------------------------------- -/* This returns a string representation of the dependency compare - type */ -const char *pkgCache::DepIterator::CompType() -{ - const char *Ops[] = {"","<=",">=","<",">","=","!="}; - if ((unsigned)(Dep->CompareOp & 0xF) < 7) - return Ops[Dep->CompareOp & 0xF]; - return ""; -} - /*}}}*/ -// DepIterator::DepType - Return a string describing the dep type /*{{{*/ -// --------------------------------------------------------------------- -/* */ -const char *pkgCache::DepIterator::DepType() -{ - const char *Types[] = {"","Depends","PreDepends","Suggests", - "Recommends","Conflicts","Replaces"}; - if (Dep->Type < 7) - return Types[Dep->Type]; - return ""; -} - /*}}}*/ // DepIterator::GlobOr - Compute an OR group /*{{{*/ // --------------------------------------------------------------------- /* This Takes an iterator, iterates past the current dependency grouping @@ -462,18 +464,6 @@ bool pkgCache::VerIterator::Downloadable() const return false; } /*}}}*/ -// VerIterator::PriorityType - Return a string describing the priority /*{{{*/ -// --------------------------------------------------------------------- -/* */ -const char *pkgCache::VerIterator::PriorityType() -{ - const char *Types[] = {"","Important","Required","Standard", - "Optional","Extra"}; - if (Ver->Priority < 6) - return Types[Ver->Priority]; - return ""; -} - /*}}}*/ // VerIterator::Automatic - Check if this version is 'automatic' /*{{{*/ // --------------------------------------------------------------------- /* This checks to see if any of the versions files are not NotAutomatic. @@ -497,13 +487,80 @@ pkgCache::VerFileIterator pkgCache::VerIterator::NewestFile() const VerFileIterator Highest = Files; for (; Files.end() == false; Files++) { - if (pkgVersionCompare(Files.File().Version(),Highest.File().Version()) > 0) + if (Owner->VS->CmpReleaseVer(Files.File().Version(),Highest.File().Version()) > 0) Highest = Files; } return Highest; } /*}}}*/ +// VerIterator::RelStr - Release description string /*{{{*/ +// --------------------------------------------------------------------- +/* This describes the version from a release-centric manner. The output is a + list of Label:Version/Archive */ +string pkgCache::VerIterator::RelStr() +{ + bool First = true; + string Res; + for (pkgCache::VerFileIterator I = this->FileList(); I.end() == false; I++) + { + // Do not print 'not source' entries' + pkgCache::PkgFileIterator File = I.File(); + if ((File->Flags & pkgCache::Flag::NotSource) == pkgCache::Flag::NotSource) + continue; + + // See if we have already printed this out.. + bool Seen = false; + for (pkgCache::VerFileIterator J = this->FileList(); I != J; J++) + { + pkgCache::PkgFileIterator File2 = J.File(); + if (File2->Label == 0 || File->Label == 0) + continue; + + if (strcmp(File.Label(),File2.Label()) != 0) + continue; + + if (File2->Version == File->Version) + { + Seen = true; + break; + } + if (File2->Version == 0) + break; + if (strcmp(File.Version(),File2.Version()) == 0) + Seen = true; + } + + if (Seen == true) + continue; + + if (First == false) + Res += ", "; + else + First = false; + + if (File->Label != 0) + Res = Res + File.Label() + ':'; + + if (File->Archive != 0) + { + if (File->Version == 0) + Res += File.Archive(); + else + Res = Res + File.Version() + '/' + File.Archive(); + } + else + { + // No release file, print the host name that this came from + if (File->Site == 0 || File.Site()[0] == 0) + Res += "localhost"; + else + Res += File.Site(); + } + } + return Res; +} + /*}}}*/ // PkgFileIterator::IsOk - Checks if the cache is in sync with the file /*{{{*/ // --------------------------------------------------------------------- /* This stats the file and compares its stats with the ones that were diff --git a/apt-pkg/pkgcache.h b/apt-pkg/pkgcache.h index 4d2401570..f2b1c39fa 100644 --- a/apt-pkg/pkgcache.h +++ b/apt-pkg/pkgcache.h @@ -1,6 +1,6 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ -// $Id: pkgcache.h,v 1.22 1999/07/30 02:54:25 jgg Exp $ +// $Id: pkgcache.h,v 1.23 2001/02/20 07:03:17 jgg Exp $ /* ###################################################################### Cache - Structure definitions for the cache file @@ -16,7 +16,6 @@ ##################################################################### */ /*}}}*/ -// Header section: pkglib #ifndef PKGLIB_PKGCACHE_H #define PKGLIB_PKGCACHE_H @@ -27,7 +26,8 @@ #include #include #include - + +class pkgVersioningSystem; class pkgCache { public: @@ -48,18 +48,20 @@ class pkgCache class PrvIterator; class PkgFileIterator; class VerFileIterator; - friend PkgIterator; - friend VerIterator; - friend DepIterator; - friend PrvIterator; - friend PkgFileIterator; - friend VerFileIterator; + friend class PkgIterator; + friend class VerIterator; + friend class DepIterator; + friend class PrvIterator; + friend class PkgFileIterator; + friend class VerFileIterator; + + class Namespace; // These are all the constants used in the cache structures struct Dep { enum DepType {Depends=1,PreDepends=2,Suggests=3,Recommends=4, - Conflicts=5,Replaces=6}; + Conflicts=5,Replaces=6,Obsoletes=7}; enum DepCompareOp {Or=0x10,NoOp=0,LessEq=0x1,GreaterEq=0x2,Less=0x3, Greater=0x4,Equals=0x5,NotEquals=0x6}; }; @@ -104,7 +106,8 @@ class pkgCache virtual bool ReMap(); inline bool Sync() {return Map.Sync();}; inline MMap &GetMap() {return Map;}; - + inline void *DataEnd() {return ((unsigned char *)Map.Data()) + Map.Size();}; + // String hashing function (512 range) inline unsigned long Hash(string S) const {return sHash(S);}; inline unsigned long Hash(const char *S) const {return sHash(S);}; @@ -119,9 +122,16 @@ class pkgCache inline PkgIterator PkgEnd(); inline PkgFileIterator FileBegin(); inline PkgFileIterator FileEnd(); - VerIterator GetCandidateVer(PkgIterator Pkg,bool AllowCurrent = true); + + // Make me a function + pkgVersioningSystem *VS; + + // Converters + static const char *CompTypeDeb(unsigned char Comp); + static const char *CompType(unsigned char Comp); + static const char *DepType(unsigned char Dep); - pkgCache(MMap &Map); + pkgCache(MMap *Map,bool DoMap = true); virtual ~pkgCache() {}; }; @@ -154,6 +164,8 @@ struct pkgCache::Header // Offsets map_ptrloc FileList; // struct PackageFile map_ptrloc StringList; // struct StringItem + map_ptrloc VerSysName; // StringTable + map_ptrloc Architecture; // StringTable unsigned long MaxVerFileSize; /* Allocation pools, there should be one of these for each structure @@ -172,9 +184,7 @@ struct pkgCache::Package // Pointers map_ptrloc Name; // Stringtable map_ptrloc VersionList; // Version - map_ptrloc TargetVer; // Version map_ptrloc CurrentVer; // Version - map_ptrloc TargetDist; // StringTable (StringItem) map_ptrloc Section; // StringTable (StringItem) // Linked list @@ -201,6 +211,8 @@ struct pkgCache::PackageFile map_ptrloc Origin; // Stringtable map_ptrloc Label; // Stringtable map_ptrloc Architecture; // Stringtable + map_ptrloc Site; // Stringtable + map_ptrloc IndexType; // Stringtable unsigned long Size; unsigned long Flags; @@ -249,7 +261,7 @@ struct pkgCache::Dependency // Specific types of depends unsigned char Type; unsigned char CompareOp; - unsigned short ID; + unsigned short ID; }; struct pkgCache::Provides @@ -274,8 +286,26 @@ inline pkgCache::PkgIterator pkgCache::PkgBegin() inline pkgCache::PkgIterator pkgCache::PkgEnd() {return PkgIterator(*this,PkgP);}; inline pkgCache::PkgFileIterator pkgCache::FileBegin() - {return PkgFileIterator(*this);}; + {return PkgFileIterator(*this,PkgFileP + HeaderP->FileList);}; inline pkgCache::PkgFileIterator pkgCache::FileEnd() {return PkgFileIterator(*this,PkgFileP);}; +// Oh I wish for Real Name Space Support +class pkgCache::Namespace +{ + public: + + typedef pkgCache::PkgIterator PkgIterator; + typedef pkgCache::VerIterator VerIterator; + typedef pkgCache::DepIterator DepIterator; + typedef pkgCache::PrvIterator PrvIterator; + typedef pkgCache::PkgFileIterator PkgFileIterator; + typedef pkgCache::VerFileIterator VerFileIterator; + typedef pkgCache::Version Version; + typedef pkgCache::Package Package; + typedef pkgCache::Header Header; + typedef pkgCache::Dep Dep; + typedef pkgCache::Flag Flag; +}; + #endif diff --git a/apt-pkg/pkgcachegen.cc b/apt-pkg/pkgcachegen.cc index c3cddd615..2fcccaf4a 100644 --- a/apt-pkg/pkgcachegen.cc +++ b/apt-pkg/pkgcachegen.cc @@ -1,6 +1,6 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ -// $Id: pkgcachegen.cc,v 1.45 2000/01/14 06:26:36 jgg Exp $ +// $Id: pkgcachegen.cc,v 1.46 2001/02/20 07:03:17 jgg Exp $ /* ###################################################################### Package Cache Generator - Generator for the cache structure. @@ -14,15 +14,20 @@ #pragma implementation "apt-pkg/pkgcachegen.h" #endif +#define APT_COMPATIBILITY 986 + #include #include #include #include #include #include -#include #include +#include +#include +#include + #include #include #include @@ -33,23 +38,42 @@ // CacheGenerator::pkgCacheGenerator - Constructor /*{{{*/ // --------------------------------------------------------------------- /* We set the diry flag and make sure that is written to the disk */ -pkgCacheGenerator::pkgCacheGenerator(DynamicMMap &Map,OpProgress &Prog) : - Map(Map), Cache(Map), Progress(&Prog) +pkgCacheGenerator::pkgCacheGenerator(DynamicMMap *pMap,OpProgress *Prog) : + Map(*pMap), Cache(pMap,false), Progress(Prog) { CurrentFile = 0; + memset(UniqHash,0,sizeof(UniqHash)); if (_error->PendingError() == true) return; - + if (Map.Size() == 0) { + // Setup the map interface.. + Cache.HeaderP = (pkgCache::Header *)Map.Data(); Map.RawAllocate(sizeof(pkgCache::Header)); + Map.UsePools(*Cache.HeaderP->Pools,sizeof(Cache.HeaderP->Pools)/sizeof(Cache.HeaderP->Pools[0])); + + // Starting header *Cache.HeaderP = pkgCache::Header(); + Cache.HeaderP->VerSysName = Map.WriteString(_system->VS->Label); + Cache.HeaderP->Architecture = Map.WriteString(_config->Find("APT::Architecture")); + Cache.ReMap(); } + else + { + // Map directly from the existing file + Cache.ReMap(); + Map.UsePools(*Cache.HeaderP->Pools,sizeof(Cache.HeaderP->Pools)/sizeof(Cache.HeaderP->Pools[0])); + if (Cache.VS != _system->VS) + { + _error->Error(_("Cache has an incompatible versioning system")); + return; + } + } + Cache.HeaderP->Dirty = true; Map.Sync(0,sizeof(pkgCache::Header)); - Map.UsePools(*Cache.HeaderP->Pools,sizeof(Cache.HeaderP->Pools)/sizeof(Cache.HeaderP->Pools[0])); - memset(UniqHash,0,sizeof(UniqHash)); } /*}}}*/ // CacheGenerator::~pkgCacheGenerator - Destructor /*{{{*/ @@ -86,7 +110,7 @@ bool pkgCacheGenerator::MergeList(ListParser &List, pkgCache::PkgIterator Pkg; if (NewPackage(Pkg,PackageName) == false) - return _error->Error("Error occured while processing %s (NewPackage)",PackageName.c_str()); + return _error->Error(_("Error occured while processing %s (NewPackage)"),PackageName.c_str()); Counter++; if (Counter % 100 == 0 && Progress != 0) Progress->Progress(List.Offset()); @@ -98,7 +122,7 @@ bool pkgCacheGenerator::MergeList(ListParser &List, if (Version.empty() == true) { if (List.UsePackage(Pkg,pkgCache::VerIterator(Cache)) == false) - return _error->Error("Error occured while processing %s (UsePackage1)",PackageName.c_str()); + return _error->Error(_("Error occured while processing %s (UsePackage1)"),PackageName.c_str()); continue; } @@ -107,7 +131,7 @@ bool pkgCacheGenerator::MergeList(ListParser &List, int Res = 1; for (; Ver.end() == false; Last = &Ver->NextVer, Ver++) { - Res = pkgVersionCompare(Version.begin(),Version.end(),Ver.VerStr(), + Res = Cache.VS->DoCmpVersion(Version.begin(),Version.end(),Ver.VerStr(), Ver.VerStr() + strlen(Ver.VerStr())); if (Res >= 0) break; @@ -119,10 +143,10 @@ bool pkgCacheGenerator::MergeList(ListParser &List, if (Res == 0 && Ver->Hash == Hash) { if (List.UsePackage(Pkg,Ver) == false) - return _error->Error("Error occured while processing %s (UsePackage2)",PackageName.c_str()); + return _error->Error(_("Error occured while processing %s (UsePackage2)"),PackageName.c_str()); if (NewFileVer(Ver,List) == false) - return _error->Error("Error occured while processing %s (NewFileVer1)",PackageName.c_str()); + return _error->Error(_("Error occured while processing %s (NewFileVer1)"),PackageName.c_str()); // Read only a single record and return if (OutVer != 0) @@ -139,7 +163,7 @@ bool pkgCacheGenerator::MergeList(ListParser &List, { for (; Ver.end() == false; Last = &Ver->NextVer, Ver++) { - Res = pkgVersionCompare(Version.begin(),Version.end(),Ver.VerStr(), + Res = Cache.VS->DoCmpVersion(Version.begin(),Version.end(),Ver.VerStr(), Ver.VerStr() + strlen(Ver.VerStr())); if (Res != 0) break; @@ -151,13 +175,13 @@ bool pkgCacheGenerator::MergeList(ListParser &List, Ver->ParentPkg = Pkg.Index(); Ver->Hash = Hash; if (List.NewVersion(Ver) == false) - return _error->Error("Error occured while processing %s (NewVersion1)",PackageName.c_str()); + return _error->Error(_("Error occured while processing %s (NewVersion1)"),PackageName.c_str()); if (List.UsePackage(Pkg,Ver) == false) - return _error->Error("Error occured while processing %s (UsePackage3)",PackageName.c_str()); + return _error->Error(_("Error occured while processing %s (UsePackage3)"),PackageName.c_str()); if (NewFileVer(Ver,List) == false) - return _error->Error("Error occured while processing %s (NewVersion2)",PackageName.c_str()); + return _error->Error(_("Error occured while processing %s (NewVersion2)"),PackageName.c_str()); // Read only a single record and return if (OutVer != 0) @@ -288,7 +312,7 @@ bool pkgCacheGenerator::ListParser::NewDepends(pkgCache::VerIterator Ver, // Probe the reverse dependency list for a version string that matches if (Version.empty() == false) { -/* for (pkgCache::DepIterator I = Pkg.RevDependsList(); I.end() == false; I++, Hit++) +/* for (pkgCache::DepIterator I = Pkg.RevDependsList(); I.end() == false; I++) if (I->Version != 0 && I.TargetVer() == Version) Dep->Version = I->Version;*/ if (Dep->Version == 0) @@ -342,7 +366,7 @@ bool pkgCacheGenerator::ListParser::NewProvides(pkgCache::VerIterator Ver, Prv->Version = Ver.Index(); Prv->NextPkgProv = Ver->ProvidesList; Ver->ProvidesList = Prv.Index(); - if (Version.empty() == false && (Prv->Version = WriteString(Version)) == 0) + if (Version.empty() == false && (Prv->ProvideVersion = WriteString(Version)) == 0) return false; // Locate the target package @@ -361,13 +385,11 @@ bool pkgCacheGenerator::ListParser::NewProvides(pkgCache::VerIterator Ver, // CacheGenerator::SelectFile - Select the current file being parsed /*{{{*/ // --------------------------------------------------------------------- /* This is used to select which file is to be associated with all newly - added versions. */ -bool pkgCacheGenerator::SelectFile(string File,unsigned long Flags) + added versions. The caller is responsible for setting the IMS fields. */ +bool pkgCacheGenerator::SelectFile(string File,string Site, + const pkgIndexFile &Index, + unsigned long Flags) { - struct stat Buf; - if (stat(File.c_str(),&Buf) == -1) - return _error->Errno("stat","Couldn't stat ",File.c_str()); - // Get some space for the structure CurrentFile = Cache.PkgFileP + Map.Allocate(sizeof(*CurrentFile)); if (CurrentFile == Cache.PkgFileP) @@ -375,20 +397,20 @@ bool pkgCacheGenerator::SelectFile(string File,unsigned long Flags) // Fill it in CurrentFile->FileName = Map.WriteString(File); - CurrentFile->Size = Buf.st_size; - CurrentFile->mtime = Buf.st_mtime; + CurrentFile->Site = WriteUniqString(Site); CurrentFile->NextFile = Cache.HeaderP->FileList; CurrentFile->Flags = Flags; CurrentFile->ID = Cache.HeaderP->PackageFileCount; + CurrentFile->IndexType = WriteUniqString(Index.GetType()->Label); PkgFileName = File; Cache.HeaderP->FileList = CurrentFile - Cache.PkgFileP; Cache.HeaderP->PackageFileCount++; - + if (CurrentFile->FileName == 0) return false; if (Progress != 0) - Progress->SubProgress(Buf.st_size); + Progress->SubProgress(Index.Size()); return true; } /*}}}*/ @@ -443,491 +465,279 @@ unsigned long pkgCacheGenerator::WriteUniqString(const char *S, } /*}}}*/ -// SrcCacheCheck - Check if the source package cache is uptodate /*{{{*/ +// CheckValidity - Check that a cache is up-to-date /*{{{*/ // --------------------------------------------------------------------- -/* The source cache is checked against the source list and the files - on disk, any difference results in a false. */ -bool pkgSrcCacheCheck(pkgSourceList &List) +/* This just verifies that each file in the list of index files exists, + has matching attributes with the cache and the cache does not have + any extra files. */ +static bool CheckValidity(string CacheFile,pkgIndexFile **Start, + pkgIndexFile **End,MMap **OutMap = 0) { - if (_error->PendingError() == true) - return false; - - string CacheFile = _config->FindFile("Dir::Cache::srcpkgcache"); - string ListDir = _config->FindDir("Dir::State::lists"); - - // Count the number of missing files - int Missing = 0; - for (pkgSourceList::const_iterator I = List.begin(); I != List.end(); I++) - { - // Only cache deb source types. - if (I->Type != pkgSourceList::Item::Deb) - { - Missing++; - continue; - } - - string File = ListDir + URItoFileName(I->PackagesURI()); - struct stat Buf; - if (stat(File.c_str(),&Buf) != 0) - { - // Old format file name.. rename it - if (File[0] == '_' && stat(File.c_str()+1,&Buf) == 0) - { - if (rename(File.c_str()+1,File.c_str()) != 0) - return _error->Errno("rename","Failed to rename %s to %s", - File.c_str()+1,File.c_str()); - continue; - } - - _error->WarningE("stat","Couldn't stat source package list '%s' (%s)", - I->PackagesInfo().c_str(),File.c_str()); - Missing++; - } - } - - // Open the source package cache - if (FileExists(CacheFile) == false) + // No file, certainly invalid + if (CacheFile.empty() == true || FileExists(CacheFile) == false) return false; + // Map it FileFd CacheF(CacheFile,FileFd::ReadOnly); - if (_error->PendingError() == true) - { - _error->Discard(); - return false; - } - - MMap Map(CacheF,MMap::Public | MMap::ReadOnly); - if (_error->PendingError() == true || Map.Size() == 0) - { - _error->Discard(); - return false; - } - + SPtr Map = new MMap(CacheF,MMap::Public | MMap::ReadOnly); pkgCache Cache(Map); - if (_error->PendingError() == true) + if (_error->PendingError() == true || Map->Size() == 0) { _error->Discard(); return false; } - - // They are certianly out of sync - if (Cache.Head().PackageFileCount != List.size() - Missing) - return false; - for (pkgCache::PkgFileIterator F(Cache); F.end() == false; F++) - { - // Search for a match in the source list - bool Bad = true; - for (pkgSourceList::const_iterator I = List.begin(); - I != List.end(); I++) + /* Now we check every index file, see if it is in the cache, + verify the IMS data and check that it is on the disk too.. */ + SPtrArray Visited = new bool[Cache.HeaderP->PackageFileCount]; + memset(Visited,0,sizeof(*Visited)*Cache.HeaderP->PackageFileCount); + for (; Start != End; Start++) + { + if ((*Start)->HasPackages() == false) + continue; + + if ((*Start)->Exists() == false) { - // Only cache deb source types. - if (I->Type != pkgSourceList::Item::Deb) - continue; - - string File = ListDir + URItoFileName(I->PackagesURI()); - if (F.FileName() == File) - { - Bad = false; - break; - } + _error->WarningE("stat",_("Couldn't stat source package list %s"), + (*Start)->Describe().c_str()); + continue; } - - // Check if the file matches what was cached - Bad |= !F.IsOk(); - if (Bad == true) + + // FindInCache is also expected to do an IMS check. + pkgCache::PkgFileIterator File = (*Start)->FindInCache(Cache); + if (File.end() == true) return false; + + Visited[File->ID] = true; } - return true; -} - /*}}}*/ -// PkgCacheCheck - Check if the package cache is uptodate /*{{{*/ -// --------------------------------------------------------------------- -/* This does a simple check of all files used to compose the cache */ -bool pkgPkgCacheCheck(string CacheFile) -{ - if (_error->PendingError() == true) - return false; - - // Open the source package cache - if (FileExists(CacheFile) == false) - return false; - - FileFd CacheF(CacheFile,FileFd::ReadOnly); - if (_error->PendingError() == true) - { - _error->Discard(); - return false; - } - - MMap Map(CacheF,MMap::Public | MMap::ReadOnly); - if (_error->PendingError() == true || Map.Size() == 0) - { - _error->Discard(); - return false; - } + for (unsigned I = 0; I != Cache.HeaderP->PackageFileCount; I++) + if (Visited[I] == false) + return false; - pkgCache Cache(Map); if (_error->PendingError() == true) { _error->Discard(); return false; } - - // Status files that must be in the cache - string Status[3]; - Status[0] = _config->FindFile("Dir::State::xstatus"); - Status[1]= _config->FindFile("Dir::State::userstatus"); - Status[2] = _config->FindFile("Dir::State::status"); - - // Cheack each file - for (pkgCache::PkgFileIterator F(Cache); F.end() == false; F++) - { - if (F.IsOk() == false) - return false; - - // See if this is one of the status files - for (int I = 0; I != 3; I++) - if (F.FileName() == Status[I]) - Status[I] = string(); - } - - // Make sure all the status files are loaded. - for (int I = 0; I != 3; I++) - { - if (Status[I].empty() == false && FileExists(Status[I]) == true) - return false; - } - - return true; -} - /*}}}*/ -// AddStatusSize - Add the size of the status files /*{{{*/ -// --------------------------------------------------------------------- -/* This adds the size of all the status files to the size counter */ -bool pkgAddStatusSize(unsigned long &TotalSize) -{ - // Grab the file names - string xstatus = _config->FindFile("Dir::State::xstatus"); - string userstatus = _config->FindFile("Dir::State::userstatus"); - string status = _config->FindFile("Dir::State::status"); - - // Grab the sizes - struct stat Buf; - if (stat(xstatus.c_str(),&Buf) == 0) - TotalSize += Buf.st_size; - if (stat(userstatus.c_str(),&Buf) == 0) - TotalSize += Buf.st_size; - if (stat(status.c_str(),&Buf) != 0) - return _error->Errno("stat","Couldn't stat the status file %s",status.c_str()); - TotalSize += Buf.st_size; + if (OutMap != 0) + *OutMap = Map.UnGuard(); return true; } /*}}}*/ -// MergeStatus - Add the status files to the cache /*{{{*/ +// ComputeSize - Compute the total size of a bunch of files /*{{{*/ // --------------------------------------------------------------------- -/* This adds the status files to the map */ -bool pkgMergeStatus(OpProgress &Progress,pkgCacheGenerator &Gen, - unsigned long &CurrentSize,unsigned long TotalSize) +/* Size is kind of an abstract notion that is only used for the progress + meter */ +static unsigned long ComputeSize(pkgIndexFile **Start,pkgIndexFile **End) { - // Grab the file names - string Status[3]; - Status[0] = _config->FindFile("Dir::State::xstatus"); - Status[1]= _config->FindFile("Dir::State::userstatus"); - Status[2] = _config->FindFile("Dir::State::status"); - - for (int I = 0; I != 3; I++) + unsigned long TotalSize = 0; + for (; Start != End; Start++) { - // Check if the file exists and it is not the primary status file. - string File = Status[I]; - if (I != 2 && FileExists(File) == false) - continue; - - FileFd Pkg(File,FileFd::ReadOnly); - debListParser Parser(Pkg); - Progress.OverallProgress(CurrentSize,TotalSize,Pkg.Size(),"Reading Package Lists"); - if (_error->PendingError() == true) - return _error->Error("Problem opening %s",File.c_str()); - CurrentSize += Pkg.Size(); - - Progress.SubProgress(0,"Local Package State - " + flNotDir(File)); - if (Gen.SelectFile(File,pkgCache::Flag::NotSource) == false) - return _error->Error("Problem with SelectFile %s",File.c_str()); - - if (Gen.MergeList(Parser) == false) - return _error->Error("Problem with MergeList %s",File.c_str()); - Progress.Progress(Pkg.Size()); + if ((*Start)->HasPackages() == false) + continue; + TotalSize += (*Start)->Size(); } - - return true; + return TotalSize; } /*}}}*/ -// GenerateSrcCache - Write the source package lists to the map /*{{{*/ +// BuildCache - Merge the list of index files into the cache /*{{{*/ // --------------------------------------------------------------------- -/* This puts the source package cache into the given generator. */ -bool pkgGenerateSrcCache(pkgSourceList &List,OpProgress &Progress, - pkgCacheGenerator &Gen, - unsigned long &CurrentSize,unsigned long &TotalSize) +/* */ +static bool BuildCache(pkgCacheGenerator &Gen, + OpProgress &Progress, + unsigned long &CurrentSize,unsigned long TotalSize, + pkgIndexFile **Start,pkgIndexFile **End) { - string ListDir = _config->FindDir("Dir::State::lists"); - - // Prepare the progress indicator - TotalSize = 0; - struct stat Buf; - for (pkgSourceList::const_iterator I = List.begin(); I != List.end(); I++) - { - string File = ListDir + URItoFileName(I->PackagesURI()); - if (stat(File.c_str(),&Buf) != 0) - continue; - TotalSize += Buf.st_size; - } - - if (pkgAddStatusSize(TotalSize) == false) - return false; - - // Generate the pkg source cache - CurrentSize = 0; - for (pkgSourceList::const_iterator I = List.begin(); I != List.end(); I++) + for (; Start != End; Start++) { - // Only cache deb source types. - if (I->Type != pkgSourceList::Item::Deb) + if ((*Start)->HasPackages() == false) continue; - string File = ListDir + URItoFileName(I->PackagesURI()); - - if (FileExists(File) == false) + if ((*Start)->Exists() == false) continue; + + unsigned long Size = (*Start)->Size(); + Progress.OverallProgress(CurrentSize,TotalSize,Size,_("Reading Package Lists")); + CurrentSize += Size; - FileFd Pkg(File,FileFd::ReadOnly); - debListParser Parser(Pkg); - Progress.OverallProgress(CurrentSize,TotalSize,Pkg.Size(),"Reading Package Lists"); - if (_error->PendingError() == true) - return _error->Error("Problem opening %s",File.c_str()); - CurrentSize += Pkg.Size(); - - Progress.SubProgress(0,I->PackagesInfo()); - if (Gen.SelectFile(File) == false) - return _error->Error("Problem with SelectFile %s",File.c_str()); - - if (Gen.MergeList(Parser) == false) - return _error->Error("Problem with MergeList %s",File.c_str()); - - // Check the release file - string RFile = ListDir + URItoFileName(I->ReleaseURI()); - if (FileExists(RFile) == true) - { - FileFd Rel(RFile,FileFd::ReadOnly); - if (_error->PendingError() == true) - return false; - Parser.LoadReleaseInfo(Gen.GetCurFile(),Rel); - } - } + if ((*Start)->Merge(Gen,Progress) == false) + return false; + } return true; } /*}}}*/ -// MakeStatusCache - Generates a cache that includes the status files /*{{{*/ +// MakeStatusCache - Construct the status cache /*{{{*/ // --------------------------------------------------------------------- -/* This copies the package source cache and then merges the status and - xstatus files into it. */ -bool pkgMakeStatusCache(pkgSourceList &List,OpProgress &Progress) +/* This makes sure that the status cache (the cache that has all + index files from the sources list and all local ones) is ready + to be mmaped. If OutMap is not zero then a MMap object representing + the cache will be stored there. This is pretty much mandetory if you + are using AllowMem. AllowMem lets the function be run as non-root + where it builds the cache 'fast' into a memory buffer. */ +bool pkgMakeStatusCache(pkgSourceList &List,OpProgress &Progress, + MMap **OutMap,bool AllowMem) { unsigned long MapSize = _config->FindI("APT::Cache-Limit",4*1024*1024); - Progress.OverallProgress(0,1,1,"Reading Package Lists"); + vector Files(List.begin(),List.end()); + unsigned long EndOfSource = Files.size(); + if (_system->AddStatusFiles(Files) == false) + return false; + // Decide if we can write to the files.. string CacheFile = _config->FindFile("Dir::Cache::pkgcache"); - bool SrcOk = pkgSrcCacheCheck(List); - bool PkgOk = SrcOk && pkgPkgCacheCheck(CacheFile); - - // Rebuild the source and package caches - if (SrcOk == false) - { - string SCacheFile = _config->FindFile("Dir::Cache::srcpkgcache"); - FileFd SCacheF(SCacheFile,FileFd::WriteEmpty); - - /* Open the pkgcache, we want a new inode here so we do no corrupt - existing mmaps */ - unlink(CacheFile.c_str()); - FileFd CacheF(CacheFile,FileFd::WriteEmpty); - DynamicMMap Map(CacheF,MMap::Public,MapSize); + string SrcCacheFile = _config->FindFile("Dir::Cache::srcpkgcache"); + + // Decide if we can write to the cache + bool Writeable = false; + if (CacheFile.empty() == false) + Writeable = access(flNotFile(CacheFile).c_str(),W_OK) == 0; + else + if (SrcCacheFile.empty() == false) + Writeable = access(flNotFile(SrcCacheFile).c_str(),W_OK) == 0; + + if (Writeable == false && AllowMem == false && CacheFile.empty() == false) + return _error->Error(_("Unable to write to %s"),flNotFile(CacheFile).c_str()); + + Progress.OverallProgress(0,1,1,_("Reading Package Lists")); + + // Cache is OK, Fin. + if (CheckValidity(CacheFile,Files.begin(),Files.end(),OutMap) == true) + { + Progress.OverallProgress(1,1,1,_("Reading Package Lists")); + return true; + } + + /* At this point we know we need to reconstruct the package cache, + begin. */ + SPtr CacheF; + SPtr Map; + if (Writeable == true && CacheFile.empty() == false) + { + unlink(CacheFile.c_str()); + CacheF = new FileFd(CacheFile,FileFd::WriteEmpty); + Map = new DynamicMMap(*CacheF,MMap::Public,MapSize); if (_error->PendingError() == true) return false; - - pkgCacheGenerator Gen(Map,Progress); - unsigned long CurrentSize = 0; - unsigned long TotalSize = 0; - if (pkgGenerateSrcCache(List,Progress,Gen,CurrentSize,TotalSize) == false) - return false; - - // Write the src cache - Gen.GetCache().HeaderP->Dirty = false; - if (SCacheF.Write(Map.Data(),Map.Size()) == false) - return _error->Error("IO Error saving source cache"); - Gen.GetCache().HeaderP->Dirty = true; - - // Merge in the source caches - return pkgMergeStatus(Progress,Gen,CurrentSize,TotalSize); } - - if (PkgOk == true) + else { - Progress.OverallProgress(1,1,1,"Reading Package Lists"); - return true; + // Just build it in memory.. + Map = new DynamicMMap(MMap::Public,MapSize); } - // We use the source cache to generate the package cache - string SCacheFile = _config->FindFile("Dir::Cache::srcpkgcache"); - FileFd SCacheF(SCacheFile,FileFd::ReadOnly); - - /* Open the pkgcache, we want a new inode here so we do no corrupt - existing mmaps */ - unlink(CacheFile.c_str()); - FileFd CacheF(CacheFile,FileFd::WriteEmpty); - DynamicMMap Map(CacheF,MMap::Public,MapSize); - if (_error->PendingError() == true) - return false; - - // Preload the map with the source cache - if (SCacheF.Read((unsigned char *)Map.Data() + Map.RawAllocate(SCacheF.Size()), - SCacheF.Size()) == false) - return false; - - pkgCacheGenerator Gen(Map,Progress); - - // Compute the progress - unsigned long TotalSize = 0; - if (pkgAddStatusSize(TotalSize) == false) - return false; - + // Lets try the source cache. unsigned long CurrentSize = 0; - return pkgMergeStatus(Progress,Gen,CurrentSize,TotalSize); -} - /*}}}*/ -// MakeStatusCacheMem - Returns a map for the status cache /*{{{*/ -// --------------------------------------------------------------------- -/* This creates a map object for the status cache. If the process has write - access to the caches then it is the same as MakeStatusCache, otherwise it - creates a memory block and puts the cache in there. */ -MMap *pkgMakeStatusCacheMem(pkgSourceList &List,OpProgress &Progress) -{ - unsigned long MapSize = _config->FindI("APT::Cache-Limit",4*1024*1024); - - /* If the cache file is writeable this is just a wrapper for - MakeStatusCache */ - string CacheFile = _config->FindFile("Dir::Cache::pkgcache"); - bool Writeable = (access(CacheFile.c_str(),W_OK) == 0) || - (errno == ENOENT); - - if (Writeable == true) + unsigned long TotalSize = 0; + if (CheckValidity(SrcCacheFile,Files.begin(), + Files.begin()+EndOfSource) == true) { - if (pkgMakeStatusCache(List,Progress) == false) - return 0; - - // Open the cache file - FileFd File(_config->FindFile("Dir::Cache::pkgcache"),FileFd::ReadOnly); - if (_error->PendingError() == true) - return 0; + // Preload the map with the source cache + FileFd SCacheF(SrcCacheFile,FileFd::ReadOnly); + if (SCacheF.Read((unsigned char *)Map->Data() + Map->RawAllocate(SCacheF.Size()), + SCacheF.Size()) == false) + return false; + + TotalSize = ComputeSize(Files.begin()+EndOfSource,Files.end()); - MMap *Map = new MMap(File,MMap::Public | MMap::ReadOnly); + // Build the status cache + pkgCacheGenerator Gen(Map.Get(),&Progress); if (_error->PendingError() == true) - { - delete Map; - return 0; - } - return Map; - } - - // Mostly from MakeStatusCache.. - Progress.OverallProgress(0,1,1,"Reading Package Lists"); - - bool SrcOk = pkgSrcCacheCheck(List); - bool PkgOk = SrcOk && pkgPkgCacheCheck(CacheFile); - - // Rebuild the source and package caches - if (SrcOk == false) + return false; + if (BuildCache(Gen,Progress,CurrentSize,TotalSize, + Files.begin()+EndOfSource,Files.end()) == false) + return false; + } + else { - DynamicMMap *Map = new DynamicMMap(MMap::Public,MapSize); - if (_error->PendingError() == true) - { - delete Map; - return 0; - } + TotalSize = ComputeSize(Files.begin(),Files.end()); - pkgCacheGenerator Gen(*Map,Progress); - unsigned long CurrentSize = 0; - unsigned long TotalSize = 0; - if (pkgGenerateSrcCache(List,Progress,Gen,CurrentSize,TotalSize) == false) - { - delete Map; - return 0; - } + // Build the source cache + pkgCacheGenerator Gen(Map.Get(),&Progress); + if (_error->PendingError() == true) + return false; + if (BuildCache(Gen,Progress,CurrentSize,TotalSize, + Files.begin(),Files.begin()+EndOfSource) == false) + return false; - // Merge in the source caches - if (pkgMergeStatus(Progress,Gen,CurrentSize,TotalSize) == false) + // Write it back + if (Writeable == true && SrcCacheFile.empty() == false) { - delete Map; - return 0; + FileFd SCacheF(SrcCacheFile,FileFd::WriteEmpty); + if (_error->PendingError() == true) + return false; + // Write out the main data + if (SCacheF.Write(Map->Data(),Map->Size()) == false) + return _error->Error(_("IO Error saving source cache")); + SCacheF.Sync(); + + // Write out the proper header + Gen.GetCache().HeaderP->Dirty = false; + if (SCacheF.Seek(0) == false || + SCacheF.Write(Map->Data(),sizeof(*Gen.GetCache().HeaderP)) == false) + return _error->Error(_("IO Error saving source cache")); + SCacheF.Sync(); + Gen.GetCache().HeaderP->Dirty = true; } - return Map; + // Build the status cache + if (BuildCache(Gen,Progress,CurrentSize,TotalSize, + Files.begin()+EndOfSource,Files.end()) == false) + return false; } - if (PkgOk == true) + if (_error->PendingError() == true) + return false; + if (OutMap != 0) { - Progress.OverallProgress(1,1,1,"Reading Package Lists"); - - // Open the cache file - FileFd File(_config->FindFile("Dir::Cache::pkgcache"),FileFd::ReadOnly); - if (_error->PendingError() == true) - return 0; - - MMap *Map = new MMap(File,MMap::Public | MMap::ReadOnly); - if (_error->PendingError() == true) + if (CacheF != 0) { - delete Map; - return 0; + delete Map.UnGuard(); + *OutMap = new MMap(*CacheF,MMap::Public | MMap::ReadOnly); } - return Map; + else + { + *OutMap = Map.UnGuard(); + } } - // We use the source cache to generate the package cache - string SCacheFile = _config->FindFile("Dir::Cache::srcpkgcache"); - FileFd SCacheF(SCacheFile,FileFd::ReadOnly); - DynamicMMap *Map = new DynamicMMap(MMap::Public,MapSize); + return true; +} + /*}}}*/ +// MakeOnlyStatusCache - Build a cache with just the status files /*{{{*/ +// --------------------------------------------------------------------- +/* */ +bool pkgMakeOnlyStatusCache(OpProgress &Progress,DynamicMMap **OutMap) +{ + unsigned long MapSize = _config->FindI("APT::Cache-Limit",4*1024*1024); + vector Files; + unsigned long EndOfSource = Files.size(); + if (_system->AddStatusFiles(Files) == false) + return false; + + SPtr Map; + Map = new DynamicMMap(MMap::Public,MapSize); + unsigned long CurrentSize = 0; + unsigned long TotalSize = 0; + + TotalSize = ComputeSize(Files.begin()+EndOfSource,Files.end()); + + // Build the status cache + Progress.OverallProgress(0,1,1,_("Reading Package Lists")); + pkgCacheGenerator Gen(Map.Get(),&Progress); if (_error->PendingError() == true) - { - delete Map; - return 0; - } + return false; + if (BuildCache(Gen,Progress,CurrentSize,TotalSize, + Files.begin()+EndOfSource,Files.end()) == false) + return false; - // Preload the map with the source cache - if (SCacheF.Read((unsigned char *)Map->Data() + Map->RawAllocate(SCacheF.Size()), - SCacheF.Size()) == false) - { - delete Map; - return 0; - } - - pkgCacheGenerator Gen(*Map,Progress); + if (_error->PendingError() == true) + return false; + *OutMap = Map.UnGuard(); - // Compute the progress - unsigned long TotalSize = 0; - if (pkgAddStatusSize(TotalSize) == false) - { - delete Map; - return 0; - } - - unsigned long CurrentSize = 0; - if (pkgMergeStatus(Progress,Gen,CurrentSize,TotalSize) == false) - { - delete Map; - return 0; - } - - return Map; + return true; } /*}}}*/ diff --git a/apt-pkg/pkgcachegen.h b/apt-pkg/pkgcachegen.h index f264b314d..7a8c784ff 100644 --- a/apt-pkg/pkgcachegen.h +++ b/apt-pkg/pkgcachegen.h @@ -1,6 +1,6 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ -// $Id: pkgcachegen.h,v 1.17 1999/07/26 17:46:08 jgg Exp $ +// $Id: pkgcachegen.h,v 1.18 2001/02/20 07:03:17 jgg Exp $ /* ###################################################################### Package Cache Generator - Generator for the cache structure. @@ -16,7 +16,6 @@ ##################################################################### */ /*}}}*/ -// Header section: pkglib #ifndef PKGLIB_PKGCACHEGEN_H #define PKGLIB_PKGCACHEGEN_H @@ -29,6 +28,7 @@ class pkgSourceList; class OpProgress; class MMap; +class pkgIndexFile; class pkgCacheGenerator { @@ -39,7 +39,7 @@ class pkgCacheGenerator public: class ListParser; - friend ListParser; + friend class ListParser; protected: @@ -54,32 +54,28 @@ class pkgCacheGenerator bool NewFileVer(pkgCache::VerIterator &Ver,ListParser &List); unsigned long NewVersion(pkgCache::VerIterator &Ver,string VerStr,unsigned long Next); + public: + unsigned long WriteUniqString(const char *S,unsigned int Size); inline unsigned long WriteUniqString(string S) {return WriteUniqString(S.c_str(),S.length());}; - public: - void DropProgress() {Progress = 0;}; - bool SelectFile(string File,unsigned long Flags = 0); + bool SelectFile(string File,string Site,pkgIndexFile const &Index, + unsigned long Flags = 0); bool MergeList(ListParser &List,pkgCache::VerIterator *Ver = 0); inline pkgCache &GetCache() {return Cache;}; inline pkgCache::PkgFileIterator GetCurFile() {return pkgCache::PkgFileIterator(Cache,CurrentFile);}; - pkgCacheGenerator(DynamicMMap &Map,OpProgress &Progress); + pkgCacheGenerator(DynamicMMap *Map,OpProgress *Progress); ~pkgCacheGenerator(); }; -bool pkgSrcCacheCheck(pkgSourceList &List); -bool pkgPkgCacheCheck(string CacheFile); -bool pkgMakeStatusCache(pkgSourceList &List,OpProgress &Progress); -MMap *pkgMakeStatusCacheMem(pkgSourceList &List,OpProgress &Progress); - // This is the abstract package list parser class. class pkgCacheGenerator::ListParser { pkgCacheGenerator *Owner; - friend pkgCacheGenerator; + friend class pkgCacheGenerator; // Some cache items pkgCache::VerIterator OldDepVer; @@ -113,8 +109,21 @@ class pkgCacheGenerator::ListParser virtual ~ListParser() {}; }; -bool pkgMergeStatus(OpProgress &Progress,pkgCacheGenerator &Gen, - unsigned long &CurrentSize,unsigned long TotalSize); -bool pkgAddStatusSize(unsigned long &TotalSize); +bool pkgMakeStatusCache(pkgSourceList &List,OpProgress &Progress, + MMap **OutMap = 0,bool AllowMem = false); +bool pkgMakeOnlyStatusCache(OpProgress &Progress,DynamicMMap **OutMap); + +#ifdef APT_COMPATIBILITY +#if APT_COMPATIBILITY != 986 +#warning "Using APT_COMPATIBILITY" +#endif +MMap *pkgMakeStatusCacheMem(pkgSourceList &List,OpProgress &Progress) +{ + MMap *Map = 0; + if (pkgMakeStatusCache(List,Progress,&Map,true) == false) + return 0; + return Map; +} +#endif #endif diff --git a/apt-pkg/pkgrecords.cc b/apt-pkg/pkgrecords.cc index 5d112a5c1..69aac6622 100644 --- a/apt-pkg/pkgrecords.cc +++ b/apt-pkg/pkgrecords.cc @@ -1,6 +1,6 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ -// $Id: pkgrecords.cc,v 1.5 1999/02/22 03:30:06 jgg Exp $ +// $Id: pkgrecords.cc,v 1.6 2001/02/20 07:03:17 jgg Exp $ /* ###################################################################### Package Records - Allows access to complete package description records @@ -13,9 +13,11 @@ #pragma implementation "apt-pkg/pkgrecords.h" #endif #include -#include +#include #include #include + +#include /*}}}*/ // Records::pkgRecords - Constructor /*{{{*/ @@ -23,25 +25,21 @@ /* This will create the necessary structures to access the status files */ pkgRecords::pkgRecords(pkgCache &Cache) : Cache(Cache), Files(0) { - Files = new PkgFile[Cache.HeaderP->PackageFileCount]; + Files = new Parser *[Cache.HeaderP->PackageFileCount]; + memset(Files,0,sizeof(*Files)*Cache.HeaderP->PackageFileCount); + for (pkgCache::PkgFileIterator I = Cache.FileBegin(); I.end() == false; I++) { - // We can not initialize if the cache is out of sync. - if (I.IsOk() == false) + const pkgIndexFile::Type *Type = pkgIndexFile::Type::GetType(I.IndexType()); + if (Type == 0) { - _error->Error("Package file %s is out of sync.",I.FileName()); + _error->Error(_("Index file type '%s' is not supported"),I.IndexType()); return; } - - // Create the file - Files[I->ID].File = new FileFd(I.FileName(),FileFd::ReadOnly); - if (_error->PendingError() == true) - return; - - // Create the parser - Files[I->ID].Parse = new debRecordParser(*Files[I->ID].File,Cache); - if (_error->PendingError() == true) + + Files[I->ID] = Type->CreatePkgParser(I); + if (Files[I->ID] == 0) return; } } @@ -51,6 +49,8 @@ pkgRecords::pkgRecords(pkgCache &Cache) : Cache(Cache), Files(0) /* */ pkgRecords::~pkgRecords() { + for (unsigned I = 0; I != Cache.HeaderP->PackageFileCount; I++) + delete Files[I]; delete [] Files; } /*}}}*/ @@ -59,18 +59,7 @@ pkgRecords::~pkgRecords() /* */ pkgRecords::Parser &pkgRecords::Lookup(pkgCache::VerFileIterator const &Ver) { - PkgFile &File = Files[Ver.File()->ID]; - File.Parse->Jump(Ver); - - return *File.Parse; -} - /*}}}*/ -// Records::Pkgfile::~PkgFile - Destructor /*{{{*/ -// --------------------------------------------------------------------- -/* */ -pkgRecords::PkgFile::~PkgFile() -{ - delete Parse; - delete File; + Files[Ver.File()->ID]->Jump(Ver); + return *Files[Ver.File()->ID]; } /*}}}*/ diff --git a/apt-pkg/pkgrecords.h b/apt-pkg/pkgrecords.h index b5205f1ac..af5fac646 100644 --- a/apt-pkg/pkgrecords.h +++ b/apt-pkg/pkgrecords.h @@ -1,6 +1,6 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ -// $Id: pkgrecords.h,v 1.4 1999/04/07 05:30:17 jgg Exp $ +// $Id: pkgrecords.h,v 1.5 2001/02/20 07:03:17 jgg Exp $ /* ###################################################################### Package Records - Allows access to complete package description records @@ -14,7 +14,6 @@ ##################################################################### */ /*}}}*/ -// Header section: pkglib #ifndef PKGLIB_PKGRECORDS_H #define PKGLIB_PKGRECORDS_H @@ -33,18 +32,8 @@ class pkgRecords private: pkgCache &Cache; - - // List of package files - struct PkgFile - { - FileFd *File; - Parser *Parse; - - PkgFile() : File(0), Parse(0) {}; - ~PkgFile(); - }; - PkgFile *Files; - + Parser **Files; + public: // Lookup function @@ -62,18 +51,22 @@ class pkgRecords::Parser virtual bool Jump(pkgCache::VerFileIterator const &Ver) = 0; public: - friend pkgRecords; + friend class pkgRecords; // These refer to the archive file for the Version virtual string FileName() {return string();}; virtual string MD5Hash() {return string();}; virtual string SourcePkg() {return string();}; - + // These are some general stats about the package virtual string Maintainer() {return string();}; virtual string ShortDesc() {return string();}; virtual string LongDesc() {return string();}; - + virtual string Name() {return string();}; + + // The record in binary form + virtual void GetRec(const char *&Start,const char *&Stop) {Start = Stop = 0;}; + virtual ~Parser() {}; }; diff --git a/apt-pkg/pkgsystem.cc b/apt-pkg/pkgsystem.cc new file mode 100644 index 000000000..530f69c91 --- /dev/null +++ b/apt-pkg/pkgsystem.cc @@ -0,0 +1,45 @@ +// -*- mode: cpp; mode: fold -*- +// Description /*{{{*/ +// $Id: pkgsystem.cc,v 1.2 2001/02/20 07:03:17 jgg Exp $ +/* ###################################################################### + + System - Abstraction for running on different systems. + + Basic general structure.. + + ##################################################################### */ + /*}}}*/ +// Include Files /*{{{*/ +#ifdef __GNUG__ +#pragma implementation "apt-pkg/pkgsystem.h" +#endif + +#include +#include + /*}}}*/ + +pkgSystem *_system = 0; +static pkgSystem *SysList[10]; +pkgSystem **pkgSystem::GlobalList = SysList; +unsigned long pkgSystem::GlobalListLen = 0; + +// System::pkgSystem - Constructor /*{{{*/ +// --------------------------------------------------------------------- +/* Add it to the global list.. */ +pkgSystem::pkgSystem() +{ + SysList[GlobalListLen] = this; + GlobalListLen++; +} + /*}}}*/ +// System::GetSystem - Get the named system /*{{{*/ +// --------------------------------------------------------------------- +/* */ +pkgSystem *pkgSystem::GetSystem(const char *Label) +{ + for (unsigned I = 0; I != GlobalListLen; I++) + if (strcmp(SysList[I]->Label,Label) == 0) + return SysList[I]; + return 0; +} + /*}}}*/ diff --git a/apt-pkg/pkgsystem.h b/apt-pkg/pkgsystem.h new file mode 100644 index 000000000..7d0e42d13 --- /dev/null +++ b/apt-pkg/pkgsystem.h @@ -0,0 +1,95 @@ +// -*- mode: cpp; mode: fold -*- +// Description /*{{{*/ +// $Id: pkgsystem.h,v 1.2 2001/02/20 07:03:17 jgg Exp $ +/* ###################################################################### + + System - Abstraction for running on different systems. + + Instances of this class can be thought of as factories or meta-classes + for a variety of more specialized classes. Together this class and + it's speciallized offspring completely define the environment and how + to access resources for a specific system. There are several sub + areas that are all orthogonal - each system has a unique combination of + these sub areas: + - Versioning. Different systems have different ideas on versions. + Within a system all sub classes must follow the same versioning + rules. + - Local tool locking to prevent multiple tools from accessing the + same database. + - Candidate Version selection policy - this is probably almost always + managed using a standard APT class + - Actual Package installation + * Indication of what kind of binary formats are supported + - Selection of local 'status' indexes that make up the pkgCache. + + It is important to note that the handling of index files is not a + function of the system. Index files are handled through a seperate + abstraction - the only requirement is that the index files have the + same idea of versioning as the target system. + + Upon startup each supported system instantiates an instance of the + pkgSystem class (using a global constructor) which will make itself + available to the main APT init routine. That routine will select the + proper system and make it the global default. + + ##################################################################### */ + /*}}}*/ +#ifndef PKGLIB_PKGSYSTEM_H +#define PKGLIB_PKGSYSTEM_H + +#ifdef __GNUG__ +#pragma interface "apt-pkg/pkgsystem.h" +#endif + +#include +#include + +class pkgPackageManager; +class pkgVersioningSystem; +class Configuration; +class pkgIndexFile; + +class pkgSystem +{ + public: + + // Global list of supported systems + static pkgSystem **GlobalList; + static unsigned long GlobalListLen; + static pkgSystem *GetSystem(const char *Label); + + const char *Label; + pkgVersioningSystem *VS; + + /* Prevent other programs from touching shared data not covered by + other locks (cache or state locks) */ + virtual bool Lock() = 0; + virtual bool UnLock(bool NoErrors = false) = 0; + + /* Various helper classes to interface with specific bits of this + environment */ + virtual pkgPackageManager *CreatePM(pkgDepCache *Cache) const = 0; + + /* Load environment specific configuration and perform any other setup + necessary */ + virtual bool Initialize(Configuration &Cnf) {return true;}; + + /* Type is some kind of Globally Unique way of differentiating + archive file types.. */ + virtual bool ArchiveSupported(const char *Type) = 0; + + // Return a list of system index files.. + virtual bool AddStatusFiles(vector &List) = 0; + + /* Evauluate how 'right' we are for this system based on the filesystem + etc.. */ + virtual signed Score(Configuration const &Cnf) {return 0;}; + + pkgSystem(); + virtual ~pkgSystem() {}; +}; + +// The environment we are operating in. +extern pkgSystem *_system; + +#endif diff --git a/apt-pkg/policy.cc b/apt-pkg/policy.cc new file mode 100644 index 000000000..029a37df7 --- /dev/null +++ b/apt-pkg/policy.cc @@ -0,0 +1,275 @@ +// -*- mode: cpp; mode: fold -*- +// Description /*{{{*/ +// $Id: policy.cc,v 1.2 2001/02/20 07:03:17 jgg Exp $ +/* ###################################################################### + + Package Version Policy implementation + + This is just a really simple wrapper around pkgVersionMatch with + some added goodies to manage the list of things.. + + Priority Table: + + 1000 -> inf = Downgradeable priorities + 1000 = The 'no downgrade' pseduo-status file + 100 -> 1000 = Standard priorities + 990 = Config file override package files + 989 = Start for preference auto-priorities + 500 = Default package files + 100 = The status file + 0 -> 100 = NotAutomatic sources like experimental + -inf -> 0 = Never selected + + ##################################################################### */ + /*}}}*/ +// Include Files /*{{{*/ +#ifdef __GNUG__ +#pragma implementation "apt-pkg/policy.h" +#endif +#include +#include +#include +#include +#include +#include + +#include + /*}}}*/ + +// Policy::Init - Startup and bind to a cache /*{{{*/ +// --------------------------------------------------------------------- +/* Set the defaults for operation. The default mode with no loaded policy + file matches the V0 policy engine. */ +pkgPolicy::pkgPolicy(pkgCache *Owner) : Pins(0), PFPriority(0), Cache(Owner) +{ + PFPriority = new signed short[Owner->Head().PackageFileCount]; + Pins = new Pin[Owner->Head().PackageCount]; + + for (unsigned long I = 0; I != Owner->Head().PackageCount; I++) + Pins[I].Type = pkgVersionMatch::None; + + // The config file has a master override. + string DefRel = _config->Find("APT::Default-Release"); + if (DefRel.empty() == false) + CreatePin(pkgVersionMatch::Release,"",DefRel,990); + + InitDefaults(); +} + /*}}}*/ +// Policy::InitDefaults - Compute the default selections /*{{{*/ +// --------------------------------------------------------------------- +/* */ +bool pkgPolicy::InitDefaults() +{ + // Initialize the priorities based on the status of the package file + for (pkgCache::PkgFileIterator I = Cache->FileBegin(); I != Cache->FileEnd(); I++) + { + PFPriority[I->ID] = 500; + if ((I->Flags & pkgCache::Flag::NotSource) == pkgCache::Flag::NotSource) + PFPriority[I->ID] = 100; + else + if ((I->Flags & pkgCache::Flag::NotAutomatic) == pkgCache::Flag::NotAutomatic) + PFPriority[I->ID] = 1; + } + + // Apply the defaults.. + SPtr Fixed = new bool[Cache->HeaderP->PackageFileCount]; + memset(Fixed,0,sizeof(*Fixed)*Cache->HeaderP->PackageFileCount); + signed Cur = 989; + StatusOverride = false; + for (vector::const_iterator I = Defaults.begin(); I != Defaults.end(); + I++, Cur--) + { + pkgVersionMatch Match(I->Data,I->Type); + for (pkgCache::PkgFileIterator F = Cache->FileBegin(); F != Cache->FileEnd(); F++) + { +/* hmm? + if ((F->Flags & pkgCache::Flag::NotSource) == pkgCache::Flag::NotSource) + continue;*/ + + if (Match.FileMatch(F) == true && Fixed[F->ID] == false) + { + if (I->Priority != 0 && I->Priority > 0) + Cur = I->Priority; + + if (I->Priority < 0) + PFPriority[F->ID] = I->Priority; + else + PFPriority[F->ID] = Cur; + + if (PFPriority[F->ID] > 1000) + StatusOverride = true; + + Fixed[F->ID] = true; + } + } + } + + if (_config->FindB("Debug::pkgPolicy",false) == true) + for (pkgCache::PkgFileIterator F = Cache->FileBegin(); F != Cache->FileEnd(); F++) + cout << "Prio of " << F.FileName() << ' ' << PFPriority[F->ID] << endl; + + return true; +} + /*}}}*/ +// Policy::GetCandidateVer - Get the candidate install version /*{{{*/ +// --------------------------------------------------------------------- +/* Evaluate the package pins and the default list to deteremine what the + best package is. */ +pkgCache::VerIterator pkgPolicy::GetCandidateVer(pkgCache::PkgIterator Pkg) +{ + const Pin &PPkg = Pins[Pkg->ID]; + + // Look for a package pin and evaluate it. + signed Max = 0; + pkgCache::VerIterator Pref(*Cache); + if (PPkg.Type != pkgVersionMatch::None) + { + pkgVersionMatch Match(PPkg.Data,PPkg.Type); + Pref = Match.Find(Pkg); + Max = PPkg.Priority; + if (PPkg.Priority == 0) + Max = 989; + } + + /* Falling through to the default version.. Setting Max to zero + effectively excludes everything <= 0 which are the non-automatic + priorities.. The status file is given a prio of 100 which will exclude + not-automatic sources, except in a single shot not-installed mode. + The second pseduo-status file is at prio 1000, above which will permit + the user to force-downgrade things. + + The user pin is subject to the same priority rules as default + selections. Thus there are two ways to create a pin - a pin that + tracks the default when the default is taken away, and a permanent + pin that stays at that setting. + */ + for (pkgCache::VerIterator Ver = Pkg.VersionList(); Ver.end() == false; Ver++) + { + for (pkgCache::VerFileIterator VF = Ver.FileList(); VF.end() == false; VF++) + { + signed Prio = PFPriority[VF.File()->ID]; + if (Prio > Max) + { + Pref = Ver; + Max = Prio; + } + } + + if (Pkg.CurrentVer() == Ver && Max < 1000) + { + /* Elevate our current selection (or the status file itself) + to the Pseudo-status priority. */ + if (Pref.end() == true) + Pref = Ver; + Max = 1000; + + // Fast path optimize. + if (StatusOverride == false) + break; + } + } + + return Pref; +} + /*}}}*/ +// Policy::CreatePin - Create an entry in the pin table.. /*{{{*/ +// --------------------------------------------------------------------- +/* For performance we have 3 tables, the default table, the main cache + table (hashed to the cache). A blank package name indicates the pin + belongs to the default table. Order of insertion matters here, the + earlier defaults override later ones. */ +void pkgPolicy::CreatePin(pkgVersionMatch::MatchType Type,string Name, + string Data,signed short Priority) +{ + pkgCache::PkgIterator Pkg = Cache->FindPkg(Name); + Pin *P = 0; + + if (Name.empty() == true) + P = Defaults.insert(Defaults.end()); + else + { + // Get a spot to put the pin + if (Pkg.end() == true) + { + // Check the unmatched table + for (vector::iterator I = Unmatched.begin(); + I != Unmatched.end() && P == 0; I++) + if (I->Pkg == Name) + P = I; + + if (P == 0) + P = Unmatched.insert(Unmatched.end()); + } + else + { + P = Pins + Pkg->ID; + } + } + + // Set.. + P->Type = Type; + P->Priority = Priority; + P->Data = Data; +} + /*}}}*/ + +// ReadPinFile - Load the pin file into a Policy /*{{{*/ +// --------------------------------------------------------------------- +/* I'd like to see the preferences file store more than just pin information + but right now that is the only stuff I have to store. Later there will + have to be some kind of combined super parser to get the data into all + the right classes.. */ +bool ReadPinFile(pkgPolicy &Plcy,string File) +{ + if (File.empty() == true) + File = _config->FindFile("Dir::Etc::Preferences"); + + if (FileExists(File) == false) + return true; + + FileFd Fd(File,FileFd::ReadOnly); + pkgTagFile TF(&Fd); + if (_error->PendingError() == true) + return false; + + pkgTagSection Tags; + while (TF.Step(Tags) == true) + { + string Name = Tags.FindS("Package"); + if (Name.empty() == true) + return _error->Error(_("Invalid record in the preferences file, no Package header")); + if (Name == "*") + Name = string(); + + const char *Start; + const char *End; + if (Tags.Find("Pin",Start,End) == false) + continue; + + const char *Word = Start; + for (; Word != End && isspace(*Word) == 0; Word++); + + // Parse the type.. + pkgVersionMatch::MatchType Type; + if (stringcasecmp(Start,Word,"version") == 0 && Name.empty() == false) + Type = pkgVersionMatch::Version; + else if (stringcasecmp(Start,Word,"release") == 0) + Type = pkgVersionMatch::Release; + else if (stringcasecmp(Start,Word,"origin") == 0) + Type = pkgVersionMatch::Origin; + else + { + _error->Warning(_("Did not understand pin type %s"),string(Start,Word).c_str()); + continue; + } + for (; Word != End && isspace(*Word) != 0; Word++); + + Plcy.CreatePin(Type,Name,string(Word,End), + Tags.FindI("Pin-Priority")); + } + + Plcy.InitDefaults(); + return true; +} + /*}}}*/ diff --git a/apt-pkg/policy.h b/apt-pkg/policy.h new file mode 100644 index 000000000..f89916202 --- /dev/null +++ b/apt-pkg/policy.h @@ -0,0 +1,83 @@ +// -*- mode: cpp; mode: fold -*- +// Description /*{{{*/ +// $Id: policy.h,v 1.2 2001/02/20 07:03:17 jgg Exp $ +/* ###################################################################### + + Package Version Policy implementation + + This implements the more advanced 'Version 4' APT policy engine. The + standard 'Version 0' engine is included inside the DepCache which is + it's historical location. + + The V4 engine allows the user to completly control all aspects of + version selection. There are three primary means to choose a version + * Selection by version match + * Selection by Release file match + * Selection by origin server + + Each package may be 'pinned' with a single criteria, which will ultimately + result in the selection of a single version, or no version, for each + package. + + Furthermore, the default selection can be influenced by specifying + the ordering of package files. The order is derived by reading the + package file preferences and assigning a priority to each package + file. + + A special flag may be set to indicate if no version should be returned + if no matching versions are found, otherwise the default matching + rules are used to locate a hit. + + ##################################################################### */ + /*}}}*/ +#ifndef PKGLIB_POLICY_H +#define PKGLIB_POLICY_H + +#ifdef __GNUG__ +#pragma interface "apt-pkg/policy.h" +#endif + +#include +#include +#include + +class pkgPolicy : public pkgDepCache::Policy +{ + struct Pin + { + pkgVersionMatch::MatchType Type; + string Data; + signed short Priority; + Pin() : Type(pkgVersionMatch::None), Priority(0) {}; + }; + + struct PkgPin : Pin + { + string Pkg; + }; + + protected: + + Pin *Pins; + signed short *PFPriority; + vector Defaults; + vector Unmatched; + pkgCache *Cache; + bool StatusOverride; + + public: + + void CreatePin(pkgVersionMatch::MatchType Type,string Pkg, + string Data,signed short Priority); + + virtual pkgCache::VerIterator GetCandidateVer(pkgCache::PkgIterator Pkg); + virtual bool IsImportantDep(pkgCache::DepIterator Dep) {return pkgDepCache::Policy::IsImportantDep(Dep);}; + bool InitDefaults(); + + pkgPolicy(pkgCache *Owner); + virtual ~pkgPolicy() {delete [] PFPriority; delete [] Pins;}; +}; + +bool ReadPinFile(pkgPolicy &Plcy,string File = ""); + +#endif diff --git a/apt-pkg/sourcelist.cc b/apt-pkg/sourcelist.cc index 1fdbd834e..da7e38f6e 100644 --- a/apt-pkg/sourcelist.cc +++ b/apt-pkg/sourcelist.cc @@ -1,6 +1,6 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ -// $Id: sourcelist.cc,v 1.17 1999/10/17 07:30:23 jgg Exp $ +// $Id: sourcelist.cc,v 1.18 2001/02/20 07:03:17 jgg Exp $ /* ###################################################################### List of Sources @@ -18,10 +18,99 @@ #include #include +#include + #include -#include -#include -#include + /*}}}*/ + +// Global list of Item supported +static pkgSourceList::Type *ItmList[10]; +pkgSourceList::Type **pkgSourceList::Type::GlobalList = ItmList; +unsigned long pkgSourceList::Type::GlobalListLen = 0; + +// Type::Type - Constructor /*{{{*/ +// --------------------------------------------------------------------- +/* Link this to the global list of items*/ +pkgSourceList::Type::Type() +{ + ItmList[GlobalListLen] = this; + GlobalListLen++; +} + /*}}}*/ +// Type::GetType - Get a specific meta for a given type /*{{{*/ +// --------------------------------------------------------------------- +/* */ +pkgSourceList::Type *pkgSourceList::Type::GetType(const char *Type) +{ + for (unsigned I = 0; I != GlobalListLen; I++) + if (strcmp(GlobalList[I]->Name,Type) == 0) + return GlobalList[I]; + return 0; +} + /*}}}*/ +// Type::FixupURI - Normalize the URI and check it.. /*{{{*/ +// --------------------------------------------------------------------- +/* */ +bool pkgSourceList::Type::FixupURI(string &URI) const +{ + if (URI.empty() == true) + return false; + + if (URI.find(':') == string::npos) + return false; + + URI = SubstVar(URI,"$(ARCH)",_config->Find("APT::Architecture")); + + // Make sure that the URN is / postfixed + if (URI[URI.size() - 1] != '/') + URI += '/'; + + return true; +} + /*}}}*/ +// Type::ParseLine - Parse a single line /*{{{*/ +// --------------------------------------------------------------------- +/* This is a generic one that is the 'usual' format for sources.list + Weird types may override this. */ +bool pkgSourceList::Type::ParseLine(vector &List, + const char *Buffer, + unsigned long CurLine, + string File) const +{ + string URI; + string Dist; + string Section; + + if (ParseQuoteWord(Buffer,URI) == false) + return _error->Error(_("Malformed line %lu in source list %s (URI)"),CurLine,File.c_str()); + if (ParseQuoteWord(Buffer,Dist) == false) + return _error->Error(_("Malformed line %lu in source list %s (dist)"),CurLine,File.c_str()); + + if (FixupURI(URI) == false) + return _error->Error(_("Malformed line %lu in source list %s (URI parse)"),CurLine,File.c_str()); + + // Check for an absolute dists specification. + if (Dist.empty() == false && Dist[Dist.size() - 1] == '/') + { + if (ParseQuoteWord(Buffer,Section) == true) + return _error->Error(_("Malformed line %lu in source list %s (Absolute dist)"),CurLine,File.c_str()); + Dist = SubstVar(Dist,"$(ARCH)",_config->Find("APT::Architecture")); + return CreateItem(List,URI,Dist,Section); + } + + // Grab the rest of the dists + if (ParseQuoteWord(Buffer,Section) == false) + return _error->Error(_("Malformed line %lu in source list %s (dist parse)"),CurLine,File.c_str()); + + do + { + if (CreateItem(List,URI,Dist,Section) == false) + return false; + } + while (ParseQuoteWord(Buffer,Section) == true); + + return true; +} /*}}}*/ // SourceList::pkgSourceList - Constructors /*{{{*/ @@ -52,7 +141,7 @@ bool pkgSourceList::Read(string File) // Open the stream for reading ifstream F(File.c_str(),ios::in | ios::nocreate); if (!F != 0) - return _error->Errno("ifstream::ifstream","Opening %s",File.c_str()); + return _error->Errno("ifstream::ifstream",_("Opening %s"),File.c_str()); List.erase(List.begin(),List.end()); char Buffer[300]; @@ -63,318 +152,59 @@ bool pkgSourceList::Read(string File) F.getline(Buffer,sizeof(Buffer)); CurLine++; _strtabexpand(Buffer,sizeof(Buffer)); - _strstrip(Buffer); + + + char *I; + for (I = Buffer; *I != 0 && *I != '#'; I++); + *I = 0; + + const char *C = _strstrip(Buffer); // Comment or blank - if (Buffer[0] == '#' || Buffer[0] == 0) + if (C[0] == '#' || C[0] == 0) continue; - + // Grok it - string Type; - string URI; - Item Itm; - const char *C = Buffer; - if (ParseQuoteWord(C,Type) == false) - return _error->Error("Malformed line %u in source list %s (type)",CurLine,File.c_str()); - if (ParseQuoteWord(C,URI) == false) - return _error->Error("Malformed line %u in source list %s (URI)",CurLine,File.c_str()); - if (ParseQuoteWord(C,Itm.Dist) == false) - return _error->Error("Malformed line %u in source list %s (dist)",CurLine,File.c_str()); - if (Itm.SetType(Type) == false) - return _error->Error("Malformed line %u in source list %s (type parse)",CurLine,File.c_str()); - if (Itm.SetURI(URI) == false) - return _error->Error("Malformed line %u in source list %s (URI parse)",CurLine,File.c_str()); - - // Check for an absolute dists specification. - if (Itm.Dist.empty() == false && Itm.Dist[Itm.Dist.size() - 1] == '/') - { - if (ParseQuoteWord(C,Itm.Section) == true) - return _error->Error("Malformed line %u in source list %s (Absolute dist)",CurLine,File.c_str()); - Itm.Dist = SubstVar(Itm.Dist,"$(ARCH)",_config->Find("APT::Architecture")); - List.push_back(Itm); - continue; - } + string LineType; + if (ParseQuoteWord(C,LineType) == false) + return _error->Error(_("Malformed line %u in source list %s (type)"),CurLine,File.c_str()); - // Grab the rest of the dists - if (ParseQuoteWord(C,Itm.Section) == false) - return _error->Error("Malformed line %u in source list %s (dist parse)",CurLine,File.c_str()); + Type *Parse = Type::GetType(LineType.c_str()); + if (Parse == 0) + return _error->Error(_("Type '%s' is not known in on line %u in source list %s"),LineType.c_str(),CurLine,File.c_str()); - do - { - List.push_back(Itm); - } - while (ParseQuoteWord(C,Itm.Section) == true); + if (Parse->ParseLine(List,C,CurLine,File) == false) + return false; } return true; } /*}}}*/ -// SourceList::Item << - Writes the item to a stream /*{{{*/ -// --------------------------------------------------------------------- -/* This is not suitable for rebuilding the sourcelist file but it good for - debugging. */ -ostream &operator <<(ostream &O,pkgSourceList::Item &Itm) -{ - O << (int)Itm.Type << ' ' << Itm.URI << ' ' << Itm.Dist << ' ' << Itm.Section; - return O; -} - /*}}}*/ -// SourceList::Item::SetType - Sets the distribution type /*{{{*/ +// SourceList::FindIndex - Get the index associated with a file /*{{{*/ // --------------------------------------------------------------------- /* */ -bool pkgSourceList::Item::SetType(string S) +bool pkgSourceList::FindIndex(pkgCache::PkgFileIterator File, + pkgIndexFile *&Found) const { - if (S == "deb") + for (const_iterator I = List.begin(); I != List.end(); I++) { - Type = Deb; - return true; - } - - if (S == "deb-src") - { - Type = DebSrc; - return true; + if ((*I)->FindInCache(*File.Cache()) == File) + { + Found = *I; + return true; + } } - - return false; -} - /*}}}*/ -// SourceList::Item::SetURI - Set the URI /*{{{*/ -// --------------------------------------------------------------------- -/* For simplicity we strip the scheme off the uri */ -bool pkgSourceList::Item::SetURI(string S) -{ - if (S.empty() == true) - return false; - - if (S.find(':') == string::npos) - return false; - - S = SubstVar(S,"$(ARCH)",_config->Find("APT::Architecture")); - // Make sure that the URN is / postfixed - URI = S; - if (URI[URI.size() - 1] != '/') - URI += '/'; - - return true; -} - /*}}}*/ -// SourceList::Item::PackagesURI - Returns a URI to the packages file /*{{{*/ -// --------------------------------------------------------------------- -/* */ -string pkgSourceList::Item::PackagesURI() const -{ - string Res; - switch (Type) - { - case Deb: - if (Dist[Dist.size() - 1] == '/') - { - if (Dist != "/") - Res = URI + Dist; - else - Res = URI; - } - else - Res = URI + "dists/" + Dist + '/' + Section + - "/binary-" + _config->Find("APT::Architecture") + '/'; - - Res += "Packages"; - break; - - case DebSrc: - if (Dist[Dist.size() - 1] == '/') - Res = URI + Dist; - else - Res = URI + "dists/" + Dist + '/' + Section + - "/source/"; - - Res += "Sources"; - break; - }; - return Res; -} - /*}}}*/ -// SourceList::Item::PackagesInfo - Shorter version of the URI /*{{{*/ -// --------------------------------------------------------------------- -/* This is a shorter version that is designed to be < 60 chars or so */ -string pkgSourceList::Item::PackagesInfo() const -{ - string Res; - switch (Type) - { - case Deb: - Res += SiteOnly(URI) + ' '; - if (Dist[Dist.size() - 1] == '/') - { - if (Dist != "/") - Res += Dist; - } - else - Res += Dist + '/' + Section; - - Res += " Packages"; - break; - - case DebSrc: - Res += SiteOnly(URI) + ' '; - if (Dist[Dist.size() - 1] == '/') - Res += Dist; - else - Res += Dist + '/' + Section; - - Res += " Sources"; - break; - }; - return Res; -} - /*}}}*/ -// SourceList::Item::ReleaseURI - Returns a URI to the release file /*{{{*/ -// --------------------------------------------------------------------- -/* */ -string pkgSourceList::Item::ReleaseURI() const -{ - string Res; - switch (Type) - { - case Deb: - if (Dist[Dist.size() - 1] == '/') - { - if (Dist != "/") - Res = URI + Dist; - else - Res = URI; - } - else - Res = URI + "dists/" + Dist + '/' + Section + - "/binary-" + _config->Find("APT::Architecture") + '/'; - - Res += "Release"; - break; - - case DebSrc: - if (Dist[Dist.size() - 1] == '/') - Res = URI + Dist; - else - Res = URI + "dists/" + Dist + '/' + Section + - "/source/"; - - Res += "Release"; - break; - }; - return Res; -} - /*}}}*/ -// SourceList::Item::ReleaseInfo - Shorter version of the URI /*{{{*/ -// --------------------------------------------------------------------- -/* This is a shorter version that is designed to be < 60 chars or so */ -string pkgSourceList::Item::ReleaseInfo() const -{ - string Res; - switch (Type) - { - case Deb: - case DebSrc: - Res += SiteOnly(URI) + ' '; - if (Dist[Dist.size() - 1] == '/') - { - if (Dist != "/") - Res += Dist; - } - else - Res += Dist + '/' + Section; - - Res += " Release"; - break; - }; - return Res; -} - /*}}}*/ -// SourceList::Item::ArchiveInfo - Shorter version of the archive spec /*{{{*/ -// --------------------------------------------------------------------- -/* This is a shorter version that is designed to be < 60 chars or so */ -string pkgSourceList::Item::ArchiveInfo(pkgCache::VerIterator Ver) const -{ - string Res; - switch (Type) - { - case DebSrc: - case Deb: - Res += SiteOnly(URI) + ' '; - if (Dist[Dist.size() - 1] == '/') - { - if (Dist != "/") - Res += Dist; - } - else - Res += Dist + '/' + Section; - - Res += " "; - Res += Ver.ParentPkg().Name(); - Res += " "; - Res += Ver.VerStr(); - - break; - }; - return Res; -} - /*}}}*/ -// SourceList::Item::ArchiveURI - Returns a URI to the given archive /*{{{*/ -// --------------------------------------------------------------------- -/* */ -string pkgSourceList::Item::ArchiveURI(string File) const -{ - string Res; - switch (Type) - { - case Deb: - case DebSrc: - Res = URI + File; - break; - }; - return Res; -} - /*}}}*/ -// SourceList::Item::SourceInfo - Returns an info line for a source /*{{{*/ -// --------------------------------------------------------------------- -/* */ -string pkgSourceList::Item::SourceInfo(string Pkg,string Ver,string Comp) const -{ - string Res; - switch (Type) - { - case DebSrc: - case Deb: - Res += SiteOnly(URI) + ' '; - if (Dist[Dist.size() - 1] == '/') - { - if (Dist != "/") - Res += Dist; - } - else - Res += Dist + '/' + Section; - - Res += " "; - Res += Pkg; - Res += " "; - Res += Ver; - if (Comp.empty() == false) - Res += " (" + Comp + ")"; - break; - }; - return Res; + return false; } /*}}}*/ -// SourceList::Item::SiteOnly - Strip off the path part of a URI /*{{{*/ +// SourceList::GetIndexes - Load the index files into the downloader /*{{{*/ // --------------------------------------------------------------------- /* */ -string pkgSourceList::Item::SiteOnly(string URI) const +bool pkgSourceList::GetIndexes(pkgAcquire *Owner) const { - ::URI U(URI); - U.User = string(); - U.Password = string(); - U.Path = string(); - U.Port = 0; - return U; + for (const_iterator I = List.begin(); I != List.end(); I++) + if ((*I)->GetIndexes(Owner) == false) + return false; + return true; } /*}}}*/ diff --git a/apt-pkg/sourcelist.h b/apt-pkg/sourcelist.h index 37accc5ab..3a6b274f6 100644 --- a/apt-pkg/sourcelist.h +++ b/apt-pkg/sourcelist.h @@ -1,6 +1,6 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ -// $Id: sourcelist.h,v 1.8 1999/04/07 05:30:18 jgg Exp $ +// $Id: sourcelist.h,v 1.9 2001/02/20 07:03:17 jgg Exp $ /* ###################################################################### SourceList - Manage a list of sources @@ -12,18 +12,22 @@ All sources have a type associated with them that defines the layout of the archive. The exact format of the file is documented in files.sgml. + + The types are mapped through a list of type definitions which handle + the actual construction of the type. After loading a source list all + you have is a list of package index files that have the ability + to be Acquired. ##################################################################### */ /*}}}*/ -// Header section: pkglib #ifndef PKGLIB_SOURCELIST_H #define PKGLIB_SOURCELIST_H #include #include -#include #include - +#include + #ifdef __GNUG__ #pragma interface "apt-pkg/sourcelist.h" #endif @@ -33,32 +37,35 @@ class pkgSourceList { public: - /* Each item in the source list, each line can have more than one - item */ - struct Item + // List of supported source list types + class Type { - enum {Deb, DebSrc} Type; - - string URI; - string Dist; - string Section; + public: - bool SetType(string S); - bool SetURI(string S); - string PackagesURI() const; - string PackagesInfo() const; - string ReleaseURI() const; - string ReleaseInfo() const; - string SourceInfo(string Pkg,string Ver,string Comp) const; - string SiteOnly(string URI) const; - string ArchiveInfo(pkgCache::VerIterator Ver) const; - string ArchiveURI(string File) const; + // Global list of Items supported + static Type **GlobalList; + static unsigned long GlobalListLen; + static Type *GetType(const char *Type); + + const char *Name; + const char *Label; + + bool FixupURI(string &URI) const; + virtual bool ParseLine(vector &List, + const char *Buffer, + unsigned long CurLine,string File) const; + virtual bool CreateItem(vector &List,string URI, + string Dist,string Section) const = 0; + + Type(); + virtual ~Type() {}; }; - typedef vector::const_iterator const_iterator; + + typedef vector::const_iterator const_iterator; protected: - vector List; + vector List; public: @@ -71,10 +78,12 @@ class pkgSourceList inline unsigned int size() const {return List.size();}; inline bool empty() const {return List.empty();}; + bool FindIndex(pkgCache::PkgFileIterator File, + pkgIndexFile *&Found) const; + bool GetIndexes(pkgAcquire *Owner) const; + pkgSourceList(); pkgSourceList(string File); }; -ostream &operator <<(ostream &O,pkgSourceList::Item &Itm); - #endif diff --git a/apt-pkg/srcrecords.cc b/apt-pkg/srcrecords.cc index 6da902d98..b9df32e92 100644 --- a/apt-pkg/srcrecords.cc +++ b/apt-pkg/srcrecords.cc @@ -1,6 +1,6 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ -// $Id: srcrecords.cc,v 1.3 1999/10/18 04:15:24 jgg Exp $ +// $Id: srcrecords.cc,v 1.4 2001/02/20 07:03:17 jgg Exp $ /* ###################################################################### Source Package Records - Allows access to source package records @@ -17,9 +17,10 @@ #include #include -#include +#include #include -#include + +#include /*}}}*/ // SrcRecords::pkgSrcRecords - Constructor /*{{{*/ @@ -27,46 +28,28 @@ /* Open all the source index files */ pkgSrcRecords::pkgSrcRecords(pkgSourceList &List) : Files(0), Current(0) { - pkgSourceList::const_iterator I = List.begin(); - - // Count how many items we will need + Files = new Parser *[List.end() - List.begin() + 1]; + unsigned int Count = 0; + pkgSourceList::const_iterator I = List.begin(); for (; I != List.end(); I++) - if (I->Type == pkgSourceList::Item::DebSrc) + { + Files[Count] = (*I)->CreateSrcParser(); + if (_error->PendingError() == true) + return; + if (Files[Count] != 0) Count++; - + } + Files[Count] = 0; + // Doesnt work without any source index files if (Count == 0) { - _error->Error("Sorry, you must put some 'source' uris" - " in your sources.list"); + _error->Error(_("Sorry, you must put some 'source' URIs" + " in your sources.list")); return; } - Files = new Parser *[Count+1]; - memset(Files,0,sizeof(*Files)*(Count+1)); - - // Create the parser objects - Count = 0; - string Dir = _config->FindDir("Dir::State::lists"); - for (I = List.begin(); I != List.end(); I++) - { - if (I->Type != pkgSourceList::Item::DebSrc) - continue; - - // Open the file - FileFd *FD = new FileFd(Dir + URItoFileName(I->PackagesURI()), - FileFd::ReadOnly); - if (_error->PendingError() == true) - { - delete FD; - return; - } - - Files[Count] = new debSrcRecordParser(FD,I); - Count++; - } - Restart(); } /*}}}*/ @@ -81,6 +64,7 @@ pkgSrcRecords::~pkgSrcRecords() // Blow away all the parser objects for (unsigned int Count = 0; Files[Count] != 0; Count++) delete Files[Count]; + delete [] Files; } /*}}}*/ // SrcRecords::Restart - Restart the search /*{{{*/ @@ -136,4 +120,20 @@ pkgSrcRecords::Parser *pkgSrcRecords::Find(const char *Package,bool SrcOnly) } } /*}}}*/ +// Parser::BuildDepType - Convert a build dep to a string /*{{{*/ +// --------------------------------------------------------------------- +/* */ +const char *pkgSrcRecords::Parser::BuildDepType(unsigned char Type) +{ + const char *fields[] = {"Build-Depends", + "Build-Depends-Indep", + "Build-Conflicts", + "Build-Conflicts-Indep"}; + if (Type < 4) + return fields[Type]; + else + return ""; +} + /*}}}*/ + diff --git a/apt-pkg/srcrecords.h b/apt-pkg/srcrecords.h index 8391349dd..a73499aef 100644 --- a/apt-pkg/srcrecords.h +++ b/apt-pkg/srcrecords.h @@ -1,6 +1,6 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ -// $Id: srcrecords.h,v 1.5 1999/10/18 03:44:39 jgg Exp $ +// $Id: srcrecords.h,v 1.6 2001/02/20 07:03:17 jgg Exp $ /* ###################################################################### Source Package Records - Allows access to source package records @@ -17,9 +17,11 @@ #pragma interface "apt-pkg/srcrecords.h" #endif -#include -#include +#include +#include +class pkgSourceList; +class pkgIndexFile; class pkgSrcRecords { public: @@ -30,17 +32,30 @@ class pkgSrcRecords string MD5Hash; unsigned long Size; string Path; + string Type; }; // Abstract parser for each source record class Parser { - FileFd *File; - pkgSourceList::const_iterator SrcItem; + protected: + + const pkgIndexFile *iIndex; public: - inline pkgSourceList::const_iterator Source() const {return SrcItem;}; + enum BuildDep {BuildDepend=0x0,BuildDependIndep=0x1, + BuildConflict=0x2,BuildConflictIndep=0x3}; + + struct BuildDepRec + { + string Package; + string Version; + unsigned int Op; + unsigned char Type; + }; + + inline const pkgIndexFile &Index() const {return *iIndex;}; virtual bool Restart() = 0; virtual bool Step() = 0; @@ -48,16 +63,19 @@ class pkgSrcRecords virtual unsigned long Offset() = 0; virtual string AsStr() = 0; - virtual string Package() = 0; - virtual string Version() = 0; - virtual string Maintainer() = 0; - virtual string Section() = 0; - virtual const char **Binaries() = 0; + virtual string Package() const = 0; + virtual string Version() const = 0; + virtual string Maintainer() const = 0; + virtual string Section() const = 0; + virtual const char **Binaries() = 0; // Ownership does not transfer + + virtual bool BuildDepends(vector &BuildDeps) = 0; + static const char *BuildDepType(unsigned char Type); + virtual bool Files(vector &F) = 0; - Parser(FileFd *File,pkgSourceList::const_iterator SrcItem) : File(File), - SrcItem(SrcItem) {}; - virtual ~Parser() {delete File;}; + Parser(const pkgIndexFile *Index) : iIndex(Index) {}; + virtual ~Parser() {}; }; private: @@ -78,5 +96,4 @@ class pkgSrcRecords ~pkgSrcRecords(); }; - #endif diff --git a/apt-pkg/tagfile.cc b/apt-pkg/tagfile.cc index 97e5c244a..5d1144629 100644 --- a/apt-pkg/tagfile.cc +++ b/apt-pkg/tagfile.cc @@ -1,6 +1,6 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ -// $Id: tagfile.cc,v 1.25 1999/07/03 06:45:40 jgg Exp $ +// $Id: tagfile.cc,v 1.26 2001/02/20 07:03:17 jgg Exp $ /* ###################################################################### Fast scanner for RFC-822 type header information @@ -19,6 +19,8 @@ #include #include +#include + #include #include /*}}}*/ @@ -26,16 +28,17 @@ // TagFile::pkgTagFile - Constructor /*{{{*/ // --------------------------------------------------------------------- /* */ -pkgTagFile::pkgTagFile(FileFd &Fd,unsigned long Size) : Fd(Fd), Size(Size) +pkgTagFile::pkgTagFile(FileFd *pFd,unsigned long Size) : Fd(*pFd), Size(Size) { Buffer = new char[Size]; Start = End = Buffer; Left = Fd.Size(); + TotalSize = Fd.Size(); iOffset = 0; Fill(); } /*}}}*/ -// pkgTagFile::~pkgTagFile - Destructor /*{{{*/ +// TagFile::~pkgTagFile - Destructor /*{{{*/ // --------------------------------------------------------------------- /* */ pkgTagFile::~pkgTagFile() @@ -54,10 +57,12 @@ bool pkgTagFile::Step(pkgTagSection &Tag) return false; if (Tag.Scan(Start,End - Start) == false) - return _error->Error("Unable to parse package file %s (1)",Fd.Name().c_str()); + return _error->Error(_("Unable to parse package file %s (1)"),Fd.Name().c_str()); } Start += Tag.size(); iOffset += Tag.size(); + + Tag.Trim(); return true; } @@ -118,8 +123,18 @@ bool pkgTagFile::Fill() that is there */ bool pkgTagFile::Jump(pkgTagSection &Tag,unsigned long Offset) { + // We are within a buffer space of the next hit.. + if (Offset >= iOffset && iOffset + (End - Start) > Offset) + { + unsigned long Dist = Offset - iOffset; + Start += Dist; + iOffset += Dist; + return Step(Tag); + } + + // Reposition and reload.. iOffset = Offset; - Left = Fd.Size() - Offset; + Left = TotalSize - Offset; if (Fd.Seek(Offset) == false) return false; End = Start = Buffer; @@ -135,10 +150,7 @@ bool pkgTagFile::Jump(pkgTagSection &Tag,unsigned long Offset) return false; if (Tag.Scan(Start,End - Start) == false) - { - cout << string(Start,End) << endl; - return _error->Error("Unable to parse package file %s (2)",Fd.Name().c_str()); - } + return _error->Error(_("Unable to parse package file %s (2)"),Fd.Name().c_str()); return true; } @@ -148,6 +160,14 @@ bool pkgTagFile::Jump(pkgTagSection &Tag,unsigned long Offset) /* This looks for the first double new line in the data stream. It also indexes the tags in the section. This very simple hash function for the first 3 letters gives very good performance on the debian package files */ +inline static unsigned long AlphaHash(const char *Text, const char *End = 0) +{ + unsigned long Res = 0; + for (; Text != End && *Text != ':' && *Text != 0; Text++) + Res = (unsigned long)(*Text) ^ (Res << 2); + return Res & 0xFF; +} + bool pkgTagSection::Scan(const char *Start,unsigned long MaxLength) { const char *End = Start + MaxLength; @@ -164,10 +184,7 @@ bool pkgTagSection::Scan(const char *Start,unsigned long MaxLength) if (isspace(Stop[0]) == 0) { Indexes[TagCount++] = Stop - Section; - unsigned char A = tolower(Stop[0]) - 'a'; - unsigned char B = tolower(Stop[1]) - 'a'; - unsigned char C = tolower(Stop[3]) - 'a'; - AlphaIndexes[((A + C/3)%26) + 26*((B + C/2)%26)] = TagCount; + AlphaIndexes[AlphaHash(Stop,End)] = TagCount; } Stop = (const char *)memchr(Stop,'\n',End - Stop); @@ -191,17 +208,21 @@ bool pkgTagSection::Scan(const char *Start,unsigned long MaxLength) return false; } /*}}}*/ +// TagSection::Trim - Trim off any trailing garbage /*{{{*/ +// --------------------------------------------------------------------- +/* There should be exactly 1 newline at the end of the buffer, no more. */ +void pkgTagSection::Trim() +{ + for (; Stop > Section + 2 && (Stop[-2] == '\n' || Stop[-2] == '\r'); Stop--); +} + /*}}}*/ // TagSection::Find - Locate a tag /*{{{*/ // --------------------------------------------------------------------- /* This searches the section for a tag that matches the given string. */ -bool pkgTagSection::Find(const char *Tag,const char *&Start, - const char *&End) +bool pkgTagSection::Find(const char *Tag,unsigned &Pos) const { unsigned int Length = strlen(Tag); - unsigned char A = tolower(Tag[0]) - 'a'; - unsigned char B = tolower(Tag[1]) - 'a'; - unsigned char C = tolower(Tag[3]) - 'a'; - unsigned int I = AlphaIndexes[((A + C/3)%26) + 26*((B + C/2)%26)]; + unsigned int I = AlphaIndexes[AlphaHash(Tag)]; if (I == 0) return false; I--; @@ -214,6 +235,39 @@ bool pkgTagSection::Find(const char *Tag,const char *&Start, if (strncasecmp(Tag,St,Length) != 0) continue; + // Make sure the colon is in the right place + const char *C = St + Length; + for (; isspace(*C) != 0; C++); + if (*C != ':') + continue; + Pos = I; + return true; + } + + Pos = 0; + return false; +} + /*}}}*/ +// TagSection::Find - Locate a tag /*{{{*/ +// --------------------------------------------------------------------- +/* This searches the section for a tag that matches the given string. */ +bool pkgTagSection::Find(const char *Tag,const char *&Start, + const char *&End) const +{ + unsigned int Length = strlen(Tag); + unsigned int I = AlphaIndexes[AlphaHash(Tag)]; + if (I == 0) + return false; + I--; + + for (unsigned int Counter = 0; Counter != TagCount; Counter++, + I = (I+1)%TagCount) + { + const char *St; + St = Section + Indexes[I]; + if (strncasecmp(Tag,St,Length) != 0) + continue; + // Make sure the colon is in the right place const char *C = St + Length; for (; isspace(*C) != 0; C++); @@ -239,7 +293,7 @@ bool pkgTagSection::Find(const char *Tag,const char *&Start, // TagSection::FindS - Find a string /*{{{*/ // --------------------------------------------------------------------- /* */ -string pkgTagSection::FindS(const char *Tag) +string pkgTagSection::FindS(const char *Tag) const { const char *Start; const char *End; @@ -251,7 +305,7 @@ string pkgTagSection::FindS(const char *Tag) // TagSection::FindI - Find an integer /*{{{*/ // --------------------------------------------------------------------- /* */ -signed int pkgTagSection::FindI(const char *Tag,signed long Default) +signed int pkgTagSection::FindI(const char *Tag,signed long Default) const { const char *Start; const char *Stop; @@ -276,7 +330,7 @@ signed int pkgTagSection::FindI(const char *Tag,signed long Default) // --------------------------------------------------------------------- /* The bits marked in Flag are masked on/off in Flags */ bool pkgTagSection::FindFlag(const char *Tag,unsigned long &Flags, - unsigned long Flag) + unsigned long Flag) const { const char *Start; const char *Stop; @@ -294,9 +348,191 @@ bool pkgTagSection::FindFlag(const char *Tag,unsigned long &Flags, return true; default: - _error->Warning("Unknown flag value"); + _error->Warning("Unknown flag value: %s",string(Start,Stop).c_str()); return true; } return true; } /*}}}*/ + +// TFRewrite - Rewrite a control record /*{{{*/ +// --------------------------------------------------------------------- +/* This writes the control record to stdout rewriting it as necessary. The + override map item specificies the rewriting rules to follow. This also + takes the time to sort the feild list. */ + +/* The order of this list is taken from dpkg source lib/parse.c the fieldinfos + array. */ +static const char *iTFRewritePackageOrder[] = { + "Package", + "Essential", + "Status", + "Priority", + "Section", + "Installed-Size", + "Maintainer", + "Architecture", + "Source", + "Version", + "Revision", // Obsolete + "Config-Version", // Obsolete + "Replaces", + "Provides", + "Depends", + "Pre-Depends", + "Recommends", + "Suggests", + "Conflicts", + "Conffiles", + "Filename", + "Size", + "MD5Sum", + "MSDOS-Filename", // Obsolete + "Description", + 0}; +static const char *iTFRewriteSourceOrder[] = {"Package", + "Source", + "Binary", + "Version", + "Priority", + "Section", + "Maintainer", + "Build-Depends", + "Build-Depends-Indep", + "Build-Conflicts", + "Build-Conflicts-Indep", + "Architecture", + "Standards-Version", + "Format", + "Directory", + "Files", + 0}; + +/* Two levels of initialization are used because gcc will set the symbol + size of an array to the length of the array, causing dynamic relinking + errors. Doing this makes the symbol size constant */ +const char **TFRewritePackageOrder = iTFRewritePackageOrder; +const char **TFRewriteSourceOrder = iTFRewriteSourceOrder; + +bool TFRewrite(FILE *Output,pkgTagSection const &Tags,const char *Order[], + TFRewriteData *Rewrite) +{ + unsigned char Visited[256]; // Bit 1 is Order, Bit 2 is Rewrite + for (unsigned I = 0; I != 256; I++) + Visited[I] = 0; + + // Set new tag up as necessary. + for (unsigned int J = 0; Rewrite != 0 && Rewrite[J].Tag != 0; J++) + { + if (Rewrite[J].NewTag == 0) + Rewrite[J].NewTag = Rewrite[J].Tag; + } + + // Write all all of the tags, in order. + for (unsigned int I = 0; Order[I] != 0; I++) + { + bool Rewritten = false; + + // See if this is a field that needs to be rewritten + for (unsigned int J = 0; Rewrite != 0 && Rewrite[J].Tag != 0; J++) + { + if (strcasecmp(Rewrite[J].Tag,Order[I]) == 0) + { + Visited[J] |= 2; + if (Rewrite[J].Rewrite != 0 && Rewrite[J].Rewrite[0] != 0) + { + if (isspace(Rewrite[J].Rewrite[0])) + fprintf(Output,"%s:%s\n",Rewrite[J].NewTag,Rewrite[J].Rewrite); + else + fprintf(Output,"%s: %s\n",Rewrite[J].NewTag,Rewrite[J].Rewrite); + } + + Rewritten = true; + break; + } + } + + // See if it is in the fragment + unsigned Pos; + if (Tags.Find(Order[I],Pos) == false) + continue; + Visited[Pos] |= 1; + + if (Rewritten == true) + continue; + + /* Write out this element, taking a moment to rewrite the tag + in case of changes of case. */ + const char *Start; + const char *Stop; + Tags.Get(Start,Stop,Pos); + + if (fputs(Order[I],Output) < 0) + return _error->Errno("fputs","IO Error to output"); + Start += strlen(Order[I]); + if (fwrite(Start,Stop - Start,1,Output) != 1) + return _error->Errno("fwrite","IO Error to output"); + if (Stop[-1] != '\n') + fprintf(Output,"\n"); + } + + // Now write all the old tags that were missed. + for (unsigned int I = 0; I != Tags.Count(); I++) + { + if ((Visited[I] & 1) == 1) + continue; + + const char *Start; + const char *Stop; + Tags.Get(Start,Stop,I); + const char *End = Start; + for (; End < Stop && *End != ':'; End++); + + // See if this is a field that needs to be rewritten + bool Rewritten = false; + for (unsigned int J = 0; Rewrite != 0 && Rewrite[J].Tag != 0; J++) + { + if (stringcasecmp(Start,End,Rewrite[J].Tag) == 0) + { + Visited[J] |= 2; + if (Rewrite[J].Rewrite != 0 && Rewrite[J].Rewrite[0] != 0) + { + if (isspace(Rewrite[J].Rewrite[0])) + fprintf(Output,"%s:%s\n",Rewrite[J].NewTag,Rewrite[J].Rewrite); + else + fprintf(Output,"%s: %s\n",Rewrite[J].NewTag,Rewrite[J].Rewrite); + } + + Rewritten = true; + break; + } + } + + if (Rewritten == true) + continue; + + // Write out this element + if (fwrite(Start,Stop - Start,1,Output) != 1) + return _error->Errno("fwrite","IO Error to output"); + if (Stop[-1] != '\n') + fprintf(Output,"\n"); + } + + // Now write all the rewrites that were missed + for (unsigned int J = 0; Rewrite != 0 && Rewrite[J].Tag != 0; J++) + { + if ((Visited[J] & 2) == 2) + continue; + + if (Rewrite[J].Rewrite != 0 && Rewrite[J].Rewrite[0] != 0) + { + if (isspace(Rewrite[J].Rewrite[0])) + fprintf(Output,"%s:%s\n",Rewrite[J].NewTag,Rewrite[J].Rewrite); + else + fprintf(Output,"%s: %s\n",Rewrite[J].NewTag,Rewrite[J].Rewrite); + } + } + + return true; +} + /*}}}*/ diff --git a/apt-pkg/tagfile.h b/apt-pkg/tagfile.h index 84998629d..948adb426 100644 --- a/apt-pkg/tagfile.h +++ b/apt-pkg/tagfile.h @@ -1,12 +1,12 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ -// $Id: tagfile.h,v 1.14 1999/07/03 06:45:40 jgg Exp $ +// $Id: tagfile.h,v 1.15 2001/02/20 07:03:17 jgg Exp $ /* ###################################################################### Fast scanner for RFC-822 type header information This parser handles Debian package files (and others). Their form is - RFC-822 type header fields in groups seperated by a blank line. + RFC-822 type header fields in groups separated by a blank line. The parser reads the file and provides methods to step linearly over it or to jump to a pre-recorded start point and read that record. @@ -17,7 +17,6 @@ ##################################################################### */ /*}}}*/ -// Header section: pkglib #ifndef PKGLIB_TAGFILE_H #define PKGLIB_TAGFILE_H @@ -26,7 +25,8 @@ #endif #include - +#include + class pkgTagSection { const char *Section; @@ -34,7 +34,7 @@ class pkgTagSection // We have a limit of 256 tags per section. unsigned short Indexes[256]; - unsigned short AlphaIndexes[26 + 26*26]; + unsigned short AlphaIndexes[0xff]; unsigned int TagCount; @@ -43,19 +43,21 @@ class pkgTagSection inline bool operator ==(const pkgTagSection &rhs) {return Section == rhs.Section;}; inline bool operator !=(const pkgTagSection &rhs) {return Section != rhs.Section;}; - bool Find(const char *Tag,const char *&Start, const char *&End); - string FindS(const char *Tag); - signed int FindI(const char *Tag,signed long Default = 0); + bool Find(const char *Tag,const char *&Start, const char *&End) const; + bool Find(const char *Tag,unsigned &Pos) const; + string FindS(const char *Tag) const; + signed int FindI(const char *Tag,signed long Default = 0) const ; bool pkgTagSection::FindFlag(const char *Tag,unsigned long &Flags, - unsigned long Flag); + unsigned long Flag) const; bool Scan(const char *Start,unsigned long MaxLength); - inline unsigned long size() {return Stop - Section;}; - - inline unsigned int Count() {return TagCount;}; - inline void Get(const char *&Start,const char *&Stop,unsigned int I) + inline unsigned long size() const {return Stop - Section;}; + void Trim(); + + inline unsigned int Count() const {return TagCount;}; + inline void Get(const char *&Start,const char *&Stop,unsigned int I) const {Start = Section + Indexes[I]; Stop = Section + Indexes[I+1];} - inline void GetSection(const char *&Start,const char *&Stop) + inline void GetSection(const char *&Start,const char *&Stop) const { Start = Section; Stop = this->Stop; @@ -73,6 +75,7 @@ class pkgTagFile unsigned long Left; unsigned long iOffset; unsigned long Size; + unsigned long TotalSize; bool Fill(); @@ -82,8 +85,24 @@ class pkgTagFile inline unsigned long Offset() {return iOffset;}; bool Jump(pkgTagSection &Tag,unsigned long Offset); - pkgTagFile(FileFd &F,unsigned long Size = 32*1024); + pkgTagFile(FileFd *F,unsigned long Size = 32*1024); ~pkgTagFile(); }; +/* This is the list of things to rewrite. The rewriter + goes through and changes or adds each of these headers + to suit. A zero forces the header to be erased, an empty string + causes the old value to be used. (rewrite rule ignored) */ +struct TFRewriteData +{ + const char *Tag; + const char *Rewrite; + const char *NewTag; +}; +extern const char **TFRewritePackageOrder; +extern const char **TFRewriteSourceOrder; + +bool TFRewrite(FILE *Output,pkgTagSection const &Tags,const char *Order[], + TFRewriteData *Rewrite); + #endif diff --git a/apt-pkg/version.cc b/apt-pkg/version.cc index 4aad581f8..db340c11f 100644 --- a/apt-pkg/version.cc +++ b/apt-pkg/version.cc @@ -1,18 +1,9 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ -// $Id: version.cc,v 1.9 1999/04/19 06:03:09 jgg Exp $ +// $Id: version.cc,v 1.10 2001/02/20 07:03:17 jgg Exp $ /* ###################################################################### - Version - Version string - - Version comparing is done using the == and < operators. STL's - function.h provides the remaining set of comparitors. A directly - callable non-string class version is provided for functions manipulating - the cache file (esp the sort function). - - A version is defined to be equal if a case sensitive compare returns - that the two strings are the same. For compatibility with the QSort - function this version returns -1,0,1. + Version - Versioning system.. ##################################################################### */ /*}}}*/ @@ -26,246 +17,28 @@ #include /*}}}*/ + +static pkgVersioningSystem *VSList[10]; +pkgVersioningSystem **pkgVersioningSystem::GlobalList = VSList; +unsigned long pkgVersioningSystem::GlobalListLen = 0; -// StrToLong - Convert the string between two iterators to a long /*{{{*/ +// pkgVS::pkgVersioningSystem - Constructor /*{{{*/ // --------------------------------------------------------------------- -/* */ -static unsigned long StrToLong(const char *begin,const char *end) +/* Link to the global list of versioning systems supported */ +pkgVersioningSystem::pkgVersioningSystem() { - char S[40]; - char *I = S; - for (; begin != end && I < S + 40;) - *I++ = *begin++; - *I = 0; - return strtoul(S,0,10); + VSList[GlobalListLen] = this; + GlobalListLen++; } /*}}}*/ -// VersionCompare (op) - Greater than comparison for versions /*{{{*/ +// pkgVS::GetVS - Find a VS by name /*{{{*/ // --------------------------------------------------------------------- /* */ -int pkgVersionCompare(const char *A, const char *B) -{ - return pkgVersionCompare(A,A + strlen(A),B,B + strlen(B)); -} -int pkgVersionCompare(string A,string B) -{ - return pkgVersionCompare(A.begin(),A.end(),B.begin(),B.end()); -} - - /*}}}*/ -// iVersionCompare - Compare versions /*{{{*/ -// --------------------------------------------------------------------- -/* This compares a fragment of the version. */ -static int iVersionCompare(const char *A, const char *AEnd, const char *B, - const char *BEnd) -{ - if (A >= AEnd && B >= BEnd) - return 0; - if (A >= AEnd) - return -1; - if (B >= BEnd) - return 1; - - /* Iterate over the whole string - What this does is to spilt the whole string into groups of - numeric and non numeric portions. For instance: - a67bhgs89 - Has 4 portions 'a', '67', 'bhgs', '89'. A more normal: - 2.7.2-linux-1 - Has '2', '.', '7', '.' ,'-linux-','1' */ - const char *lhs = A; - const char *rhs = B; - while (lhs != AEnd && rhs != BEnd) - { - // Starting points - const char *Slhs = lhs; - const char *Srhs = rhs; - - // Compute ending points were we have passed over the portion - bool Digit = (isdigit(*lhs) > 0?true:false); - for (;lhs != AEnd && (isdigit(*lhs) > 0?true:false) == Digit; lhs++); - for (;rhs != BEnd && (isdigit(*rhs) > 0?true:false) == Digit; rhs++); - - if (Digit == true) - { - // If the lhs has a digit and the rhs does not then < - if (rhs - Srhs == 0) - return -1; - - // Generate integers from the strings. - unsigned long Ilhs = StrToLong(Slhs,lhs); - unsigned long Irhs = StrToLong(Srhs,rhs); - if (Ilhs != Irhs) - { - if (Ilhs > Irhs) - return 1; - return -1; - } - } - else - { - // They are equal length so do a straight text compare - for (;Slhs != lhs && Srhs != rhs; Slhs++, Srhs++) - { - if (*Slhs != *Srhs) - { - /* We need to compare non alpha chars as higher than alpha - chars (a < !) */ - int lc = *Slhs; - int rc = *Srhs; - if (isalpha(lc) == 0) lc += 256; - if (isalpha(rc) == 0) rc += 256; - if (lc > rc) - return 1; - return -1; - } - } - - // If the lhs is shorter than the right it is 'less' - if (lhs - Slhs < rhs - Srhs) - return -1; - - // If the lhs is longer than the right it is 'more' - if (lhs - Slhs > rhs - Srhs) - return 1; - } - } - - // The strings must be equal - if (lhs == AEnd && rhs == BEnd) - return 0; - - // lhs is shorter - if (lhs == AEnd) - return -1; - - // rhs is shorter - if (rhs == BEnd) - return 1; - - // Shouldnt happen - return 1; -} - /*}}}*/ -// VersionCompare - Comparison for versions /*{{{*/ -// --------------------------------------------------------------------- -/* This fragments the version into E:V-R triples and compares each - portion seperately. */ -int pkgVersionCompare(const char *A, const char *AEnd, const char *B, - const char *BEnd) +pkgVersioningSystem *pkgVersioningSystem::GetVS(const char *Label) { - // Strip off the epoch and compare it - const char *lhs = A; - const char *rhs = B; - for (;lhs != AEnd && *lhs != ':'; lhs++); - for (;rhs != BEnd && *rhs != ':'; rhs++); - if (lhs == AEnd) - lhs = A; - if (rhs == BEnd) - rhs = B; - - // Compare the epoch - int Res = iVersionCompare(A,lhs,B,rhs); - if (Res != 0) - return Res; - - // Skip the : - if (lhs != A) - lhs++; - if (rhs != B) - rhs++; - - // Find the last - - const char *dlhs = AEnd-1; - const char *drhs = BEnd-1; - for (;dlhs > lhs && *dlhs != '-'; dlhs--); - for (;drhs > rhs && *drhs != '-'; drhs--); - - if (dlhs == lhs) - dlhs = AEnd; - if (drhs == rhs) - drhs = BEnd; - - // Compare the main version - Res = iVersionCompare(lhs,dlhs,rhs,drhs); - if (Res != 0) - return Res; - - // Skip the - - if (dlhs != lhs) - dlhs++; - if (drhs != rhs) - drhs++; - return iVersionCompare(dlhs,AEnd,drhs,BEnd); -} - /*}}}*/ -// CheckDep - Check a single dependency /*{{{*/ -// --------------------------------------------------------------------- -/* This simply preforms the version comparison and switch based on - operator. */ -bool pkgCheckDep(const char *DepVer,const char *PkgVer,int Op) -{ - if (DepVer == 0) - return true; - if (PkgVer == 0) - return false; - - // Perform the actuall comparision. - int Res = pkgVersionCompare(PkgVer,DepVer); - switch (Op & 0x0F) - { - case pkgCache::Dep::LessEq: - if (Res <= 0) - return true; - break; - - case pkgCache::Dep::GreaterEq: - if (Res >= 0) - return true; - break; - - case pkgCache::Dep::Less: - if (Res < 0) - return true; - break; - - case pkgCache::Dep::Greater: - if (Res > 0) - return true; - break; - - case pkgCache::Dep::Equals: - if (Res == 0) - return true; - break; - - case pkgCache::Dep::NotEquals: - if (Res != 0) - return true; - break; - } - - return false; -} - /*}}}*/ -// BaseVersion - Return the upstream version string /*{{{*/ -// --------------------------------------------------------------------- -/* This strips all the debian specific information from the version number */ -string pkgBaseVersion(const char *Ver) -{ - // Strip off the bit before the first colon - const char *I = Ver; - for (; *I != 0 && *I != ':'; I++); - if (*I == ':') - Ver = I + 1; - - // Chop off the trailing - - I = Ver; - unsigned Last = strlen(Ver); - for (; *I != 0; I++) - if (*I == '-') - Last = I - Ver; - - return string(Ver,Last); + for (unsigned I = 0; I != GlobalListLen; I++) + if (strcmp(VSList[I]->Label,Label) == 0) + return VSList[I]; + return 0; } /*}}}*/ diff --git a/apt-pkg/version.h b/apt-pkg/version.h index 127519583..27e8e1f1b 100644 --- a/apt-pkg/version.h +++ b/apt-pkg/version.h @@ -1,16 +1,22 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ -// $Id: version.h,v 1.5 1999/04/19 06:03:09 jgg Exp $ +// $Id: version.h,v 1.6 2001/02/20 07:03:17 jgg Exp $ /* ###################################################################### - Version - Version comparison routines + Version - Versioning system.. + + The versioning system represents how versions are compared, represented + and how dependencies are evaluated. As a general rule versioning + systems are not compatible unless specifically allowed by the + TestCompatibility query. - These routines provide some means to compare versions and check - dependencies. + The versions are stored in a global list of versions, but that is just + so that they can be queried when someone does 'apt-get -v'. + pkgSystem provides the proper means to access the VS for the active + system. ##################################################################### */ /*}}}*/ -// Header section: pkglib #ifndef PKGLIB_VERSION_H #define PKGLIB_VERSION_H @@ -20,11 +26,52 @@ #include -int pkgVersionCompare(const char *A, const char *B); -int pkgVersionCompare(const char *A, const char *AEnd, const char *B, - const char *BEnd); -int pkgVersionCompare(string A,string B); -bool pkgCheckDep(const char *DepVer,const char *PkgVer,int Op); -string pkgBaseVersion(const char *Ver); +class pkgVersioningSystem +{ + public: + // Global list of VS's + static pkgVersioningSystem **GlobalList; + static unsigned long GlobalListLen; + static pkgVersioningSystem *GetVS(const char *Label); + + const char *Label; + + // Compare versions.. + virtual int DoCmpVersion(const char *A,const char *Aend, + const char *B,const char *Bend) = 0; + virtual bool CheckDep(const char *PkgVer,int Op,const char *DepVer) = 0; + virtual int DoCmpReleaseVer(const char *A,const char *Aend, + const char *B,const char *Bend) = 0; + virtual string UpstreamVersion(const char *A) = 0; + + // See if the given VS is compatible with this one.. + virtual bool TestCompatibility(pkgVersioningSystem const &Against) + {return this == &Against;}; + + // Shortcuts + inline int CmpVersion(const char *A, const char *B) + { + return DoCmpVersion(A,A+strlen(A),B,B+strlen(B)); + }; + inline int CmpVersion(string A,string B) + { + return DoCmpVersion(A.begin(),A.end(),B.begin(),B.end()); + }; + inline int CmpReleaseVer(const char *A, const char *B) + { + return DoCmpReleaseVer(A,A+strlen(A),B,B+strlen(B)); + }; + inline int CmpReleaseVer(string A,string B) + { + return DoCmpReleaseVer(A.begin(),A.end(),B.begin(),B.end()); + }; + + pkgVersioningSystem(); + virtual ~pkgVersioningSystem() {}; +}; + +#ifdef APT_COMPATIBILITY +#include +#endif #endif diff --git a/apt-pkg/versionmatch.cc b/apt-pkg/versionmatch.cc new file mode 100644 index 000000000..45cdb117e --- /dev/null +++ b/apt-pkg/versionmatch.cc @@ -0,0 +1,210 @@ +// -*- mode: cpp; mode: fold -*- +// Description /*{{{*/ +// $Id: versionmatch.cc,v 1.2 2001/02/20 07:03:17 jgg Exp $ +/* ###################################################################### + + Version Matching + + This module takes a matching string and a type and locates the version + record that satisfies the constraint described by the matching string. + + ##################################################################### */ + /*}}}*/ +// Include Files /*{{{*/ +#ifdef __GNUG__ +#pragma implementation "apt-pkg/versionmatch.h" +#endif +#include + +#include +#include + +#include + /*}}}*/ + +// VersionMatch::pkgVersionMatch - Constructor /*{{{*/ +// --------------------------------------------------------------------- +/* Break up the data string according to the selected type */ +pkgVersionMatch::pkgVersionMatch(string Data,MatchType Type) : Type(Type) +{ + if (Type == None || Data.length() < 1) + return; + + // Cut up the version representation + if (Type == Version) + { + if (Data.end()[-1] == '*') + { + VerPrefixMatch = true; + VerStr = string(Data.begin(),Data.end()-1); + } + else + VerStr = Data; + return; + } + + if (Type == Release) + { + // All empty = match all + if (Data == "*") + return; + + // Are we a simple specification? + const char *I = Data.begin(); + for (; I < Data.end() && *I != '='; I++); + if (I == Data.end()) + { + // Temporary + if (isdigit(Data[0])) + RelVerStr = Data; + else + RelArchive = Data; + + if (RelVerStr.end()[-1] == '*') + { + RelVerPrefixMatch = true; + RelVerStr = string(RelVerStr.begin(),RelVerStr.end()-1); + } + return; + } + + char Spec[300]; + char *Fragments[20]; + snprintf(Spec,sizeof(Spec),"%s",Data.c_str()); + if (TokSplitString(',',Spec,Fragments, + sizeof(Fragments)/sizeof(Fragments[0])) == false) + { + Type = None; + return; + } + + for (unsigned J = 0; Fragments[J] != 0; J++) + { + if (strlen(Fragments[J]) < 3) + continue; + + if (stringcasecmp(Fragments[J],Fragments[J]+2,"v=") == 0) + RelVerStr = Fragments[J]+2; + else if (stringcasecmp(Fragments[J],Fragments[J]+2,"o=") == 0) + RelOrigin = Fragments[J]+2; + else if (stringcasecmp(Fragments[J],Fragments[J]+2,"a=") == 0) + RelArchive = Fragments[J]+2; + else if (stringcasecmp(Fragments[J],Fragments[J]+2,"l=") == 0) + RelLabel = Fragments[J]+2; + else if (stringcasecmp(Fragments[J],Fragments[J]+2,"c=") == 0) + RelComponent = Fragments[J]+2; + } + + if (RelVerStr.end()[-1] == '*') + { + RelVerPrefixMatch = true; + RelVerStr = string(RelVerStr.begin(),RelVerStr.end()-1); + } + return; + } + + if (Type == Origin) + { + OrSite = Data; + return; + } +} + /*}}}*/ +// VersionMatch::MatchVer - Match a version string with prefixing /*{{{*/ +// --------------------------------------------------------------------- +/* */ +bool pkgVersionMatch::MatchVer(const char *A,string B,bool Prefix) +{ + const char *Ab = A; + const char *Ae = Ab + strlen(A); + + // Strings are not a compatible size. + if ((unsigned)(Ae - Ab) != B.length() && Prefix == false || + (unsigned)(Ae - Ab) < B.length()) + return false; + + // Match (leading?) + if (stringcasecmp(B.begin(),B.end(), + Ab,Ab + B.length()) == 0) + return true; + + return false; +} + /*}}}*/ +// VersionMatch::Find - Locate the best match for the select type /*{{{*/ +// --------------------------------------------------------------------- +/* */ +pkgCache::VerIterator pkgVersionMatch::Find(pkgCache::PkgIterator Pkg) +{ + pkgCache::VerIterator Ver = Pkg.VersionList(); + for (; Ver.end() == false; Ver++) + { + if (Type == Version) + { + if (MatchVer(Ver.VerStr(),VerStr,VerPrefixMatch) == true) + return Ver; + continue; + } + + for (pkgCache::VerFileIterator VF = Ver.FileList(); VF.end() == false; VF++) + if (FileMatch(VF.File()) == true) + return Ver; + } + + // This will be Ended by now. + return Ver; +} + /*}}}*/ +// VersionMatch::FileMatch - Match against an index file /*{{{*/ +// --------------------------------------------------------------------- +/* This matcher checks against the release file and the origin location + to see if the constraints are met. */ +bool pkgVersionMatch::FileMatch(pkgCache::PkgFileIterator File) +{ + if (Type == Release) + { +/* cout << RelVerStr << ',' << RelOrigin << ',' << RelArchive << ',' << RelLabel << endl; + cout << File.Version() << ',' << File.Origin() << ',' << File.Archive() << ',' << File.Label() << endl; +*/ + if (RelVerStr.empty() == true && RelOrigin.empty() == true && + RelArchive.empty() == true && RelLabel.empty() == true && + RelComponent.empty() == true) + return false; + + if (RelVerStr.empty() == false) + if (File->Version == 0 || + MatchVer(File.Version(),RelVerStr,RelVerPrefixMatch) == false) + return false; + if (RelOrigin.empty() == false) + if (File->Origin == 0 || + stringcasecmp(RelOrigin,File.Origin()) != 0) + return false; + if (RelArchive.empty() == false) + { + if (File->Archive == 0 || + stringcasecmp(RelArchive,File.Archive()) != 0) + return false; + } + if (RelLabel.empty() == false) + if (File->Label == 0 || + stringcasecmp(RelLabel,File.Label()) != 0) + return false; + if (RelComponent.empty() == false) + if (File->Component == 0 || + stringcasecmp(RelLabel,File.Component()) != 0) + return false; + return true; + } + + if (Type == Origin) + { + if (OrSite.empty() == false) + if (File->Site == 0 || + OrSite != File.Site()) + return false; + return true; + } + + return false; +} + /*}}}*/ diff --git a/apt-pkg/versionmatch.h b/apt-pkg/versionmatch.h new file mode 100644 index 000000000..f8f236a2f --- /dev/null +++ b/apt-pkg/versionmatch.h @@ -0,0 +1,69 @@ +// -*- mode: cpp; mode: fold -*- +// Description /*{{{*/ +// $Id: versionmatch.h,v 1.2 2001/02/20 07:03:17 jgg Exp $ +/* ###################################################################### + + Version Matching + + This module takes a matching string and a type and locates the version + record that satisfies the constraint described by the matching string. + + Version: 1.2* + Release: o=Debian,v=2.1*,c=main + Release: v=2.1* + Release: * + Origin: ftp.debian.org + + Release may be a complex type that can specify matches for any of: + Version (v= with prefix) + Origin (o=) + Archive (a=) + Label (l=) + Component (c=) + If there are no equals signs in the string then it is scanned in short + form - if it starts with a number it is Version otherwise it is an + Archive. + + Release may be a '*' to match all releases. + + ##################################################################### */ + /*}}}*/ +#ifndef PKGLIB_VERSIONMATCH_H +#define PKGLIB_VERSIONMATCH_H + +#ifdef __GNUG__ +#pragma interface "apt-pkg/versionmatch.h" +#endif + +#include +#include + +class pkgVersionMatch +{ + // Version Matching + string VerStr; + bool VerPrefixMatch; + + // Release Matching + string RelVerStr; + bool RelVerPrefixMatch; + string RelOrigin; + string RelArchive; + string RelLabel; + string RelComponent; + + // Origin Matching + string OrSite; + + public: + + enum MatchType {None = 0,Version,Release,Origin} Type; + + bool MatchVer(const char *A,string B,bool Prefix); + bool FileMatch(pkgCache::PkgFileIterator File); + pkgCache::VerIterator Find(pkgCache::PkgIterator Pkg); + + pkgVersionMatch(string Data,MatchType Type); +}; + +#endif -- cgit v1.2.3-70-g09d2