diff options
47 files changed, 873 insertions, 215 deletions
diff --git a/apt-pkg/acquire-item.cc b/apt-pkg/acquire-item.cc index 0178456a8..913764f64 100644 --- a/apt-pkg/acquire-item.cc +++ b/apt-pkg/acquire-item.cc @@ -55,7 +55,8 @@ using namespace std; /* */ pkgAcquire::Item::Item(pkgAcquire *Owner) : Owner(Owner), FileSize(0), PartialSize(0), Mode(0), ID(0), Complete(false), - Local(false), QueueCounter(0) + Local(false), QueueCounter(0), + ExpectedAdditionalItems(0) { Owner->Add(this); Status = StatIdle; @@ -342,21 +343,24 @@ bool pkgAcqSubIndex::ParseIndex(string const &IndexFile) /*{{{*/ * the original packages file */ pkgAcqDiffIndex::pkgAcqDiffIndex(pkgAcquire *Owner, - string URI,string URIDesc,string ShortDesc, - HashString ExpectedHash) - : Item(Owner), RealURI(URI), ExpectedHash(ExpectedHash), - Description(URIDesc) + IndexTarget const *Target, + HashString ExpectedHash, + indexRecords *MetaIndexParser) + : Item(Owner), ExpectedHash(ExpectedHash), Target(Target), + MetaIndexParser(MetaIndexParser) + { Debug = _config->FindB("Debug::pkgAcquire::Diffs",false); - Desc.Description = URIDesc + "/DiffIndex"; + RealURI = Target->URI; Desc.Owner = this; - Desc.ShortDesc = ShortDesc; - Desc.URI = URI + ".diff/Index"; + Desc.Description = Target->Description + "/DiffIndex"; + Desc.ShortDesc = Target->ShortDesc; + Desc.URI = Target->URI + ".diff/Index"; DestFile = _config->FindDir("Dir::State::lists") + "partial/"; - DestFile += URItoFileName(URI) + string(".DiffIndex"); + DestFile += URItoFileName(Target->URI) + string(".DiffIndex"); if(Debug) std::clog << "pkgAcqDiffIndex: " << Desc.URI << std::endl; @@ -559,8 +563,7 @@ void pkgAcqDiffIndex::Failed(string Message,pkgAcquire::MethodConfig * /*Cnf*/)/ std::clog << "pkgAcqDiffIndex failed: " << Desc.URI << " with " << Message << std::endl << "Falling back to normal index file acquire" << std::endl; - new pkgAcqIndex(Owner, RealURI, Description, Desc.ShortDesc, - ExpectedHash); + new pkgAcqIndex(Owner, Target, ExpectedHash, MetaIndexParser); Complete = false; Status = StatDone; @@ -919,7 +922,8 @@ void pkgAcqIndexMergeDiffs::Done(string Message,unsigned long long Size,string M pkgAcqIndex::pkgAcqIndex(pkgAcquire *Owner, string URI,string URIDesc,string ShortDesc, HashString ExpectedHash, string comprExt) - : Item(Owner), RealURI(URI), ExpectedHash(ExpectedHash) + : Item(Owner), RealURI(URI), ExpectedHash(ExpectedHash), Target(0), + MetaIndexParser(0) { if(comprExt.empty() == true) { @@ -937,7 +941,7 @@ pkgAcqIndex::pkgAcqIndex(pkgAcquire *Owner, Init(URI, URIDesc, ShortDesc); } pkgAcqIndex::pkgAcqIndex(pkgAcquire *Owner, IndexTarget const *Target, - HashString const &ExpectedHash, indexRecords const *MetaIndexParser) + HashString const &ExpectedHash, indexRecords *MetaIndexParser) : Item(Owner), RealURI(Target->URI), ExpectedHash(ExpectedHash) { // autoselect the compression method @@ -964,6 +968,10 @@ pkgAcqIndex::pkgAcqIndex(pkgAcquire *Owner, IndexTarget const *Target, else Verify = true; + // we need this in Init() + this->Target = Target; + this->MetaIndexParser = MetaIndexParser; + Init(Target->URI, Target->Description, Target->ShortDesc); } /*}}}*/ @@ -976,10 +984,27 @@ void pkgAcqIndex::Init(string const &URI, string const &URIDesc, string const &S DestFile += URItoFileName(URI); std::string const comprExt = CompressionExtension.substr(0, CompressionExtension.find(' ')); + std::string MetaKey; if (comprExt == "uncompressed") + { Desc.URI = URI; + if(Target) + MetaKey = string(Target->MetaKey); + } else + { Desc.URI = URI + '.' + comprExt; + if(Target) + MetaKey = string(Target->MetaKey) + '.' + comprExt; + } + + // load the filesize + if(MetaIndexParser) + { + indexRecords::checkSum *Record = MetaIndexParser->Lookup(MetaKey); + if(Record) + FileSize = Record->Size; + } Desc.Description = URIDesc; Desc.Owner = this; @@ -1081,7 +1106,7 @@ void pkgAcqIndex::Done(string Message,unsigned long long Size,string Hash, FinalFile += URItoFileName(RealURI); Rename(DestFile,FinalFile); chmod(FinalFile.c_str(),0644); - + /* We restore the original name to DestFile so that the clean operation will work OK */ DestFile = _config->FindDir("Dir::State::lists") + "partial/"; @@ -1090,6 +1115,7 @@ void pkgAcqIndex::Done(string Message,unsigned long long Size,string Hash, // Remove the compressed version. if (Erase == true) unlink(DestFile.c_str()); + return; } @@ -1177,9 +1203,13 @@ pkgAcqIndexTrans::pkgAcqIndexTrans(pkgAcquire *Owner, { } pkgAcqIndexTrans::pkgAcqIndexTrans(pkgAcquire *Owner, IndexTarget const *Target, - HashString const &ExpectedHash, indexRecords const *MetaIndexParser) + HashString const &ExpectedHash, indexRecords *MetaIndexParser) : pkgAcqIndex(Owner, Target, ExpectedHash, MetaIndexParser) { + // load the filesize + indexRecords::checkSum *Record = MetaIndexParser->Lookup(string(Target->MetaKey)); + if(Record) + FileSize = Record->Size; } /*}}}*/ // AcqIndexTrans::Custom600Headers - Insert custom request headers /*{{{*/ @@ -1259,6 +1289,9 @@ pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire *Owner, /*{{{*/ Rename(Final,LastGoodSig); } + // we expect the indextargets + one additional Release file + ExpectedAdditionalItems = IndexTargets->size() + 1; + QueueURI(Desc); } /*}}}*/ @@ -1311,6 +1344,9 @@ void pkgAcqMetaSig::Done(string Message,unsigned long long Size,string MD5, Complete = true; + // at this point pkgAcqMetaIndex takes over + ExpectedAdditionalItems = 0; + // put the last known good file back on i-m-s hit (it will // be re-verified again) // Else do nothing, we have the new file in DestFile then @@ -1328,6 +1364,9 @@ void pkgAcqMetaSig::Failed(string Message,pkgAcquire::MethodConfig *Cnf)/*{{{*/ { string Final = _config->FindDir("Dir::State::lists") + URItoFileName(RealURI); + // at this point pkgAcqMetaIndex takes over + ExpectedAdditionalItems = 0; + // if we get a network error we fail gracefully if(Status == StatTransientNetworkError) { @@ -1378,6 +1417,9 @@ pkgAcqMetaIndex::pkgAcqMetaIndex(pkgAcquire *Owner, /*{{{*/ Desc.ShortDesc = ShortDesc; Desc.URI = URI; + // we expect more item + ExpectedAdditionalItems = IndexTargets->size(); + QueueURI(Desc); } /*}}}*/ @@ -1428,9 +1470,20 @@ void pkgAcqMetaIndex::Done(string Message,unsigned long long Size,string Hash, / } else { + // FIXME: move this into pkgAcqMetaClearSig::Done on the next + // ABI break + + // if we expect a ClearTextSignature (InRelase), ensure that + // this is what we get and if not fail to queue a + // Release/Release.gpg, see #346386 + if (SigFile == DestFile && !StartsWithGPGClearTextSignature(DestFile)) + { + Failed(Message, Cfg); + return; + } + // There was a signature file, so pass it to gpgv for // verification - if (_config->FindB("Debug::pkgAcquire::Auth", false)) std::cerr << "Metaindex acquired, queueing gpg verification (" << SigFile << "," << DestFile << ")\n"; @@ -1556,12 +1609,15 @@ void pkgAcqMetaIndex::QueueIndexes(bool verify) /*{{{*/ } } + // at this point the real Items are loaded in the fetcher + ExpectedAdditionalItems = 0; + for (vector <struct IndexTarget*>::const_iterator Target = IndexTargets->begin(); Target != IndexTargets->end(); ++Target) { HashString ExpectedIndexHash; - const indexRecords::checkSum *Record = MetaIndexParser->Lookup((*Target)->MetaKey); + indexRecords::checkSum *Record = MetaIndexParser->Lookup((*Target)->MetaKey); bool compressedAvailable = false; if (Record == NULL) { @@ -1608,8 +1664,7 @@ void pkgAcqMetaIndex::QueueIndexes(bool verify) /*{{{*/ { if (_config->FindB("Acquire::PDiffs",true) == true && transInRelease == true && MetaIndexParser->Exists((*Target)->MetaKey + ".diff/Index") == true) - new pkgAcqDiffIndex(Owner, (*Target)->URI, (*Target)->Description, - (*Target)->ShortDesc, ExpectedIndexHash); + new pkgAcqDiffIndex(Owner, *Target, ExpectedIndexHash, MetaIndexParser); else new pkgAcqIndexTrans(Owner, *Target, ExpectedIndexHash, MetaIndexParser); } @@ -1622,8 +1677,7 @@ void pkgAcqMetaIndex::QueueIndexes(bool verify) /*{{{*/ instead, but passing the required info to it is to much hassle */ if(_config->FindB("Acquire::PDiffs",true) == true && (verify == false || MetaIndexParser->Exists((*Target)->MetaKey + ".diff/Index") == true)) - new pkgAcqDiffIndex(Owner, (*Target)->URI, (*Target)->Description, - (*Target)->ShortDesc, ExpectedIndexHash); + new pkgAcqDiffIndex(Owner, *Target, ExpectedIndexHash, MetaIndexParser); else new pkgAcqIndex(Owner, *Target, ExpectedIndexHash, MetaIndexParser); } @@ -1786,6 +1840,10 @@ pkgAcqMetaClearSig::pkgAcqMetaClearSig(pkgAcquire *Owner, /*{{{*/ { SigFile = DestFile; + // index targets + (worst case:) Release/Release.gpg + ExpectedAdditionalItems = IndexTargets->size() + 2; + + // keep the old InRelease around in case of transistent network errors string const Final = _config->FindDir("Dir::State::lists") + URItoFileName(RealURI); if (RealFileExists(Final) == true) @@ -1828,6 +1886,9 @@ string pkgAcqMetaClearSig::Custom600Headers() /*}}}*/ void pkgAcqMetaClearSig::Failed(string Message,pkgAcquire::MethodConfig *Cnf) /*{{{*/ { + // we failed, we will not get additional items from this method + ExpectedAdditionalItems = 0; + if (AuthPass == false) { // Remove the 'old' InRelease file if we try Release.gpg now as otherwise @@ -2086,7 +2147,8 @@ void pkgAcqArchive::Done(string Message,unsigned long long Size,string CalcHash, } // Check the hash - if(ExpectedHash.toStr() != CalcHash) + // FIXME: could this empty() check impose *any* sort of security issue? + if(ExpectedHash.empty() == false && ExpectedHash.toStr() != CalcHash) { RenameOnError(HashSumMismatch); return; diff --git a/apt-pkg/acquire-item.h b/apt-pkg/acquire-item.h index f48d2a0d7..eab5bb222 100644 --- a/apt-pkg/acquire-item.h +++ b/apt-pkg/acquire-item.h @@ -166,6 +166,16 @@ class pkgAcquire::Item : public WeakPointable * \sa pkgAcquire */ unsigned int QueueCounter; + + /** \brief The number of additional fetch items that are expected + * once this item is done. + * + * Some items like pkgAcqMeta{Index,Sig} will queue additional + * items. This variable can be set by the methods if it knows + * in advance how many items to expect to get a more accurate + * progress. + */ + unsigned int ExpectedAdditionalItems; /** \brief The name of the file into which the retrieved object * will be written. @@ -395,6 +405,11 @@ class pkgAcqDiffIndex : public pkgAcquire::Item */ std::string Description; + /** \brief Pointer to the IndexTarget data + */ + const struct IndexTarget * Target; + indexRecords *MetaIndexParser; + public: // Specialized action members virtual void Failed(std::string Message,pkgAcquire::MethodConfig *Cnf); @@ -428,8 +443,10 @@ class pkgAcqDiffIndex : public pkgAcquire::Item * * \param ExpectedHash The list file's MD5 signature. */ - pkgAcqDiffIndex(pkgAcquire *Owner,std::string URI,std::string URIDesc, - std::string ShortDesc, HashString ExpectedHash); + pkgAcqDiffIndex(pkgAcquire *Owner, + struct IndexTarget const * const Target, + HashString ExpectedHash, + indexRecords *MetaIndexParser); }; /*}}}*/ /** \brief An item that is responsible for fetching client-merge patches {{{ @@ -713,6 +730,11 @@ class pkgAcqIndex : public pkgAcquire::Item */ std::string CompressionExtension; + /** \brief Pointer to the IndexTarget data + */ + const struct IndexTarget * Target; + indexRecords *MetaIndexParser; + public: // Specialized action members @@ -746,7 +768,7 @@ class pkgAcqIndex : public pkgAcquire::Item std::string ShortDesc, HashString ExpectedHash, std::string compressExt=""); pkgAcqIndex(pkgAcquire *Owner, struct IndexTarget const * const Target, - HashString const &ExpectedHash, indexRecords const *MetaIndexParser); + HashString const &ExpectedHash, indexRecords *MetaIndexParser); void Init(std::string const &URI, std::string const &URIDesc, std::string const &ShortDesc); }; /*}}}*/ @@ -778,7 +800,7 @@ class pkgAcqIndexTrans : public pkgAcqIndex pkgAcqIndexTrans(pkgAcquire *Owner,std::string URI,std::string URIDesc, std::string ShortDesc); pkgAcqIndexTrans(pkgAcquire *Owner, struct IndexTarget const * const Target, - HashString const &ExpectedHash, indexRecords const *MetaIndexParser); + HashString const &ExpectedHash, indexRecords *MetaIndexParser); }; /*}}}*/ /** \brief Information about an index file. */ /*{{{*/ diff --git a/apt-pkg/acquire.cc b/apt-pkg/acquire.cc index a187a00ae..57cbba169 100644 --- a/apt-pkg/acquire.cc +++ b/apt-pkg/acquire.cc @@ -31,6 +31,7 @@ #include <stdlib.h> #include <string.h> #include <unistd.h> +#include <iomanip> #include <dirent.h> #include <sys/time.h> @@ -821,7 +822,9 @@ bool pkgAcquireStatus::Pulse(pkgAcquire *Owner) // Compute the total number of bytes to fetch unsigned int Unknown = 0; unsigned int Count = 0; - for (pkgAcquire::ItemCIterator I = Owner->ItemsBegin(); I != Owner->ItemsEnd(); + bool UnfetchedReleaseFiles = false; + for (pkgAcquire::ItemCIterator I = Owner->ItemsBegin(); + I != Owner->ItemsEnd(); ++I, ++Count) { TotalItems++; @@ -832,6 +835,13 @@ bool pkgAcquireStatus::Pulse(pkgAcquire *Owner) if ((*I)->Local == true) continue; + // see if the method tells us to expect more + TotalItems += (*I)->ExpectedAdditionalItems; + + // check if there are unfetched Release files + if ((*I)->Complete == false && (*I)->ExpectedAdditionalItems > 0) + UnfetchedReleaseFiles = true; + TotalBytes += (*I)->FileSize; if ((*I)->Complete == true) CurrentBytes += (*I)->FileSize; @@ -843,6 +853,7 @@ bool pkgAcquireStatus::Pulse(pkgAcquire *Owner) unsigned long long ResumeSize = 0; for (pkgAcquire::Worker *I = Owner->WorkersBegin(); I != 0; I = Owner->WorkerStep(I)) + { if (I->CurrentItem != 0 && I->CurrentItem->Owner->Complete == false) { CurrentBytes += I->CurrentSize; @@ -853,6 +864,7 @@ bool pkgAcquireStatus::Pulse(pkgAcquire *Owner) I->CurrentItem->Owner->Complete == false) TotalBytes += I->CurrentSize; } + } // Normalize the figures and account for unknown size downloads if (TotalBytes <= 0) @@ -863,6 +875,12 @@ bool pkgAcquireStatus::Pulse(pkgAcquire *Owner) // Wha?! Is not supposed to happen. if (CurrentBytes > TotalBytes) CurrentBytes = TotalBytes; + + // debug + if (_config->FindB("Debug::acquire::progress", false) == true) + std::clog << " Bytes: " + << SizeToStr(CurrentBytes) << " / " << SizeToStr(TotalBytes) + << std::endl; // Compute the CPS struct timeval NewTime; @@ -883,6 +901,14 @@ bool pkgAcquireStatus::Pulse(pkgAcquire *Owner) Time = NewTime; } + // calculate the percentage, if we have too little data assume 1% + if (TotalBytes > 0 && UnfetchedReleaseFiles) + Percent = 0; + else + // use both files and bytes because bytes can be unreliable + Percent = (0.8 * (CurrentBytes/float(TotalBytes)*100.0) + + 0.2 * (CurrentItems/float(TotalItems)*100.0)); + int fd = _config->FindI("APT::Status-Fd",-1); if(fd > 0) { @@ -900,13 +926,11 @@ bool pkgAcquireStatus::Pulse(pkgAcquire *Owner) else snprintf(msg,sizeof(msg), _("Retrieving file %li of %li"), i, TotalItems); - - // build the status str status << "dlstatus:" << i - << ":" << (CurrentBytes/float(TotalBytes)*100.0) - << ":" << msg - << endl; + << ":" << std::setprecision(3) << Percent + << ":" << msg + << endl; std::string const dlstatus = status.str(); FileFd::Write(fd, dlstatus.c_str(), dlstatus.size()); diff --git a/apt-pkg/acquire.h b/apt-pkg/acquire.h index ef16d8556..0113021b2 100644 --- a/apt-pkg/acquire.h +++ b/apt-pkg/acquire.h @@ -714,6 +714,10 @@ class pkgAcquireStatus /** \brief The number of items that have been successfully downloaded. */ unsigned long CurrentItems; + /** \brief The estimated percentage of the download (0-100) + */ + double Percent; + public: /** \brief If \b true, the download scheduler should call Pulse() diff --git a/apt-pkg/cachefilter.h b/apt-pkg/cachefilter.h index 49d2855f5..d9b957c67 100644 --- a/apt-pkg/cachefilter.h +++ b/apt-pkg/cachefilter.h @@ -16,71 +16,14 @@ namespace APT { namespace CacheFilter { -#define PACKAGE_MATCHER_ABI_COMPAT 1 -#ifdef PACKAGE_MATCHER_ABI_COMPAT - -// PackageNameMatchesRegEx /*{{{*/ -class PackageNameMatchesRegEx { - /** \brief dpointer placeholder (for later in case we need it) */ - void *d; - regex_t* pattern; -public: - PackageNameMatchesRegEx(std::string const &Pattern); - bool operator() (pkgCache::PkgIterator const &Pkg); - bool operator() (pkgCache::GrpIterator const &Grp); - ~PackageNameMatchesRegEx(); -}; - /*}}}*/ -// PackageNameMatchesFnmatch /*{{{*/ - class PackageNameMatchesFnmatch { - /** \brief dpointer placeholder (for later in case we need it) */ - void *d; - const std::string Pattern; -public: - PackageNameMatchesFnmatch(std::string const &Pattern) - : Pattern(Pattern) {}; - bool operator() (pkgCache::PkgIterator const &Pkg); - bool operator() (pkgCache::GrpIterator const &Grp); - ~PackageNameMatchesFnmatch() {}; -}; - /*}}}*/ -// PackageArchitectureMatchesSpecification /*{{{*/ -/** \class PackageArchitectureMatchesSpecification - \brief matching against architecture specification strings - - The strings are of the format \<kernel\>-\<cpu\> where either component, - or the whole string, can be the wildcard "any" as defined in - debian-policy ยง11.1 "Architecture specification strings". - - Examples: i386, mipsel, linux-any, any-amd64, any */ -class PackageArchitectureMatchesSpecification { - std::string literal; - std::string complete; - bool isPattern; - /** \brief dpointer placeholder (for later in case we need it) */ - void *d; -public: - /** \brief matching against architecture specification strings - * - * @param pattern is the architecture specification string - * @param isPattern defines if the given \b pattern is a - * architecture specification pattern to match others against - * or if it is the fixed string and matched against patterns - */ - PackageArchitectureMatchesSpecification(std::string const &pattern, bool const isPattern = true); - bool operator() (char const * const &arch); - bool operator() (pkgCache::PkgIterator const &Pkg); - bool operator() (pkgCache::VerIterator const &Ver); - ~PackageArchitectureMatchesSpecification(); -}; - -#else - class PackageMatcher { public: - virtual bool operator() (pkgCache::PkgIterator const &Pkg) { return false; }; - virtual bool operator() (pkgCache::GrpIterator const &Grp) { return false; }; - virtual bool operator() (pkgCache::VerIterator const &Ver) { return false; }; + virtual bool operator() (pkgCache::PkgIterator const &/*Pkg*/) { + return false; }; + virtual bool operator() (pkgCache::GrpIterator const &/*Grp*/) { + return false; }; + virtual bool operator() (pkgCache::VerIterator const &/*Ver*/) { + return false; }; virtual ~PackageMatcher() {}; }; @@ -139,7 +82,6 @@ public: virtual bool operator() (pkgCache::VerIterator const &Ver); virtual ~PackageArchitectureMatchesSpecification(); }; -#endif /*}}}*/ } } diff --git a/apt-pkg/cacheset.cc b/apt-pkg/cacheset.cc index 2ed6a96da..5d7f28515 100644 --- a/apt-pkg/cacheset.cc +++ b/apt-pkg/cacheset.cc @@ -321,7 +321,8 @@ bool PackageContainerInterface::FromString(PackageContainerInterface * const pci if (FromGroup(pci, Cache, str, helper) == false && FromTask(pci, Cache, str, helper) == false && #if (APT_PKG_MAJOR >= 4 && APT_PKG_MINOR >= 13) - FromFnmatch(pci, Cache, str, helper) == false) + // FIXME: hm, hm, regexp/fnmatch incompatible? + FromFnmatch(pci, Cache, str, helper) == false && #endif FromRegEx(pci, Cache, str, helper) == false) { @@ -610,7 +611,7 @@ void CacheSetHelper::canNotFindRegEx(PackageContainerInterface * const /*pci*/, } #if (APT_PKG_MAJOR >= 4 && APT_PKG_MINOR >= 13) // canNotFindFnmatch - handle the case no package is found by a fnmatch /*{{{*/ -void CacheSetHelper::canNotFindFnmatch(PackageContainerInterface * const pci, pkgCacheFile &Cache, std::string pattern) { + void CacheSetHelper::canNotFindFnmatch(PackageContainerInterface * const /*pci*/, pkgCacheFile &/*Cache*/, std::string pattern) { if (ShowError == true) _error->Insert(ErrorType, _("Couldn't find any package by glob '%s'"), pattern.c_str()); } @@ -676,8 +677,8 @@ APT_CONST void CacheSetHelper::showRegExSelection(pkgCache::PkgIterator const &/ /*}}}*/ #if (APT_PKG_MAJOR >= 4 && APT_PKG_MINOR >= 13) // showFnmatchSelection /*{{{*/ -APT_CONST void CacheSetHelper::showFnmatchSelection(pkgCache::PkgIterator const &pkg, - std::string const &pattern) { +APT_CONST void CacheSetHelper::showFnmatchSelection(pkgCache::PkgIterator const &/*pkg*/, + std::string const &/*pattern*/) { } /*}}}*/ #endif diff --git a/apt-pkg/contrib/configuration.cc b/apt-pkg/contrib/configuration.cc index 00f6ad0f9..fbe180f8e 100644 --- a/apt-pkg/contrib/configuration.cc +++ b/apt-pkg/contrib/configuration.cc @@ -254,7 +254,9 @@ string Configuration::FindDir(const char *Name,const char *Default) const // --------------------------------------------------------------------- /* Returns a vector of config values under the given item */ #if (APT_PKG_MAJOR >= 4 && APT_PKG_MINOR < 13) -vector<string> Configuration::FindVector(const char *Name) const { return FindVector(Name, ""); } +vector<string> Configuration::FindVector(const char *Name) const { + return FindVector(Name, ""); +} #endif vector<string> Configuration::FindVector(const char *Name, std::string const &Default) const { diff --git a/apt-pkg/contrib/configuration.h b/apt-pkg/contrib/configuration.h index c256139f4..6345c8a5d 100644 --- a/apt-pkg/contrib/configuration.h +++ b/apt-pkg/contrib/configuration.h @@ -84,12 +84,10 @@ class Configuration * \param Default list of values separated by commas */ std::vector<std::string> FindVector(const char *Name, std::string const &Default) const; std::vector<std::string> FindVector(std::string const &Name, std::string const &Default) const { return FindVector(Name.c_str(), Default); }; -#if (APT_PKG_MAJOR >= 4 && APT_PKG_MINOR >= 13) - std::vector<std::string> FindVector(const char *Name) const { return FindVector(Name, ""); }; -#else +#if (APT_PKG_MAJOR >= 4 && APT_PKG_MINOR < 13) std::vector<std::string> FindVector(const char *Name) const; #endif - std::vector<std::string> FindVector(std::string const &Name) const { return FindVector(Name.c_str(), ""); }; + std::vector<std::string> FindVector(std::string const &Name="") const { return FindVector(Name.c_str(), ""); }; int FindI(const char *Name,int const &Default = 0) const; int FindI(std::string const &Name,int const &Default = 0) const {return FindI(Name.c_str(),Default);}; bool FindB(const char *Name,bool const &Default = false) const; diff --git a/apt-pkg/contrib/fileutl.cc b/apt-pkg/contrib/fileutl.cc index b77c7ff7f..02b30dc1f 100644 --- a/apt-pkg/contrib/fileutl.cc +++ b/apt-pkg/contrib/fileutl.cc @@ -656,6 +656,22 @@ string flCombine(string Dir,string File) return Dir + '/' + File; } /*}}}*/ +// flAbsPath - Return the absolute path of the filename /*{{{*/ +// --------------------------------------------------------------------- +/* */ +string flAbsPath(string File) +{ + char *p = realpath(File.c_str(), NULL); + if (p == NULL) + { + _error->Errno("realpath", "flAbsPath failed"); + return ""; + } + std::string AbsPath(p); + free(p); + return AbsPath; +} + /*}}}*/ // SetCloseExec - Set the close on exec flag /*{{{*/ // --------------------------------------------------------------------- /* */ @@ -836,6 +852,27 @@ bool ExecWait(pid_t Pid,const char *Name,bool Reap) } /*}}}*/ + +// StartsWithGPGClearTextSignature - Check if a file is Pgp/GPG clearsigned /*{{{*/ +// --------------------------------------------------------------------- +/* */ +bool StartsWithGPGClearTextSignature(string const &FileName) +{ + static const char* SIGMSG = "-----BEGIN PGP SIGNED MESSAGE-----\n"; + char buffer[strlen(SIGMSG)+1]; + FILE* gpg = fopen(FileName.c_str(), "r"); + if (gpg == NULL) + return false; + + char const * const test = fgets(buffer, sizeof(buffer), gpg); + fclose(gpg); + if (test == NULL || strcmp(buffer, SIGMSG) != 0) + return false; + + return true; +} + + class FileFdPrivate { /*{{{*/ public: #ifdef HAVE_ZLIB @@ -1911,7 +1948,6 @@ bool FileFd::Close() { if ((Flags & Compressed) != Compressed && iFd > 0 && close(iFd) != 0) Res &= _error->Errno("close",_("Problem closing the file %s"), FileName.c_str()); - if (d != NULL) { Res &= d->CloseDown(FileName); @@ -2038,6 +2074,31 @@ std::string GetTempDir() return string(tmpdir); } +FileFd* GetTempFile(std::string const &Prefix, bool ImmediateUnlink) +{ + char fn[512]; + FileFd *Fd = new FileFd(); + + std::string tempdir = GetTempDir(); + snprintf(fn, sizeof(fn), "%s/%s.XXXXXX", + tempdir.c_str(), Prefix.c_str()); + int fd = mkstemp(fn); + if(ImmediateUnlink) + unlink(fn); + if (fd < 0) + { + _error->Errno("GetTempFile",_("Unable to mkstemp %s"), fn); + return NULL; + } + if (!Fd->OpenDescriptor(fd, FileFd::WriteOnly, FileFd::None, true)) + { + _error->Errno("GetTempFile",_("Unable to write to %s"),fn); + return NULL; + } + + return Fd; +} + bool Rename(std::string From, std::string To) { if (rename(From.c_str(),To.c_str()) != 0) @@ -2048,3 +2109,58 @@ bool Rename(std::string From, std::string To) } return true; } + +bool Popen(const char* Args[], FileFd &Fd, pid_t &Child, FileFd::OpenMode Mode) +{ + int fd; + if (Mode != FileFd::ReadOnly && Mode != FileFd::WriteOnly) + return _error->Error("Popen supports ReadOnly (x)or WriteOnly mode only"); + + int Pipe[2] = {-1, -1}; + if(pipe(Pipe) != 0) + { + return _error->Errno("pipe", _("Failed to create subprocess IPC")); + return NULL; + } + std::set<int> keep_fds; + keep_fds.insert(Pipe[0]); + keep_fds.insert(Pipe[1]); + Child = ExecFork(keep_fds); + if(Child < 0) + return _error->Errno("fork", "Failed to fork"); + if(Child == 0) + { + if(Mode == FileFd::ReadOnly) + { + close(Pipe[0]); + fd = Pipe[1]; + } + else if(Mode == FileFd::WriteOnly) + { + close(Pipe[1]); + fd = Pipe[0]; + } + + if(Mode == FileFd::ReadOnly) + { + dup2(fd, 1); + dup2(fd, 2); + } else if(Mode == FileFd::WriteOnly) + dup2(fd, 0); + + execv(Args[0], (char**)Args); + _exit(100); + } + if(Mode == FileFd::ReadOnly) + { + close(Pipe[1]); + fd = Pipe[0]; + } else if(Mode == FileFd::WriteOnly) + { + close(Pipe[0]); + fd = Pipe[1]; + } + Fd.OpenDescriptor(fd, Mode, FileFd::None, true); + + return true; +} diff --git a/apt-pkg/contrib/fileutl.h b/apt-pkg/contrib/fileutl.h index cc1a98eae..0b4d94885 100644 --- a/apt-pkg/contrib/fileutl.h +++ b/apt-pkg/contrib/fileutl.h @@ -168,6 +168,8 @@ time_t GetModificationTime(std::string const &Path); bool Rename(std::string From, std::string To); std::string GetTempDir(); +FileFd* GetTempFile(std::string const &Prefix = "", + bool ImmediateUnlink = true); /** \brief Ensure the existence of the given Path * @@ -191,6 +193,9 @@ pid_t ExecFork(std::set<int> keep_fds); void MergeKeepFdsFromConfiguration(std::set<int> &keep_fds); bool ExecWait(pid_t Pid,const char *Name,bool Reap = false); +// check if the given file starts with a PGP cleartext signature +bool StartsWithGPGClearTextSignature(std::string const &FileName); + // File string manipulators std::string flNotDir(std::string File); std::string flNotFile(std::string File); @@ -198,7 +203,23 @@ std::string flNoLink(std::string File); std::string flExtension(std::string File); std::string flCombine(std::string Dir,std::string File); +/** \brief Takes a file path and returns the absolute path + */ +std::string flAbsPath(std::string File); + // simple c++ glob std::vector<std::string> Glob(std::string const &pattern, int flags=0); +/** \brief Popen() implementation that execv() instead of using a shell + * + * \param Args the execv style command to run + * \param FileFd is a referenz to the FileFd to use for input or output + * \param Child a reference to the integer that stores the child pid + * Note that you must call ExecWait() or similar to cleanup + * \param Mode is either FileFd::ReadOnly or FileFd::WriteOnly + * \return true on success, false on failure with _error set + */ +bool Popen(const char* Args[], FileFd &Fd, pid_t &Child, FileFd::OpenMode Mode); + + #endif diff --git a/apt-pkg/contrib/macros.h b/apt-pkg/contrib/macros.h index 2d6448e5e..b268ce24c 100644 --- a/apt-pkg/contrib/macros.h +++ b/apt-pkg/contrib/macros.h @@ -138,7 +138,7 @@ // Non-ABI-Breaks should only increase RELEASE number. // See also buildlib/libversion.mak #define APT_PKG_MAJOR 4 -#define APT_PKG_MINOR 12 +#define APT_PKG_MINOR 13 #define APT_PKG_RELEASE 0 #endif diff --git a/apt-pkg/contrib/netrc.cc b/apt-pkg/contrib/netrc.cc index feaed67c8..1e3778f45 100644 --- a/apt-pkg/contrib/netrc.cc +++ b/apt-pkg/contrib/netrc.cc @@ -152,18 +152,6 @@ static int parsenetrc_string (char *host, std::string &login, std::string &passw return retcode; } -// for some unknown reason this method is exported so keep a compatible interface for now โฆ -int parsenetrc (char *host, char *login, char *password, char *netrcfile = NULL) -{ - std::string login_string, password_string; - int const ret = parsenetrc_string(host, login_string, password_string, netrcfile); - if (ret < 0) - return ret; - strncpy(login, login_string.c_str(), LOGINSIZE - 1); - strncpy(password, password_string.c_str(), PASSWORDSIZE - 1); - return ret; -} - void maybe_add_auth (URI &Uri, string NetRCFile) { diff --git a/apt-pkg/contrib/netrc.h b/apt-pkg/contrib/netrc.h index dbeb45386..b5b56f5d4 100644 --- a/apt-pkg/contrib/netrc.h +++ b/apt-pkg/contrib/netrc.h @@ -27,9 +27,5 @@ class URI; -// FIXME: kill this export on the next ABI break - strongly doubt its in use anyway -// outside of the apt itself, its really a internal interface -APT_DEPRECATED int parsenetrc (char *host, char *login, char *password, char *filename); - void maybe_add_auth (URI &Uri, std::string NetRCFile); #endif diff --git a/apt-pkg/deb/debindexfile.cc b/apt-pkg/deb/debindexfile.cc index eee758b7a..86ef92bfb 100644 --- a/apt-pkg/deb/debindexfile.cc +++ b/apt-pkg/deb/debindexfile.cc @@ -30,6 +30,7 @@ #include <apt-pkg/pkgcachegen.h> #include <apt-pkg/pkgrecords.h> #include <apt-pkg/srcrecords.h> +#include <apt-pkg/sptr.h> #include <stdio.h> #include <iostream> @@ -667,6 +668,97 @@ APT_CONST bool debStatusIndex::Exists() const } /*}}}*/ +// debDebPkgFile - Single .deb file /*{{{*/ +// --------------------------------------------------------------------- +debDebPkgFileIndex::debDebPkgFileIndex(std::string DebFile) + : pkgIndexFile(true), DebFile(DebFile) +{ + DebFileFullPath = flAbsPath(DebFile); +} + +std::string debDebPkgFileIndex::ArchiveURI(std::string /*File*/) const +{ + return "file:" + DebFileFullPath; +} + +bool debDebPkgFileIndex::Exists() const +{ + return FileExists(DebFile); +} +bool debDebPkgFileIndex::Merge(pkgCacheGenerator& Gen, OpProgress* Prog) const +{ + if(Prog) + Prog->SubProgress(0, "Reading deb file"); + + // get the control data out of the deb file vid dpkg -I + // ... can I haz libdpkg? + const char *Args[5] = {"/usr/bin/dpkg", + "-I", + DebFile.c_str(), + "control", + NULL}; + FileFd PipeFd; + pid_t Child; + if(Popen(Args, PipeFd, Child, FileFd::ReadOnly) == false) + return _error->Error("Popen failed"); + // FIXME: static buffer + char buf[8*1024]; + unsigned long long n = 0; + if(PipeFd.Read(buf, sizeof(buf)-1, &n) == false) + return _error->Errno("read", "Failed to read dpkg pipe"); + ExecWait(Child, "Popen"); + + // now write the control data to a tempfile + SPtr<FileFd> DebControl = GetTempFile("deb-file-" + DebFile); + if(DebControl == NULL) + return false; + DebControl->Write(buf, n); + // append size of the file + FileFd Fd(DebFile, FileFd::ReadOnly); + string Size; + strprintf(Size, "Size: %llu\n", Fd.Size()); + DebControl->Write(Size.c_str(), Size.size()); + // and rewind for the listparser + DebControl->Seek(0); + + // and give it to the list parser + debDebFileParser Parser(DebControl, DebFile); + if(Gen.SelectFile(DebFile, "local", *this) == false) + return _error->Error("Problem with SelectFile %s", DebFile.c_str()); + + pkgCache::PkgFileIterator File = Gen.GetCurFile(); + File->Size = DebControl->Size(); + File->mtime = DebControl->ModificationTime(); + + if (Gen.MergeList(Parser) == false) + return _error->Error("Problem with MergeLister for %s", DebFile.c_str()); + + return true; +} +pkgCache::PkgFileIterator debDebPkgFileIndex::FindInCache(pkgCache &Cache) const +{ + // FIXME: we could simply always return pkgCache::PkgFileIterator(Cache); + // to indicate its never in the cache which will force a Merge() + pkgCache::PkgFileIterator File = Cache.FileBegin(); + for (; File.end() == false; ++File) + { + if (File.FileName() == NULL || DebFile != File.FileName()) + continue; + + return File; + } + + return File; +} +unsigned long debDebPkgFileIndex::Size() const +{ + struct stat buf; + if(stat(DebFile.c_str(), &buf) != 0) + return 0; + return buf.st_size; +} + /*}}}*/ + // Index File types for Debian /*{{{*/ class debIFTypeSrc : public pkgIndexFile::Type { @@ -699,10 +791,20 @@ class debIFTypeStatus : public pkgIndexFile::Type }; debIFTypeStatus() {Label = "Debian dpkg status file";}; }; +class debIFTypeDebPkgFile : public pkgIndexFile::Type +{ + public: + virtual pkgRecords::Parser *CreatePkgParser(pkgCache::PkgFileIterator File) const + { + return new debDebFileRecordParser(File.FileName(),*File.Cache()); + }; + debIFTypeDebPkgFile() {Label = "deb Package file";}; +}; static debIFTypeSrc _apt_Src; static debIFTypePkg _apt_Pkg; static debIFTypeTrans _apt_Trans; static debIFTypeStatus _apt_Status; +static debIFTypeDebPkgFile _apt_DebPkgFile; const pkgIndexFile::Type *debSourcesIndex::GetType() const { @@ -720,5 +822,8 @@ const pkgIndexFile::Type *debStatusIndex::GetType() const { return &_apt_Status; } - +const pkgIndexFile::Type *debDebPkgFileIndex::GetType() const +{ + return &_apt_DebPkgFile; +} /*}}}*/ diff --git a/apt-pkg/deb/debindexfile.h b/apt-pkg/deb/debindexfile.h index 017c69a0a..69754e79d 100644 --- a/apt-pkg/deb/debindexfile.h +++ b/apt-pkg/deb/debindexfile.h @@ -164,4 +164,35 @@ class debSourcesIndex : public pkgIndexFile virtual ~debSourcesIndex() {}; }; +class debDebPkgFileIndex : public pkgIndexFile +{ + private: + void *d; + std::string DebFile; + std::string DebFileFullPath; + + public: + virtual const Type *GetType() const APT_CONST; + + virtual std::string Describe(bool /*Short*/) const { + return DebFile; + } + + // 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; + + // Interface for acquire + virtual std::string ArchiveURI(std::string /*File*/) const; + + debDebPkgFileIndex(std::string DebFile); + virtual ~debDebPkgFileIndex() {}; + +}; + #endif diff --git a/apt-pkg/deb/deblistparser.cc b/apt-pkg/deb/deblistparser.cc index a1bcfb710..d5e3ccb65 100644 --- a/apt-pkg/deb/deblistparser.cc +++ b/apt-pkg/deb/deblistparser.cc @@ -959,3 +959,23 @@ bool debListParser::SameVersion(unsigned short const Hash, /*{{{*/ } /*}}}*/ #endif + + +debDebFileParser::debDebFileParser(FileFd *File, std::string const &DebFile) + : debListParser(File, ""), DebFile(DebFile) +{ +} + +bool debDebFileParser::UsePackage(pkgCache::PkgIterator &Pkg, + pkgCache::VerIterator &Ver) +{ + bool res = debListParser::UsePackage(Pkg, Ver); + // we use the full file path as a provides so that the file is found + // by its name + if(NewProvidesAllArch(Ver, DebFile, Ver.VerStr()) == false) + return false; + return res; +} + + + diff --git a/apt-pkg/deb/deblistparser.h b/apt-pkg/deb/deblistparser.h index baace79fe..92ec048b1 100644 --- a/apt-pkg/deb/deblistparser.h +++ b/apt-pkg/deb/deblistparser.h @@ -56,7 +56,8 @@ class debListParser : public pkgCacheGenerator::ListParser bool ParseProvides(pkgCache::VerIterator &Ver); bool NewProvidesAllArch(pkgCache::VerIterator &Ver, std::string const &Package, std::string const &Version); static bool GrabWord(std::string Word,WordList *List,unsigned char &Out); - + APT_HIDDEN unsigned char ParseMultiArch(bool const showErrors); + public: static unsigned char GetPrio(std::string Str); @@ -101,9 +102,17 @@ class debListParser : public pkgCacheGenerator::ListParser debListParser(FileFd *File, std::string const &Arch = ""); virtual ~debListParser() {}; +}; - private: - APT_HIDDEN unsigned char ParseMultiArch(bool const showErrors); +class debDebFileParser : public debListParser +{ + private: + std::string DebFile; + + public: + debDebFileParser(FileFd *File, std::string const &DebFile); + virtual bool UsePackage(pkgCache::PkgIterator &Pkg, + pkgCache::VerIterator &Ver); }; #endif diff --git a/apt-pkg/deb/debmetaindex.cc b/apt-pkg/deb/debmetaindex.cc index 6fd12add8..56eecdca1 100644 --- a/apt-pkg/deb/debmetaindex.cc +++ b/apt-pkg/deb/debmetaindex.cc @@ -471,6 +471,15 @@ class debSLTypeDebian : public pkgSourceList::Type } }; +debDebFileMetaIndex::debDebFileMetaIndex(std::string const &DebFile) + : metaIndex(DebFile, "local-uri", "deb-dist"), DebFile(DebFile) +{ + DebIndex = new debDebPkgFileIndex(DebFile); + Indexes = new vector<pkgIndexFile *>(); + Indexes->push_back(DebIndex); +} + + class debSLTypeDeb : public debSLTypeDebian { public: @@ -507,5 +516,25 @@ class debSLTypeDebSrc : public debSLTypeDebian } }; +class debSLTypeDebFile : public pkgSourceList::Type +{ + public: + + bool CreateItem(vector<metaIndex *> &List, string const &URI, + string const &Dist, string const &Section, + std::map<string, string> const &Options) const + { + metaIndex *mi = new debDebFileMetaIndex(URI); + List.push_back(mi); + return true; + } + + debSLTypeDebFile() + { + Name = "deb-file"; + Label = "Debian Deb File"; + } +}; debSLTypeDeb _apt_DebType; debSLTypeDebSrc _apt_DebSrcType; +debSLTypeDebFile _apt_DebFileType; diff --git a/apt-pkg/deb/debmetaindex.h b/apt-pkg/deb/debmetaindex.h index 2286fa8b2..0e70bba87 100644 --- a/apt-pkg/deb/debmetaindex.h +++ b/apt-pkg/deb/debmetaindex.h @@ -18,6 +18,7 @@ class pkgAcquire; class pkgIndexFile; +class debDebPkgFileIndex; class debReleaseIndex : public metaIndex { public: @@ -71,4 +72,27 @@ class debReleaseIndex : public metaIndex { void PushSectionEntry(const debSectionEntry *Entry); }; +class debDebFileMetaIndex : public metaIndex +{ + private: + std::string DebFile; + debDebPkgFileIndex *DebIndex; + public: + virtual std::string ArchiveURI(std::string const& /*File*/) const { + return DebFile; + } + virtual bool GetIndexes(pkgAcquire* /*Owner*/, const bool& /*GetAll=false*/) const { + return true; + } + virtual std::vector<pkgIndexFile *> *GetIndexFiles() { + return Indexes; + } + virtual bool IsTrusted() const { + return true; + } + debDebFileMetaIndex(std::string const &DebFile); + virtual ~debDebFileMetaIndex() {}; + +}; + #endif diff --git a/apt-pkg/deb/debrecords.h b/apt-pkg/deb/debrecords.h index bdac6c90b..d572bc5c2 100644 --- a/apt-pkg/deb/debrecords.h +++ b/apt-pkg/deb/debrecords.h @@ -29,17 +29,16 @@ class debRecordParser : public pkgRecords::Parser { /** \brief dpointer placeholder (for later in case we need it) */ void *d; - + + protected: FileFd File; pkgTagFile Tags; pkgTagSection Section; - protected: - virtual bool Jump(pkgCache::VerFileIterator const &Ver); virtual bool Jump(pkgCache::DescFileIterator const &Desc); - public: + public: // These refer to the archive file for the Version virtual std::string FileName(); @@ -66,4 +65,15 @@ class debRecordParser : public pkgRecords::Parser virtual ~debRecordParser() {}; }; +// custom record parser that reads deb files directly +class debDebFileRecordParser : public debRecordParser +{ + public: + virtual std::string FileName() { + return File.Name(); + } + debDebFileRecordParser(std::string FileName,pkgCache &Cache) + : debRecordParser(FileName, Cache) {}; +}; + #endif diff --git a/apt-pkg/deb/debsrcrecords.cc b/apt-pkg/deb/debsrcrecords.cc index b09588dd3..615f0f57d 100644 --- a/apt-pkg/deb/debsrcrecords.cc +++ b/apt-pkg/deb/debsrcrecords.cc @@ -18,6 +18,7 @@ #include <apt-pkg/aptconfiguration.h> #include <apt-pkg/srcrecords.h> #include <apt-pkg/tagfile.h> +#include <apt-pkg/hashes.h> #include <ctype.h> #include <stdlib.h> @@ -121,64 +122,86 @@ bool debSrcRecordParser::BuildDepends(std::vector<pkgSrcRecords::Parser::BuildDe bool debSrcRecordParser::Files(std::vector<pkgSrcRecords::File> &List) { List.erase(List.begin(),List.end()); + + // map from the Hashsum field to the hashsum function, + // unfortunately this is not a 1:1 mapping from + // Hashes::SupporedHashes as e.g. Files is a historic name for the md5 + const std::pair<const char*, const char*> SourceHashFields[] = { + std::make_pair( "Checksums-Sha512", "SHA512"), + std::make_pair( "Checksums-Sha256", "SHA256"), + std::make_pair( "Checksums-Sha1", "SHA1"), + std::make_pair( "Files", "MD5Sum"), // historic Name + }; - string Files = Sect.FindS("Files"); - if (Files.empty() == true) - return false; + for (unsigned int i=0; + i < sizeof(SourceHashFields)/sizeof(SourceHashFields[0]); + i++) + { + string Files = Sect.FindS(SourceHashFields[i].first); + if (Files.empty() == true) + continue; - // Stash the / terminated directory prefix - string Base = Sect.FindS("Directory"); - if (Base.empty() == false && Base[Base.length()-1] != '/') - Base += '/'; + // Stash the / terminated directory prefix + string Base = Sect.FindS("Directory"); + if (Base.empty() == false && Base[Base.length()-1] != '/') + Base += '/'; - std::vector<std::string> const compExts = APT::Configuration::getCompressorExtensions(); + std::vector<std::string> const compExts = APT::Configuration::getCompressorExtensions(); - // Iterate over the entire list grabbing each triplet - const char *C = Files.c_str(); - while (*C != 0) - { - pkgSrcRecords::File F; - string Size; - - // Parse each of the elements - if (ParseQuoteWord(C,F.MD5Hash) == false || - ParseQuoteWord(C,Size) == false || - ParseQuoteWord(C,F.Path) == false) - return _error->Error("Error parsing file record"); - - // 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; - if (F.Type == "tar") { - // source v3 has extension 'debian.tar.*' instead of 'diff.*' - if (string(F.Path, Tmp+1, Pos-Tmp) == "debian") - F.Type = "diff"; - break; - } - F.Type = string(F.Path,Tmp+1,Pos-Tmp); + // Iterate over the entire list grabbing each triplet + const char *C = Files.c_str(); + while (*C != 0) + { + pkgSrcRecords::File F; + string Size; + + // Parse each of the elements + std::string RawHash; + if (ParseQuoteWord(C, RawHash) == false || + ParseQuoteWord(C, Size) == false || + ParseQuoteWord(C, F.Path) == false) + return _error->Error("Error parsing '%s' record", + SourceHashFields[i].first); + // assign full hash string + F.Hash = HashString(SourceHashFields[i].second, RawHash).toStr(); + // API compat hack + if(strcmp(SourceHashFields[i].second, "MD5Sum") == 0) + F.MD5Hash = RawHash; + + // 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; + if (F.Type == "tar") { + // source v3 has extension 'debian.tar.*' instead of 'diff.*' + if (string(F.Path, Tmp+1, Pos-Tmp) == "debian") + F.Type = "diff"; + break; + } + F.Type = string(F.Path,Tmp+1,Pos-Tmp); + + if (std::find(compExts.begin(), compExts.end(), std::string(".").append(F.Type)) != compExts.end() || + F.Type == "tar") + { + Pos = Tmp-1; + continue; + } - if (std::find(compExts.begin(), compExts.end(), std::string(".").append(F.Type)) != compExts.end() || - F.Type == "tar") - { - Pos = Tmp-1; - continue; - } - - break; - } + break; + } - List.push_back(F); + List.push_back(F); + } + break; } - - return true; + return (List.size() > 0); } /*}}}*/ // SrcRecordParser::~SrcRecordParser - Destructor /*{{{*/ diff --git a/apt-pkg/deb/dpkgpm.cc b/apt-pkg/deb/dpkgpm.cc index e410594df..32ef343aa 100644 --- a/apt-pkg/deb/dpkgpm.cc +++ b/apt-pkg/deb/dpkgpm.cc @@ -517,7 +517,7 @@ bool pkgDPkgPM::RunScriptsWithPkgs(const char *Cnf) void pkgDPkgPM::DoStdin(int master) { unsigned char input_buf[256] = {0,}; - ssize_t len = read(0, input_buf, sizeof(input_buf)); + ssize_t len = read(STDIN_FILENO, input_buf, sizeof(input_buf)); if (len) FileFd::Write(master, input_buf, len); else diff --git a/apt-pkg/indexrecords.cc b/apt-pkg/indexrecords.cc index 5353d1098..68ebdce08 100644 --- a/apt-pkg/indexrecords.cc +++ b/apt-pkg/indexrecords.cc @@ -53,7 +53,7 @@ APT_PURE time_t indexRecords::GetValidUntil() const return this->ValidUntil; } -APT_PURE const indexRecords::checkSum *indexRecords::Lookup(const string MetaKey) +APT_PURE indexRecords::checkSum *indexRecords::Lookup(const string MetaKey) { std::map<std::string, indexRecords::checkSum* >::const_iterator sum = Entries.find(MetaKey); if (sum == Entries.end()) diff --git a/apt-pkg/indexrecords.h b/apt-pkg/indexrecords.h index e31f889ad..2260a4ae1 100644 --- a/apt-pkg/indexrecords.h +++ b/apt-pkg/indexrecords.h @@ -41,7 +41,7 @@ class indexRecords indexRecords(const std::string ExpectedDist); // Lookup function - virtual const checkSum *Lookup(const std::string MetaKey); + virtual checkSum *Lookup(const std::string MetaKey); /** \brief tests if a checksum for this file is available */ bool Exists(std::string const &MetaKey) const; std::vector<std::string> MetaKeys(); diff --git a/apt-pkg/packagemanager.cc b/apt-pkg/packagemanager.cc index 5d6bc6bd2..0ec9f3309 100644 --- a/apt-pkg/packagemanager.cc +++ b/apt-pkg/packagemanager.cc @@ -28,6 +28,7 @@ #include <apt-pkg/pkgcache.h> #include <apt-pkg/cacheiterators.h> #include <apt-pkg/strutl.h> +#include <apt-pkg/install-progress.h> #include <stddef.h> #include <list> diff --git a/apt-pkg/packagemanager.h b/apt-pkg/packagemanager.h index 344ed9192..8a51a455c 100644 --- a/apt-pkg/packagemanager.h +++ b/apt-pkg/packagemanager.h @@ -44,6 +44,11 @@ class pkgDepCache; class pkgSourceList; class pkgOrderList; class pkgRecords; +namespace APT { + namespace Progress { + class PackageManager; + }; +}; class pkgPackageManager : protected pkgCache::Namespace diff --git a/apt-pkg/pkgcache.cc b/apt-pkg/pkgcache.cc index 91b75f52e..5088712a2 100644 --- a/apt-pkg/pkgcache.cc +++ b/apt-pkg/pkgcache.cc @@ -54,7 +54,7 @@ pkgCache::Header::Header() /* Whenever the structures change the major version should be bumped, whenever the generator changes the minor version should be bumped. */ - MajorVersion = 8; + MajorVersion = 9; #if (APT_PKG_MAJOR >= 4 && APT_PKG_MINOR >= 13) MinorVersion = 2; #else diff --git a/apt-pkg/pkgcache.h b/apt-pkg/pkgcache.h index 5e8a9630a..151de7d25 100644 --- a/apt-pkg/pkgcache.h +++ b/apt-pkg/pkgcache.h @@ -138,7 +138,7 @@ class pkgCache /*{{{*/ /** \brief priority of a package version Zero is used for unparsable or absent Priority fields. */ - enum VerPriority {Important=1,Required=2,Standard=3,Optional=4,Extra=5}; + enum VerPriority {Required=1,Important=2,Standard=3,Optional=4,Extra=5}; enum PkgSelectedState {Unknown=0,Install=1,Hold=2,DeInstall=3,Purge=4}; enum PkgInstState {Ok=0,ReInstReq=1,HoldInst=2,HoldReInstReq=3}; enum PkgCurrentState {NotInstalled=0,UnPacked=1,HalfConfigured=2, diff --git a/apt-pkg/sourcelist.h b/apt-pkg/sourcelist.h index 9df0c1d74..99e83f454 100644 --- a/apt-pkg/sourcelist.h +++ b/apt-pkg/sourcelist.h @@ -52,7 +52,15 @@ class pkgAcquire; class pkgIndexFile; class metaIndex; -class pkgSourceList +class pkgSource +{ + protected: + + std::vector<metaIndex *> SrcList; + +}; + +class pkgSourceList : public pkgSource { public: diff --git a/apt-pkg/srcrecords.h b/apt-pkg/srcrecords.h index 9915debfe..58a5e242f 100644 --- a/apt-pkg/srcrecords.h +++ b/apt-pkg/srcrecords.h @@ -33,6 +33,7 @@ class pkgSrcRecords struct File { std::string MD5Hash; + std::string Hash; unsigned long Size; std::string Path; std::string Type; diff --git a/apt-private/acqprogress.cc b/apt-private/acqprogress.cc index 0f5b53e50..ee6c4536f 100644 --- a/apt-private/acqprogress.cc +++ b/apt-private/acqprogress.cc @@ -170,7 +170,7 @@ bool AcqTextStatus::Pulse(pkgAcquire *Owner) ScreenWidth = sizeof(Buffer)-1; // Put in the percent done - sprintf(S,"%.0f%%",((CurrentBytes + CurrentItems)*100.0)/(TotalBytes+TotalItems)); + sprintf(S,"%.0f%%", Percent); bool Shown = false; for (pkgAcquire::Worker *I = Owner->WorkersBegin(); I != 0; diff --git a/apt-private/private-cachefile.h b/apt-private/private-cachefile.h index dce7e0a3a..1fddabfbd 100644 --- a/apt-private/private-cachefile.h +++ b/apt-private/private-cachefile.h @@ -6,7 +6,20 @@ #include <apt-pkg/configuration.h> #include <apt-pkg/pkgcache.h> #include <apt-pkg/macros.h> +#include <apt-pkg/sourcelist.h> +#include <apti18n.h> +// FIXME: we need to find a way to export this +class APT_PUBLIC SourceList : public pkgSourceList +{ + + public: + // Add custom metaIndex (e.g. local files) + void AddMetaIndex(metaIndex *mi) { + SrcList.push_back(mi); + } + +}; // class CacheFile - Cover class for some dependency cache functions /*{{{*/ // --------------------------------------------------------------------- @@ -28,6 +41,16 @@ class APT_PUBLIC CacheFile : public pkgCacheFile return false; return true; } + // FIXME: this can go once the "libapt-pkg" pkgSourceList has a way + // to add custom metaIndexes (or custom local files or so) + bool BuildSourceList(OpProgress */*Progress*/ = NULL) { + if (SrcList != NULL) + return true; + SrcList = new SourceList(); + if (SrcList->ReadMainList() == false) + return _error->Error(_("The list of sources could not be read.")); + return true; + } bool Open(bool WithLock = true) { OpTextProgress Prog(*_config); diff --git a/apt-private/private-install.cc b/apt-private/private-install.cc index 107ed398e..d9e485462 100644 --- a/apt-private/private-install.cc +++ b/apt-private/private-install.cc @@ -19,6 +19,8 @@ #include <apt-pkg/macros.h> #include <apt-pkg/packagemanager.h> #include <apt-pkg/pkgcache.h> +#include <apt-pkg/sourcelist.h> +#include <apt-pkg/install-progress.h> #include <errno.h> #include <stdlib.h> @@ -29,6 +31,7 @@ #include <iostream> #include <set> #include <vector> +#include <map> #include <apt-private/acqprogress.h> #include <apt-private/private-install.h> @@ -669,10 +672,34 @@ bool DoCacheManipulationFromCommandLine(CommandLine &CmdL, CacheFile &Cache, bool DoInstall(CommandLine &CmdL) { CacheFile Cache; + // first check for local pkgs and add them to the cache + for (const char **I = CmdL.FileList; *I != 0; I++) + { + if(FileExists(*I)) + { + // FIXME: make this more elegant + std::string TypeStr = flExtension(*I) + "-file"; + pkgSourceList::Type *Type = pkgSourceList::Type::GetType(TypeStr.c_str()); + if(Type != 0) + { + std::vector<metaIndex *> List; + std::map<std::string, std::string> Options; + if(Type->CreateItem(List, *I, "", "", Options)) + { + // we have our own CacheFile that gives us a SourceList + // with superpowerz + SourceList *sources = (SourceList*)Cache.GetSourceList(); + sources->AddMetaIndex(List[0]); + } + } + } + } + + // then open the cache if (Cache.OpenForInstall() == false || Cache.CheckDeps(CmdL.FileSize() != 1) == false) return false; - + std::map<unsigned short, APT::VersionSet> verset; if(!DoCacheManipulationFromCommandLine(CmdL, Cache, verset)) diff --git a/apt-private/private-list.cc b/apt-private/private-list.cc index b69002103..e85aaf64c 100644 --- a/apt-private/private-list.cc +++ b/apt-private/private-list.cc @@ -37,28 +37,20 @@ struct PackageSortAlphabetic /*{{{*/ return (l_name < r_name); } }; - /*}}}*/ -class PackageNameMatcher : public Matcher /*{{{*/ + +class PackageNameMatcher : public Matcher { -#ifdef PACKAGE_MATCHER_ABI_COMPAT -#define PackageMatcher PackageNameMatchesFnmatch -#endif public: PackageNameMatcher(const char **patterns) { for(int i=0; patterns[i] != NULL; ++i) { std::string pattern = patterns[i]; -#ifdef PACKAGE_MATCHER_ABI_COMPAT - APT::CacheFilter::PackageNameMatchesFnmatch *cachefilter = NULL; - cachefilter = new APT::CacheFilter::PackageNameMatchesFnmatch(pattern); -#else APT::CacheFilter::PackageMatcher *cachefilter = NULL; if(_config->FindB("APT::Cmd::Use-Regexp", false) == true) cachefilter = new APT::CacheFilter::PackageNameMatchesRegEx(pattern); else cachefilter = new APT::CacheFilter::PackageNameMatchesFnmatch(pattern); -#endif filters.push_back(cachefilter); } } diff --git a/cmdline/apt-get.cc b/cmdline/apt-get.cc index 566103f8c..f682074a7 100644 --- a/cmdline/apt-get.cc +++ b/cmdline/apt-get.cc @@ -828,13 +828,10 @@ static bool DoSource(CommandLine &CmdL) queued.insert(Last->Index().ArchiveURI(I->Path)); // check if we have a file with that md5 sum already localy - if(!I->MD5Hash.empty() && FileExists(flNotDir(I->Path))) + if(!I->Hash.empty() && FileExists(flNotDir(I->Path))) { - FileFd Fd(flNotDir(I->Path), FileFd::ReadOnly); - MD5Summation sum; - sum.AddFD(Fd.Fd(), Fd.Size()); - Fd.Close(); - if((string)sum.Result() == I->MD5Hash) + HashString hash_string = HashString(I->Hash); + if(hash_string.VerifyFile(flNotDir(I->Path))) { ioprintf(c1out,_("Skipping already downloaded file '%s'\n"), flNotDir(I->Path).c_str()); @@ -843,7 +840,7 @@ static bool DoSource(CommandLine &CmdL) } new pkgAcqFile(&Fetcher,Last->Index().ArchiveURI(I->Path), - I->MD5Hash,I->Size, + I->Hash,I->Size, Last->Index().SourceInfo(*Last,*I),Src); } } diff --git a/debian/changelog b/debian/changelog index 57fa52f29..ce57ed639 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,16 @@ +apt (1.1~exp1) UNRELEASED; urgency=low + + [ Michael Vogt ] + * lp:~mvo/apt/webserver-simulate-broken-with-fix346386: + - fix invalid InRelease file download checking and add regression + test to server broken files to the buildin test webserver + * stop exporting the accidently exported parsenetrc() symbol + * [ABI-Break] lp:~mvo/apt/source-hashes: + - use sha{512,256,1} for deb-src when available LP: #1098738 + * [ABI-Break] remove the PACKAGE_MATCHER_ABI_COMPAT defines + + -- Michael Vogt <michael.vogt@ubuntu.com> Wed, 07 May 2014 17:48:24 +0200 + apt (1.0.3) unstable; urgency=medium [ Michael Vogt ] diff --git a/debian/control b/debian/control index ff984db75..4c795cf30 100644 --- a/debian/control +++ b/debian/control @@ -38,7 +38,7 @@ Description: commandline package manager * apt-config as an interface to the configuration settings * apt-key as an interface to manage authentication keys -Package: libapt-pkg4.12 +Package: libapt-pkg4.13 Architecture: any Multi-Arch: same Pre-Depends: ${misc:Pre-Depends} diff --git a/debian/libapt-pkg4.12.install.in b/debian/libapt-pkg4.13.install.in index 56bed39d3..56bed39d3 100644 --- a/debian/libapt-pkg4.12.install.in +++ b/debian/libapt-pkg4.13.install.in diff --git a/debian/libapt-pkg4.12.symbols b/debian/libapt-pkg4.13.symbols index 5d7b21f10..9b280c040 100644 --- a/debian/libapt-pkg4.12.symbols +++ b/debian/libapt-pkg4.13.symbols @@ -1,4 +1,4 @@ -libapt-pkg.so.4.12 libapt-pkg4.12 #MINVER# +libapt-pkg.so.4.13 libapt-pkg4.13 #MINVER# * Build-Depends-Package: libapt-pkg-dev TFRewritePackageOrder@Base 0.8.0 TFRewriteSourceOrder@Base 0.8.0 diff --git a/test/integration/framework b/test/integration/framework index eda3cebad..ab1274d9c 100644 --- a/test/integration/framework +++ b/test/integration/framework @@ -244,7 +244,8 @@ setupenvironment() { gpg --quiet --check-trustdb --secret-keyring $SECRETKEYRING --keyring $SECRETKEYRING >/dev/null 2>&1 # cleanup the environment a bit - export PATH="${PATH}:/usr/local/sbin:/usr/sbin:/sbin" + # prefer our apt binaries over the system apt binaries + export PATH="${BUILDDIRECTORY}:${PATH}:/usr/local/sbin:/usr/sbin:/sbin" export LC_ALL=C.UTF-8 unset LANGUAGE APT_CONFIG unset GREP_OPTIONS DEB_BUILD_PROFILES diff --git a/test/integration/skip-aptwebserver b/test/integration/skip-aptwebserver new file mode 100755 index 000000000..0622941ce --- /dev/null +++ b/test/integration/skip-aptwebserver @@ -0,0 +1,25 @@ +#!/bin/sh +set -e + +TESTDIR=$(readlink -f $(dirname $0)) +. $TESTDIR/framework + +setupenvironment +configarchitecture 'amd64' + +buildsimplenativepackage 'apt' 'all' '1.0' 'stable' + +setupaptarchive +changetowebserver + +rm -rf rootdir/var/lib/apt/lists +aptget update -qq +testequal 'Hit http://localhost stable InRelease +Hit http://localhost stable/main Sources +Hit http://localhost stable/main amd64 Packages +Hit http://localhost stable/main Translation-en +Reading package lists...' aptget update + +mv rootdir/var/lib/apt/lists/localhost* rootdir/var/lib/apt/lists/partial +aptget update + diff --git a/test/integration/test-bug-602412-dequote-redirect b/test/integration/test-bug-602412-dequote-redirect index 6393f0c27..4901a32d7 100755 --- a/test/integration/test-bug-602412-dequote-redirect +++ b/test/integration/test-bug-602412-dequote-redirect @@ -20,11 +20,14 @@ testrun() { testsuccess --nomsg aptget update # check that I-M-S header is kept in redirections + local LOG='update.log' + # strip away the [ 304 B ] info + aptget update 2>&1 | sed -e 's/\ \[.*//' > $LOG testequal "Hit $1 unstable InRelease Hit $1 unstable/main Sources Hit $1 unstable/main amd64 Packages Hit $1 unstable/main Translation-en -Reading package lists..." aptget update +Reading package lists..." cat $LOG msgtest 'Test redirection works in' 'package download' testsuccess --nomsg aptget install unrelated --download-only -y diff --git a/test/integration/test-bug-683786-build-dep-on-virtual-packages b/test/integration/test-bug-683786-build-dep-on-virtual-packages index 879d6a3bc..65862c572 100755 --- a/test/integration/test-bug-683786-build-dep-on-virtual-packages +++ b/test/integration/test-bug-683786-build-dep-on-virtual-packages @@ -38,8 +38,8 @@ Building dependency tree... The following NEW packages will be installed: po-debconf 0 upgraded, 1 newly installed, 0 to remove and 0 not upgraded. -Inst po-debconf (1 unstable, unstable [all]) -Conf po-debconf (1 unstable, unstable [all])' aptget build-dep dash -s +Inst po-debconf (1 unstable [all]) +Conf po-debconf (1 unstable [all])' aptget build-dep dash -s testequal 'Reading package lists... Building dependency tree... diff --git a/test/integration/test-debsrc-hashes b/test/integration/test-debsrc-hashes new file mode 100755 index 000000000..5e917232b --- /dev/null +++ b/test/integration/test-debsrc-hashes @@ -0,0 +1,77 @@ +#!/bin/sh +set -e + +TESTDIR=$(readlink -f $(dirname $0)) +. $TESTDIR/framework + +setupenvironment +configarchitecture "i386" + +# pkg-sha256-bad has a bad SHA sum, but good MD5 sum. If apt is +# checking the best available hash (as it should), this will trigger +# a hash mismatch. + +cat > aptarchive/Sources <<EOF +Package: pkg-md5-ok +Binary: pkg-md5-ok +Version: 1.0 +Maintainer: Joe Sixpack <joe@example.org> +Architecture: i386 +Files: + d41d8cd98f00b204e9800998ecf8427e 0 pkg-md5-ok_1.0.dsc + d41d8cd98f00b204e9800998ecf8427e 0 pkg-md5-ok_1.0.tar.gz + +Package: pkg-sha256-ok +Binary: pkg-sha256-ok +Version: 1.0 +Maintainer: Joe Sixpack <joe@example.org> +Architecture: i386 +Files: + d41d8cd98f00b204e9800998ecf8427e 0 pkg-sha256-ok_1.0.dsc + d41d8cd98f00b204e9800998ecf8427e 0 pkg-sha256-ok_1.0.tar.gz +Checksums-Sha1: + da39a3ee5e6b4b0d3255bfef95601890afd80709 0 pkg-sha256-ok_1.0.dsc + da39a3ee5e6b4b0d3255bfef95601890afd80709 0 pkg-sha256-ok_1.0.tar.gz +Checksums-Sha256: + e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 pkg-sha256-ok_1.0.dsc + e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 pkg-sha256-ok_1.0.tar.gz + +Package: pkg-sha256-bad +Binary: pkg-sha256-bad +Version: 1.0 +Maintainer: Joe Sixpack <joe@example.org> +Architecture: i386 +Files: + d41d8cd98f00b204e9800998ecf8427e 0 pkg-sha256-bad_1.0.dsc + d41d8cd98f00b204e9800998ecf8427e 0 pkg-sha256-bad_1.0.tar.gz +Checksums-Sha1: + da39a3ee5e6b4b0d3255bfef95601890afd80709 0 pkg-sha256-bad_1.0.dsc + da39a3ee5e6b4b0d3255bfef95601890afd80709 0 pkg-sha256-bad_1.0.tar.gz +Checksums-Sha256: + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 0 pkg-sha256-bad_1.0.dsc + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 0 pkg-sha256-bad_1.0.tar.gz +EOF + +# create fetchable files +for x in "pkg-md5-ok" "pkg-sha256-ok" "pkg-sha256-bad"; do + touch aptarchive/${x}_1.0.dsc + touch aptarchive/${x}_1.0.tar.gz +done + +testok() { + msgtest "Test for hash ok of" "$*" + $* 2>&1 | grep "Download complete" > /dev/null && msgpass || msgfail +} + +testmismatch() { + msgtest "Test for hash mismatch of" "$*" + $* 2>&1 | grep "Hash Sum mismatch" > /dev/null && msgpass || msgfail +} + +setupaptarchive +changetowebserver +aptget update -qq + +testok aptget source -d pkg-md5-ok +testok aptget source -d pkg-sha256-ok +testmismatch aptget source -d pkg-sha256-bad diff --git a/test/integration/test-ubuntu-bug-346386-apt-get-update-paywall b/test/integration/test-ubuntu-bug-346386-apt-get-update-paywall index 7112d2b45..1a7db0adc 100755 --- a/test/integration/test-ubuntu-bug-346386-apt-get-update-paywall +++ b/test/integration/test-ubuntu-bug-346386-apt-get-update-paywall @@ -22,7 +22,7 @@ Config-Item: Acquire::http::DependOnSTDIN=0 600 Acquire URI URI: http://localhost:8080/holygrail Filename: knights-talking -' | ${METHODSDIR}/http >/dev/null 2>&1 && msgpass || msgfail +' | LD_LIBRARY_PATH=${BUILDDIRECTORY} ${METHODSDIR}/http >/dev/null 2>&1 && msgpass || msgfail testfileequal knights-talking 'ni ni ni' ensure_n_canary_strings_in_dir() { diff --git a/test/interactive-helper/makefile b/test/interactive-helper/makefile index 8dc014b98..4633b78ce 100644 --- a/test/interactive-helper/makefile +++ b/test/interactive-helper/makefile @@ -39,7 +39,7 @@ include $(PROGRAM_H) #SOURCE = rpmver.cc #include $(PROGRAM_H) -# Program for testing udevcdrom +# very simple webserver for APT testing PROGRAM=aptwebserver SLIBS = -lapt-pkg -lpthread LIB_MAKES = apt-pkg/makefile diff --git a/test/libapt/fileutl_test.cc b/test/libapt/fileutl_test.cc index 643c02297..cdf7ea479 100644 --- a/test/libapt/fileutl_test.cc +++ b/test/libapt/fileutl_test.cc @@ -224,3 +224,61 @@ TEST(FileUtlTest, GetTempDir) if (old_tmpdir.empty() == false) setenv("TMPDIR", old_tmpdir.c_str(), 1); } +TEST(FileUtlTest, Popen) +{ + FileFd Fd; + pid_t Child; + char buf[1024]; + std::string s; + unsigned long long n = 0; + std::vector<std::string> OpenFds; + + // count Fds to ensure we don't have a resource leak + if(FileExists("/proc/self/fd")) + OpenFds = Glob("/proc/self/fd/*"); + + // output something + const char* Args[10] = {"/bin/echo", "meepmeep", NULL}; + bool res = Popen(Args, Fd, Child, FileFd::ReadOnly); + Fd.Read(buf, sizeof(buf)-1, &n); + buf[n] = 0; + EXPECT_NE(n, 0); + EXPECT_EQ(res, true); + EXPECT_STREQ(buf, "meepmeep\n"); + + // wait for the child to exit and cleanup + ExecWait(Child, "PopenRead"); + Fd.Close(); + + // ensure that after a close all is good again + if(FileExists("/proc/self/fd")) + EXPECT_EQ(Glob("/proc/self/fd/*").size(), OpenFds.size()); + + + // ReadWrite is not supported + res = Popen(Args, Fd, Child, FileFd::ReadWrite); + EXPECT_EQ(res, false); + _error->Discard(); + + // write something + Args[0] = "/bin/bash"; + Args[1] = "-c"; + Args[2] = "read"; + Args[3] = NULL; + res = Popen(Args, Fd, Child, FileFd::WriteOnly); + s = "\n"; + Fd.Write(s.c_str(), s.size()); + Fd.Close(); + ExecWait(Child, "PopenWrite"); +} +TEST(FileUtlTest, flAbsPath) +{ + std::string cwd = SafeGetCWD(); + int res = chdir("/bin/"); + EXPECT_EQ(res, 0); + std::string p = flAbsPath("ls"); + EXPECT_EQ(p, "/bin/ls"); + + res = chdir(cwd.c_str()); + EXPECT_EQ(res, 0); +} |