From 6c139d6e362f04a1582e8a8f511f8aeab031fecf Mon Sep 17 00:00:00 2001 From: Arch Librarian Date: Mon, 20 Sep 2004 16:50:41 +0000 Subject: Sync Author: jgg Date: 1998-07-07 04:17:00 GMT Sync --- apt-pkg/sourcelist.cc | 465 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 465 insertions(+) create mode 100644 apt-pkg/sourcelist.cc (limited to 'apt-pkg/sourcelist.cc') diff --git a/apt-pkg/sourcelist.cc b/apt-pkg/sourcelist.cc new file mode 100644 index 000000000..62d5e6fcd --- /dev/null +++ b/apt-pkg/sourcelist.cc @@ -0,0 +1,465 @@ +// -*- mode: cpp; mode: fold -*- +// Description /*{{{*/ +// $Id: sourcelist.cc,v 1.1 1998/07/07 04:17:06 jgg Exp $ +/* ###################################################################### + + List of Sources + + ##################################################################### */ + /*}}}*/ +// Include Files /*{{{*/ +#ifdef __GNUG__ +#pragma implementation "pkglib/sourcelist.h" +#endif + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + /*}}}*/ + +// SourceList::pkgSourceList - Constructors /*{{{*/ +// --------------------------------------------------------------------- +/* */ +pkgSourceList::pkgSourceList() +{ +} + +pkgSourceList::pkgSourceList(string File) +{ + Read(File); +} + /*}}}*/ +// SourceList::ReadMainList - Read the main source list from etc /*{{{*/ +// --------------------------------------------------------------------- +/* */ +bool pkgSourceList::ReadMainList() +{ + return Read(PKG_DEB_CF_SOURCELIST); +} + /*}}}*/ +// SourceList::Read - Parse the sourcelist file /*{{{*/ +// --------------------------------------------------------------------- +/* */ +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()); + + List.erase(List.begin(),List.end()); + char Buffer[300]; + + int CurLine = 0; + while (F.eof() == false) + { + F.getline(Buffer,sizeof(Buffer)); + CurLine++; + _strtabexpand(Buffer,sizeof(Buffer)); + _strstrip(Buffer); + + // Comment or blank + if (Buffer[0] == '#' || Buffer[0] == 0) + continue; + + // Grok it + string Type; + string URI; + Item Itm; + 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)",PKG_DEB_ARCH); + List.push_back(Itm); + continue; + } + + // 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()); + + do + { + List.push_back(Itm); + } + while (ParseQuoteWord(C,Itm.Section) == true); + } + return true; +} + /*}}}*/ +// SourceList::SanitizeURI - Hash the uri /*{{{*/ +// --------------------------------------------------------------------- +/* This converts a URI into a safe filename. It quotes all unsafe characters + and converts / to _ and removes the scheme identifier. */ +string pkgSourceList::SanitizeURI(string URI) +{ + string::const_iterator I = URI.begin() + URI.find(':') + 1; + for (; I < URI.end() && *I == '/'; I++); + + // "\x00-\x20{}|\\\\^\\[\\]<>\"\x7F-\xFF"; + URI = QuoteString(string(I,URI.end() - I),"\\|{}[]<>\"^~_=!@#$%^&*"); + string::iterator J = URI.begin(); + for (; J != URI.end(); J++) + if (*J == '/') + *J = '_'; + return URI; +} + /*}}}*/ +// SourceList::MatchPkgFile - Find the package file that has the ver /*{{{*/ +// --------------------------------------------------------------------- +/* This will return List.end() if it could not find the matching + file */ +pkgSourceList::const_iterator pkgSourceList::MatchPkgFile(pkgCache::VerIterator Ver) +{ + string Base = PKG_DEB_ST_LIST; + for (const_iterator I = List.begin(); I != List.end(); I++) + { + string URI = I->PackagesURI(); + switch (I->Type) + { + case Item::Deb: + if (Base + SanitizeURI(URI) == Ver.File().FileName()) + return I; + break; + }; + } + return List.end(); +} + /*}}}*/ +// 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 << Itm.Type << ' ' << Itm.URI << ' ' << Itm.Dist << ' ' << Itm.Section; + return O; +} + /*}}}*/ +// SourceList::Item::SetType - Sets the distribution type /*{{{*/ +// --------------------------------------------------------------------- +/* */ +bool pkgSourceList::Item::SetType(string S) +{ + if (S == "deb") + { + Type = Deb; + return true; + } + + return true; +} + /*}}}*/ +// 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)",PKG_DEB_ARCH); + + // 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] == '/') + Res = URI + Dist; + else + Res = URI + "dists/" + Dist + '/' + Section + + "/binary-" + PKG_DEB_ARCH + '/'; + + Res += "Packages"; + 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] == '/') + Res += Dist; + else + Res += Dist + '/' + Section; + + Res += " Packages"; + 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 Deb: + Res += SiteOnly(URI) + ' '; + if (Dist[Dist.size() - 1] == '/') + Res += Dist; + else + Res += Dist + '/' + Section; + + Res += " "; + Res += Ver.ParentPkg().Name(); + 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: + Res = URI + File; + break; + }; + return Res; +} + /*}}}*/ +// SourceList::Item::SiteOnly - Strip off the path part of a URI /*{{{*/ +// --------------------------------------------------------------------- +/* */ +string pkgSourceList::Item::SiteOnly(string URI) const +{ + unsigned int Pos = URI.find(':'); + if (Pos == string::npos || Pos + 3 > URI.length()) + return URI; + if (URI[Pos + 1] != '/' || URI[Pos + 2] != '/') + return URI; + + Pos = URI.find('/',Pos + 3); + if (Pos == string::npos) + return URI; + return string(URI,0,Pos); +} + /*}}}*/ + +// UpdateMeta - Update the meta information /*{{{*/ +// --------------------------------------------------------------------- +/* The meta information is package files, revision information and mirror + lists. */ +bool pkgUpdateMeta(pkgSourceList &List,pkgAquire &Engine) +{ + if (Engine.OutputDir(PKG_DEB_ST_LIST) == false) + return false; + + for (pkgSourceList::const_iterator I = List.begin(); I != List.end(); I++) + { + string URI = I->PackagesURI(); + string GetInfo = I->PackagesInfo(); + switch (I->Type) + { + case pkgSourceList::Item::Deb: + if (Engine.Get(URI + ".gz",List.SanitizeURI(URI),GetInfo) == false) + return false; + break; + }; + } + + return true; +} + /*}}}*/ +// MakeSrcCache - Generate a cache file of all the package files /*{{{*/ +// --------------------------------------------------------------------- +/* This goes over the source list and builds a cache of all the package + files. */ +bool pkgMakeSrcCache(pkgSourceList &List) +{ + // First we date check the cache + bool Bad = false; + while (Bad == false) + { + if (FileExists(PKG_DEB_CA_SRCCACHE) == false) + break; + + pkgCache Cache(PKG_DEB_CA_SRCCACHE,true,true); + if (_error->PendingError() == true) + { + _error->Discard(); + break; + } + + // They are certianly out of sync + if (Cache.Head().PackageFileCount != List.size()) + break; + + for (pkgCache::PkgFileIterator F(Cache); F.end() == false; F++) + { + // Search for a match in the source list + Bad = true; + for (pkgSourceList::const_iterator I = List.begin(); + I != List.end(); I++) + { + string File = string(PKG_DEB_ST_LIST) + + List.SanitizeURI(I->PackagesURI()); + if (F.FileName() == File) + { + Bad = false; + break; + } + } + + // Check if the file matches what was cached + Bad |= !F.IsOk(); + if (Bad == true) + break; + } + + if (Bad == false) + return true; + } + + unlink(PKG_DEB_CA_SRCCACHE); + pkgCache::MergeState Merge(PKG_DEB_CA_SRCCACHE); + if (_error->PendingError() == true) + return false; + + for (pkgSourceList::const_iterator I = List.begin(); I != List.end(); I++) + { + string File = string(PKG_DEB_ST_LIST) + List.SanitizeURI(I->PackagesURI()); + if (Merge.MergePackageFile(File,"??","??") == false) + return false; + } + + return true; +} + /*}}}*/ +// MakeStatusCache - Generates a cache that includes the status files /*{{{*/ +// --------------------------------------------------------------------- +/* This copies the package source cache and then merges the status and + xstatus files into it. */ +bool pkgMakeStatusCache() +{ + // Quickly check if the existing package cache is ok + bool Bad = false; + while (Bad == false) + { + if (FileExists(PKG_DEB_CA_PKGCACHE) == false) + break; + + /* We check the dates of the two caches. This takes care of most things + quickly and easially */ + struct stat Src; + struct stat Pkg; + if (stat(PKG_DEB_CA_PKGCACHE,&Pkg) != 0 || + stat(PKG_DEB_CA_SRCCACHE,&Src) != 0) + break; + if (difftime(Src.st_mtime,Pkg.st_mtime) > 0) + break; + + pkgCache Cache(PKG_DEB_CA_PKGCACHE,true,true); + if (_error->PendingError() == true) + { + _error->Discard(); + break; + } + + for (pkgCache::PkgFileIterator F(Cache); F.end() == false; F++) + { + if (F.IsOk() == false) + { + Bad = true; + break; + } + } + + if (Bad == false) + return true; + } + + // Check the integrity of the source cache. + { + pkgCache Cache(PKG_DEB_CA_SRCCACHE,true,true); + if (_error->PendingError() == true) + return false; + } + + // Sub scope so that merge destructs before we rename the file... + string Cache = PKG_DEB_CA_PKGCACHE ".new"; + { + if (CopyFile(PKG_DEB_CA_SRCCACHE,Cache) == false) + return false; + + pkgCache::MergeState Merge(Cache); + if (_error->PendingError() == true) + return false; + + // Merge in the user status file + if (FileExists(PKG_DEB_ST_USERSTATUS) == true) + if (Merge.MergePackageFile(PKG_DEB_ST_USERSTATUS,"status","0", + pkgFLAG_NotSource) == false) + return false; + + // Merge in the extra status file + if (FileExists(PKG_DEB_ST_XSTATUS) == true) + if (Merge.MergePackageFile(PKG_DEB_ST_XSTATUS,"status","0", + pkgFLAG_NotSource) == false) + return false; + + // Merge in the status file + if (Merge.MergePackageFile("/var/lib/dpkg/status","status","0", + pkgFLAG_NotSource) == false) + return false; + } + + if (rename(Cache.c_str(),PKG_DEB_CA_PKGCACHE) != 0) + return false; + + return true; +} + /*}}}*/ -- cgit v1.2.3