diff options
Diffstat (limited to 'apt-pkg')
-rw-r--r-- | apt-pkg/acquire-item.cc | 302 | ||||
-rw-r--r-- | apt-pkg/acquire-item.h | 108 | ||||
-rw-r--r-- | apt-pkg/acquire-worker.cc | 3 | ||||
-rw-r--r-- | apt-pkg/acquire.cc | 7 | ||||
-rw-r--r-- | apt-pkg/cachefile.cc | 34 | ||||
-rw-r--r-- | apt-pkg/contrib/fileutl.cc | 17 | ||||
-rw-r--r-- | apt-pkg/contrib/fileutl.h | 1 | ||||
-rw-r--r-- | apt-pkg/deb/debindexfile.cc | 10 | ||||
-rw-r--r-- | apt-pkg/deb/debmetaindex.cc | 21 | ||||
-rw-r--r-- | apt-pkg/init.cc | 3 | ||||
-rw-r--r-- | apt-pkg/packagemanager.cc | 6 |
11 files changed, 484 insertions, 28 deletions
diff --git a/apt-pkg/acquire-item.cc b/apt-pkg/acquire-item.cc index 215615bdd..b85e5d19b 100644 --- a/apt-pkg/acquire-item.cc +++ b/apt-pkg/acquire-item.cc @@ -727,7 +727,7 @@ void pkgAcqIndexDiffs::Done(string Message,unsigned long Size,string Md5Hash, /* // rred excepts the patch as $FinalFile.ed Rename(DestFile,FinalFile+".ed"); - + std::clog << " Sending to rred method FinalFile: " << FinalFile << std::endl; if(Debug) std::clog << "Sending to rred method: " << FinalFile << std::endl; @@ -2066,7 +2066,305 @@ string pkgAcqFile::Custom600Headers() return "\nIndex-File: true"; return ""; } - /*}}}*/ +/*}}}*/ + +pkgAcqDebdelta::pkgAcqDebdelta(pkgAcquire *Owner,pkgSourceList *Sources, + pkgRecords *Recs,pkgCache::VerIterator const &Version, + string &StoreFilename) : + Item(Owner), Version(Version), Sources(Sources), Recs(Recs), + StoreFilename(StoreFilename), Vf(Version.FileList()), + Trusted(false) +{ + DebdeltaName = string(Version.ParentPkg().Name()) + "_" + + string(Version.ParentPkg().CurVersion()) + "_" + + string(Version.ParentPkg().CandVersion()) + "_" + + string(Version.Arch()) + ".debdelta"; + Retries = _config->FindI("Acquire::Retries",0); + Debug = true; + if (Version.Arch() == 0) + { + _error->Error(_("I wasn't able to locate a file for the %s package. " + "This might mean you need to manually fix this package. " + "(due to missing arch)"), + Version.ParentPkg().Name()); + return; + } + + /* 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; + + DebdeltaName = StoreFilename = QuoteString(DebdeltaName, ":"); + DestFile = _config->FindDir("Dir::Cache::Archives") + "partial/" + flNotDir(StoreFilename); + } + + // check if we have one trusted source for the package. if so, switch + // to "TrustedOnly" mode + for (pkgCache::VerFileIterator i = Version.FileList(); i.end() == false; i++) + { + pkgIndexFile *Index; + if (Sources->FindIndex(i.File(),Index) == false) + continue; + if (_config->FindB("Debug::pkgAcquire::Auth", false)) + { + std::cerr << "Checking index: " << Index->Describe() + << "(Trusted=" << Index->IsTrusted() << ")\n"; + } + if (Index->IsTrusted()) { + Trusted = true; + break; + } + } + + // "allow-unauthenticated" restores apts old fetching behaviour + // that means that e.g. unauthenticated file:// uris are higher + // priority than authenticated http:// uris + if (_config->FindB("APT::Get::AllowUnauthenticated",false) == true) + Trusted = false; + if (Debug) { + std::cerr << "\n[Debdelta] pkgAcqDebdelta::pkgAcqDebdelta()" << std::endl; + std::cerr << " DebdeltaName : " << DebdeltaName << std::endl; + std::cerr << " StoreFilename: " << StoreFilename << std::endl; + std::cerr << " DestFile : " << DestFile << std::endl; + } + DebdeltaStatus = Fetching; + if (QueueNext() == false && _error->PendingError() == false) + _error->Error(_("I wasn't able to locate a file for the %s package. " + "This might mean you need to manually fix this package."), + Version.ParentPkg().Name()); +} + +bool pkgAcqDebdelta::QueueNext() +{ + string const ForceHash = _config->Find("Acquire::ForceHash"); + + for (; Vf.end() == false; Vf++) + { + // Ignore not source sources + if ((Vf.File()->Flags & pkgCache::Flag::NotSource) != 0) + continue; + + // Try to cross match against the source list + pkgIndexFile *Index; + if (Sources->FindIndex(Vf.File(),Index) == false) + continue; + + // only try to get a trusted package from another source if that source + // is also trusted + if(Trusted && !Index->IsTrusted()) + continue; + + // Grab the text package record + pkgRecords::Parser &Parse = Recs->Lookup(Vf); + if (_error->PendingError() == true) + return false; + + string PkgFile = Parse.FileName(); + //std::cerr << " PkgFile:" << PkgFile << std::endl; + if (ForceHash.empty() == false) + { + if(stringcasecmp(ForceHash, "sha256") == 0) + ExpectedHash = HashString("SHA256", Parse.SHA256Hash()); + else if (stringcasecmp(ForceHash, "sha1") == 0) + ExpectedHash = HashString("SHA1", Parse.SHA1Hash()); + else + ExpectedHash = HashString("MD5Sum", Parse.MD5Hash()); + } + else + { + string Hash; + if ((Hash = Parse.SHA256Hash()).empty() == false) + ExpectedHash = HashString("SHA256", Hash); + else if ((Hash = Parse.SHA1Hash()).empty() == false) + ExpectedHash = HashString("SHA1", Hash); + else + ExpectedHash = HashString("MD5Sum", Parse.MD5Hash()); + } + if (PkgFile.empty() == true) + return _error->Error(_("The package index files are corrupted. No Filename: " + "field for package %s."), + Version.ParentPkg().Name()); + // See if we already have the deb + FileSize = Version->Size; + string FinalFile = _config->FindDir("Dir::Cache::Archives") + flNotDir(PkgFile); + struct stat Buf; + if (stat(FinalFile.c_str(),&Buf) == 0) + { + if (Debug) + std::cerr << "[Debdelta] File already exists. " << FinalFile << std::endl; + // TODO: check if this ok. Make sure the size matches + if ((unsigned)Buf.st_size == Version->Size) + { + Complete = true; + Local = true; + Status = StatDone; + DebdeltaStatus = Completed; + StoreFilename = DestFile = FinalFile; + return true; + } + /* Hmm, we have a file and its size does not match, this means it is + an old style mismatched arch */ + unlink(FinalFile.c_str()); + } + + // Create the item + Local = false; + // See if we already have the debdelta in the partial dir. + if (FileExists(DestFile)) + { + // TODO: verify the sum/size of it. + if (Debug) + std::cerr << "[Debdelta] File already exists. " << DestFile << std::endl; + Desc.URI = "debdelta:" + DestFile; + Mode = "debdelta"; + DebdeltaStatus = Patching; + Local = true; + } + else + { + Desc.URI = flNotFile(Index->ArchiveURI(PkgFile)) + DebdeltaName; + ReplaceURI(); + } + Desc.Description = "[Debdelta] " + Index->ArchiveInfo(Version); + Desc.Owner = this; + Desc.ShortDesc = "[Debdelta] " + string(Version.ParentPkg().Name()); + if (Debug) { + std::cerr << "[Debdelta] pkgAcqDebdelta::QueueNext()" << std::endl; + std::cerr << " DestFile : " << DestFile << std::endl; + std::cerr << " Desc.URI : " << Desc.URI << std::endl; + std::cerr << " StoreFileName: " << StoreFilename << std::endl; + } + Vf++; + QueueURI(Desc); + return true; + } + return false; +} + +void pkgAcqDebdelta::Failed(string Message,pkgAcquire::MethodConfig *Cnf) +{ + if (Debug) { + std::cerr << "\n[Debdelta] Failed to download " << Desc.URI << std::endl; + std::cerr << "[Debdelta] Message:\n" << Message << std::endl; + } + // TODO: find out what went wrong and display to the user + new pkgAcqArchive(Owner, Sources, Recs, Version, StoreFilename); + Complete = false; + Status = StatError; + DebdeltaStatus = FetchingFailure; + Item::Failed(Message, Cnf); + Dequeue(); +} + +void pkgAcqDebdelta::Done(string Message,unsigned long Size,string Hash, + pkgAcquire::MethodConfig *Cnf) +{ + // TODO: there must be two stages within this method. + // one for downloading debdelta. another for verifying the resulting .deb + if (Debug) std::cerr << "[Debdelta] pkgAcqDebdelta::Done() state: " << DebdeltaStatus << std::endl; + // Grab the output filename + string FileName = LookupTag(Message,"Filename"); + if (Debug) { + std::cerr << " StoreFileName: " << StoreFilename + << "\n DestFile : " << DestFile + << "\n Desc.URI : " << Desc.URI + << "\n FileName : " << FileName << std::endl; + } + if (DebdeltaStatus == Patching) + { + if (Debug) std::cerr << "[Debdelta] Patching Done. Verifying "<< FileName << "..." << std::endl; + if (ExpectedHash.toStr() != Hash) + { + Status = StatError; + ErrorText = _("[Debdelta] Hash Sum mismatch"); + if(FileExists(DestFile)) + if (!Local) + Rename(DestFile, DestFile + ".FAILED"); + //return; // TODO: UNCOMMENT + } + // Check the size + if (Size != Version->Size) + { + Status = StatError; + ErrorText = _("[Debdelta] Size mismatch"); + //return; // TODO: UNCOMMEnT + } + DebdeltaStatus = Completed; + Complete = true; + Status = StatDone; + StoreFilename = FileName; + Item::Done(Message,Size,Hash,Cnf); + return; + } + // TODO: Check the sum/size + //std::cerr << "[Debdelta] Verifying " << DestFile << std::endl; + if (FileName.empty() == true) + { + Status = StatError; + ErrorText = "[Debdelta] Method gave a blank filename"; + return; + } + if (FileName != DestFile) // this is set in the file/http methods + { + // file => FileName != DestFile (i.e. FileName is the local file) + // http => FileName == DestFile (i.e. FileName is some local place. may be within "partial" dir) + Local = true; + } + DebdeltaStatus = Patching; + Rename(DestFile, FileName); + DestFile = StoreFilename = FileName; + chmod(DestFile.c_str(), 0644); + Desc.URI = "debdelta:" + StoreFilename; + Mode = "debdelta"; + QueueURI(Desc); +} + +void pkgAcqDebdelta::Finished() +{ + if (Debug) + std::cerr << "[Debdelta] pkgAcqDebdelta::Finished() state: " << DebdeltaStatus << std::endl; + if (Status == pkgAcquire::Item::StatDone && + Complete == true) + return; + StoreFilename = string(); +} + +bool pkgAcqDebdelta::ReplaceURI() +{ + const Configuration::Item* item = _config->Tree("Aquire::Debdelta::Replace-Rule"); + for (item = item->Child; item != 0; item = item->Next) + { + size_t pos = 0; + // see if the Des.URI is available in the URI-Space + if ((pos = Desc.URI.find(item->Tag, pos)) != std::string::npos) + { + Desc.URI.replace(pos, item->Tag.length(), item->Value); + if (Debug) + { + std::cerr << "[Debdelta] Replaced " << item->Tag << " => " << item->Value << std::endl; + std::cerr << " New URI: " << Desc.URI << std::endl; + } + return true; + } + } + return _error->Error("[Debdelta] Could not find a replacement URI."); +} + bool IndexTarget::IsOptional() const { if (strncmp(ShortDesc.c_str(), "Translation", 11) != 0) return false; diff --git a/apt-pkg/acquire-item.h b/apt-pkg/acquire-item.h index f763577ee..aa852ccc9 100644 --- a/apt-pkg/acquire-item.h +++ b/apt-pkg/acquire-item.h @@ -1018,6 +1018,114 @@ class pkgAcqFile : public pkgAcquire::Item bool IsIndexFile=false); }; /*}}}*/ + +/** \brief An item that is responsible for fetching a debdelta file. {{{ + * + * If the package file already exists in the cache, nothing will be + * done + */ +class pkgAcqDebdelta : public pkgAcquire::Item +{ + protected: + string DebdeltaName; + /** \brief The package version being fetched. */ + pkgCache::VerIterator Version; + + /** \brief The fetch command that is currently being processed. */ + pkgAcquire::ItemDesc Desc; + + /** \brief The list of sources from which to pick archives to + * download this package from. + */ + pkgSourceList *Sources; + + /** \brief A package records object, used to look up the file + * corresponding to each version of the package. + */ + pkgRecords *Recs; + + /** \brief The hashsum of this package. */ + HashString ExpectedHash; + + /** \brief A location in which the actual filename of the package + * should be stored. + */ + string &StoreFilename; + + /** \brief The next file for this version to try to download. */ + pkgCache::VerFileIterator Vf; + + /** \brief How many (more) times to try to find a new source from + * which to download this package version if it fails. + * + * Set from Acquire::Retries. + */ + unsigned int Retries; + + /** \brief \b true if this version file is being downloaded from a + * trusted source. + */ + bool Trusted; + + /** + * \brief used to debug the class + */ + bool Debug; + /** \brief Queue up the next available file for this version. */ + bool QueueNext(); + + public: + + virtual void Failed(string Message,pkgAcquire::MethodConfig *Cnf); + virtual void Done(string Message,unsigned long Size,string Hash, + pkgAcquire::MethodConfig *Cnf); + virtual string DescURI() {return Desc.URI;}; + virtual string ShortDesc() {return Desc.ShortDesc;}; + virtual void Finished(); + virtual string HashSum() {return ExpectedHash.toStr(); }; + virtual bool IsTrusted() {return Trusted;}; + virtual bool ReplaceURI(); + /** \brief Create a new pkgAcqArchive. + * + * \param Owner The pkgAcquire object with which this item is + * associated. + * + * \param Sources The sources from which to download version + * files. + * + * \param Recs A package records object, used to look up the file + * corresponding to each version of the package. + * + * \param Version The package version to download. + * + * \param StoreFilename A location in which the actual filename of + * the package should be stored. It will be set to a guessed + * basename in the constructor, and filled in with a fully + * qualified filename once the download finishes. + */ + pkgAcqDebdelta(pkgAcquire *Owner,pkgSourceList *Sources, + pkgRecords *Recs,pkgCache::VerIterator const &Version, + string &StoreFilename); + enum DebdeltaState + { + Fetching, + Patching, + Completed, + FetchingFailure + } DebdeltaStatus; +}; + /*}}}*/ + +/** \brief Retrieve an arbitrary file to the current directory. {{{ + * + * The file is retrieved even if it is accessed via a URL type that + * normally is a NOP, such as "file". If the download fails, the + * partial file is renamed to get a ".FAILED" extension. + */ +class pkgAcqDebdeltaIndex : public pkgAcquire::Item +{}; + /*}}}*/ + /** @} */ #endif diff --git a/apt-pkg/acquire-worker.cc b/apt-pkg/acquire-worker.cc index 75e03232a..1a17dfa5c 100644 --- a/apt-pkg/acquire-worker.cc +++ b/apt-pkg/acquire-worker.cc @@ -332,6 +332,7 @@ bool pkgAcquire::Worker::RunMessages() // 400 URI Failure case 400: { + std::cerr <<" 400 URI Failure" << std::endl; if (Itm == 0) { _error->Error("Method gave invalid 400 URI Failure message"); @@ -364,11 +365,13 @@ bool pkgAcquire::Worker::RunMessages() // 401 General Failure case 401: + std::cerr <<" 401 General Failure" << std::endl; _error->Error("Method %s General failure: %s",Access.c_str(),LookupTag(Message,"Message").c_str()); break; // 403 Media Change case 403: + std::cerr <<" 403 Media Change" << std::endl; MediaChange(Message); break; } diff --git a/apt-pkg/acquire.cc b/apt-pkg/acquire.cc index 9478cdfb4..7596aa956 100644 --- a/apt-pkg/acquire.cc +++ b/apt-pkg/acquire.cc @@ -228,9 +228,10 @@ void pkgAcquire::Enqueue(ItemDesc &Item) // Some trace stuff if (Debug == true) { - clog << "Fetching " << Item.URI << endl; - clog << " to " << Item.Owner->DestFile << endl; - clog << " Queue is: " << Name << endl; + clog << "pkgAcquire::Enqueue()" << endl; + clog << " Fetching " << Item.URI << endl; + clog << " to " << Item.Owner->DestFile << endl; + clog << " Queue is: " << Name << endl; } } /*}}}*/ diff --git a/apt-pkg/cachefile.cc b/apt-pkg/cachefile.cc index 964c5bd8b..a253f17f6 100644 --- a/apt-pkg/cachefile.cc +++ b/apt-pkg/cachefile.cc @@ -50,23 +50,23 @@ pkgCacheFile::~pkgCacheFile() /* */ bool pkgCacheFile::BuildCaches(OpProgress *Progress, bool WithLock) { - if (Cache != NULL) - return true; - - if (_config->FindB("pkgCacheFile::Generate", true) == false) - { - Map = new MMap(*new FileFd(_config->FindFile("Dir::Cache::pkgcache"), - FileFd::ReadOnly),MMap::Public|MMap::ReadOnly); - Cache = new pkgCache(Map); - if (_error->PendingError() == true) - return false; - return true; - } - - const bool ErrorWasEmpty = _error->empty(); - if (WithLock == true) - if (_system->Lock() == false) - return false; + if (Cache != NULL) + return true; + + if (_config->FindB("pkgCacheFile::Generate", true) == false) + { + Map = new MMap(*new FileFd(_config->FindFile("Dir::Cache::pkgcache"), + FileFd::ReadOnly),MMap::Public|MMap::ReadOnly); + Cache = new pkgCache(Map); + if (_error->PendingError() == true) + return false; + return true; + } + + const bool ErrorWasEmpty = _error->empty(); + if (WithLock == true) + if (_system->Lock() == false) + return false; if (_config->FindB("Debug::NoLocking",false) == true) WithLock = false; diff --git a/apt-pkg/contrib/fileutl.cc b/apt-pkg/contrib/fileutl.cc index 50019872e..f65f7cf28 100644 --- a/apt-pkg/contrib/fileutl.cc +++ b/apt-pkg/contrib/fileutl.cc @@ -275,7 +275,22 @@ bool CreateDirectory(string const &Parent, string const &Path) } return true; } - /*}}}*/ + +// Rename - Rename a file /*{{{*/ +// --------------------------------------------------------------------- +/* This helper function is used by alot of item methods as thier final + step */ +bool Rename(string From, string To) +{ + if (rename(From.c_str(),To.c_str()) != 0) + { + return _error->Error("Rename failed. %s (%s -> %s).",strerror(errno), + From.c_str(),To.c_str()); + } + return true; +} + +/*}}}*/ // CreateAPTDirectoryIfNeeded - ensure that the given directory exists /*{{{*/ // --------------------------------------------------------------------- /* a small wrapper around CreateDirectory to check if it exists and to diff --git a/apt-pkg/contrib/fileutl.h b/apt-pkg/contrib/fileutl.h index cde288ad2..7c1127798 100644 --- a/apt-pkg/contrib/fileutl.h +++ b/apt-pkg/contrib/fileutl.h @@ -97,6 +97,7 @@ bool FileExists(string File); bool RealFileExists(string File); bool DirectoryExists(string const &Path) __attrib_const; bool CreateDirectory(string const &Parent, string const &Path); +bool Rename(string From, string To); /** \brief Ensure the existence of the given Path * diff --git a/apt-pkg/deb/debindexfile.cc b/apt-pkg/deb/debindexfile.cc index c9e7f1176..057a99a86 100644 --- a/apt-pkg/deb/debindexfile.cc +++ b/apt-pkg/deb/debindexfile.cc @@ -176,8 +176,14 @@ debPackagesIndex::debPackagesIndex(string const &URI, string const &Dist, string bool const &Trusted, string const &Arch) : pkgIndexFile(Trusted), URI(URI), Dist(Dist), Section(Section), Architecture(Arch) { - if (Architecture == "native") - Architecture = _config->Find("APT::Architecture"); + if (Architecture == "native") + Architecture = _config->Find("APT::Architecture"); + string ReplacementItem = "Aquire::Debdelta::Replace-Rule::" + URI;//::URI::URI(URI); + string ReplacementDefault = _config->Find("Aquire::Debdelta::Replace-Rule::Default"); + _config->Set(ReplacementItem, _config->Find(ReplacementItem, ReplacementDefault)); + + //std::cerr << "==== Replacement rule: " << ReplacementItem + // << " => "<< ReplacementDefault << std::endl; } /*}}}*/ // PackagesIndex::ArchiveInfo - Short version of the archive url /*{{{*/ diff --git a/apt-pkg/deb/debmetaindex.cc b/apt-pkg/deb/debmetaindex.cc index a91cc34e9..b9946bc16 100644 --- a/apt-pkg/deb/debmetaindex.cc +++ b/apt-pkg/deb/debmetaindex.cc @@ -425,8 +425,27 @@ class debSLTypeDebSrc : public debSLTypeDebian { Name = "deb-src"; Label = "Standard Debian source tree"; - } + } +}; + +class debSLTypeDebdelta : public debSLTypeDebian +{ +public: + + bool CreateItem(vector<metaIndex *> &List, string const &URI, + string const &Dist, string const &Section, + std::map<string, string> const &Options) const + { + return CreateItemInternal(List, URI, Dist, Section, false, Options); + } + + debSLTypeDebdelta() + { + Name = "debdelta"; + Label = "Standard Debdelta tree"; + } }; debSLTypeDeb _apt_DebType; debSLTypeDebSrc _apt_DebSrcType; +debSLTypeDebdelta _apt_DebdeltaType;
\ No newline at end of file diff --git a/apt-pkg/init.cc b/apt-pkg/init.cc index 38a0814e5..4d2eae913 100644 --- a/apt-pkg/init.cc +++ b/apt-pkg/init.cc @@ -40,6 +40,9 @@ bool pkgInitConfig(Configuration &Cnf) Cnf.CndSet("APT::Install-Suggests", false); Cnf.CndSet("Dir","/"); + // Debdelta replacement rule + Cnf.Set("Aquire::Debdelta::Replace-Rule::Default", "http://debdeltas.debian.net/debian-deltas/");// http://www.bononia.it/debian-deltas/ + Cnf.Set("Aquire::Debdelta::Replace-Rule::http://security.debian.org/", "http://debdeltas.debian.net/debian-security-deltas/"); // http://security.ubuntu.com/ubuntu/ => http://www.bononia.it/debian-security-deltas/ // State Cnf.CndSet("Dir::State","var/lib/apt/"); diff --git a/apt-pkg/packagemanager.cc b/apt-pkg/packagemanager.cc index fe9f6eb68..9982dc737 100644 --- a/apt-pkg/packagemanager.cc +++ b/apt-pkg/packagemanager.cc @@ -80,8 +80,10 @@ bool pkgPackageManager::GetArchives(pkgAcquire *Owner,pkgSourceList *Sources, // Skip already processed packages if (List->IsNow(Pkg) == false) continue; - - new pkgAcqArchive(Owner,Sources,Recs,Cache[Pkg].InstVerIter(Cache), + + //new pkgAcqArchive(Owner,Sources,Recs,Cache[Pkg].InstVerIter(Cache), + // FileNames[Pkg->ID]); + new pkgAcqDebdelta(Owner,Sources,Recs,Cache[Pkg].InstVerIter(Cache), FileNames[Pkg->ID]); } |