diff options
Diffstat (limited to 'apt-pkg')
35 files changed, 1193 insertions, 406 deletions
diff --git a/apt-pkg/acquire-item.cc b/apt-pkg/acquire-item.cc index c48443eff..b76921312 100644 --- a/apt-pkg/acquire-item.cc +++ b/apt-pkg/acquire-item.cc @@ -143,6 +143,32 @@ void pkgAcquire::Item::Rename(string From,string To) } } /*}}}*/ +bool pkgAcquire::Item::RenameOnError(pkgAcquire::Item::RenameOnErrorState const error)/*{{{*/ +{ + if(FileExists(DestFile)) + Rename(DestFile, DestFile + ".FAILED"); + + switch (error) + { + case HashSumMismatch: + ErrorText = _("Hash Sum mismatch"); + Status = StatAuthError; + ReportMirrorFailure("HashChecksumFailure"); + break; + case SizeMismatch: + ErrorText = _("Size mismatch"); + Status = StatAuthError; + ReportMirrorFailure("SizeFailure"); + break; + case InvalidFormat: + ErrorText = _("Invalid file format"); + Status = StatError; + // do not report as usually its not the mirrors fault, but Portal/Proxy + break; + } + return false; +} + /*}}}*/ // Acquire::Item::ReportMirrorFailure /*{{{*/ // --------------------------------------------------------------------- void pkgAcquire::Item::ReportMirrorFailure(string FailCode) @@ -434,7 +460,7 @@ bool pkgAcqDiffIndex::ParseDiffIndex(string IndexDiffFile) /*{{{*/ if (available_patches.empty() == false) { // patching with too many files is rather slow compared to a fast download - unsigned long const fileLimit = _config->FindI("Acquire::PDiffs::FileLimit", 0); + unsigned long const fileLimit = _config->FindI("Acquire::PDiffs::FileLimit", 20); if (fileLimit != 0 && fileLimit < available_patches.size()) { if (Debug) @@ -595,9 +621,7 @@ void pkgAcqIndexDiffs::Finish(bool allDone) if(!ExpectedHash.empty() && !ExpectedHash.VerifyFile(DestFile)) { - Status = StatAuthError; - ErrorText = _("MD5Sum mismatch"); - Rename(DestFile,DestFile + ".FAILED"); + RenameOnError(HashSumMismatch); Dequeue(); return; } @@ -866,10 +890,7 @@ void pkgAcqIndex::Done(string Message,unsigned long long Size,string Hash, if (!ExpectedHash.empty() && ExpectedHash.toStr() != Hash) { - Status = StatAuthError; - ErrorText = _("Hash Sum mismatch"); - Rename(DestFile,DestFile + ".FAILED"); - ReportMirrorFailure("HashChecksumFailure"); + RenameOnError(HashSumMismatch); return; } @@ -878,22 +899,18 @@ void pkgAcqIndex::Done(string Message,unsigned long long Size,string Hash, if (Verify == true) { FileFd fd(DestFile, FileFd::ReadOnly); - pkgTagSection sec; - pkgTagFile tag(&fd); - - // Only test for correctness if the file is not empty (empty is ok) - if (fd.Size() > 0) { - if (_error->PendingError() || !tag.Step(sec)) { - Status = StatError; - _error->DumpErrors(); - Rename(DestFile,DestFile + ".FAILED"); - return; - } else if (!sec.Exists("Package")) { - Status = StatError; - ErrorText = ("Encountered a section with no Package: header"); - Rename(DestFile,DestFile + ".FAILED"); - return; - } + // Only test for correctness if the file is not empty (empty is ok) + if (fd.FileSize() > 0) + { + pkgTagSection sec; + pkgTagFile tag(&fd); + + // all our current indexes have a field 'Package' in each section + if (_error->PendingError() == true || tag.Step(sec) == false || sec.Exists("Package") == false) + { + RenameOnError(InvalidFormat); + return; + } } } @@ -984,6 +1001,8 @@ void pkgAcqIndex::Done(string Message,unsigned long long Size,string Hash, DestFile += ".decomp"; Desc.URI = decompProg + ":" + FileName; QueueURI(Desc); + + // FIXME: this points to a c++ string that goes out of scope Mode = decompProg.c_str(); } /*}}}*/ @@ -1067,8 +1086,7 @@ pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire *Owner, /*{{{*/ string Final = _config->FindDir("Dir::State::lists"); Final += URItoFileName(RealURI); - struct stat Buf; - if (stat(Final.c_str(),&Buf) == 0) + if (RealFileExists(Final) == true) { // File was already in place. It needs to be re-downloaded/verified // because Release might have changed, we do give it a differnt @@ -1082,6 +1100,19 @@ pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire *Owner, /*{{{*/ QueueURI(Desc); } /*}}}*/ +pkgAcqMetaSig::~pkgAcqMetaSig() /*{{{*/ +{ + // if the file was never queued undo file-changes done in the constructor + if (QueueCounter == 1 && Status == StatIdle && FileSize == 0 && Complete == false && + LastGoodSig.empty() == false) + { + string const Final = _config->FindDir("Dir::State::lists") + URItoFileName(RealURI); + if (RealFileExists(Final) == false && RealFileExists(LastGoodSig) == true) + Rename(LastGoodSig, Final); + } + +} + /*}}}*/ // pkgAcqMetaSig::Custom600Headers - Insert custom request headers /*{{{*/ // --------------------------------------------------------------------- /* The only header we use is the last-modified header. */ @@ -1369,9 +1400,20 @@ void pkgAcqMetaIndex::QueueIndexes(bool verify) /*{{{*/ { HashString ExpectedIndexHash; const indexRecords::checkSum *Record = MetaIndexParser->Lookup((*Target)->MetaKey); + bool compressedAvailable = false; if (Record == NULL) { - if (verify == true && (*Target)->IsOptional() == false) + if ((*Target)->IsOptional() == true) + { + std::vector<std::string> types = APT::Configuration::getCompressionTypes(); + for (std::vector<std::string>::const_iterator t = types.begin(); t != types.end(); ++t) + if (MetaIndexParser->Exists(string((*Target)->MetaKey).append(".").append(*t)) == true) + { + compressedAvailable = true; + break; + } + } + else if (verify == true) { Status = StatAuthError; strprintf(ErrorText, _("Unable to find expected entry '%s' in Release file (Wrong sources.list entry or malformed file)"), (*Target)->MetaKey.c_str()); @@ -1400,7 +1442,7 @@ void pkgAcqMetaIndex::QueueIndexes(bool verify) /*{{{*/ if ((*Target)->IsSubIndex() == true) new pkgAcqSubIndex(Owner, (*Target)->URI, (*Target)->Description, (*Target)->ShortDesc, ExpectedIndexHash); - else if (transInRelease == false || MetaIndexParser->Exists((*Target)->MetaKey) == true) + else if (transInRelease == false || Record != NULL || compressedAvailable == true) { if (_config->FindB("Acquire::PDiffs",true) == true && transInRelease == true && MetaIndexParser->Exists(string((*Target)->MetaKey).append(".diff/Index")) == true) @@ -1584,14 +1626,25 @@ pkgAcqMetaClearSig::pkgAcqMetaClearSig(pkgAcquire *Owner, /*{{{*/ // keep the old InRelease around in case of transistent network errors string const Final = _config->FindDir("Dir::State::lists") + URItoFileName(RealURI); - struct stat Buf; - if (stat(Final.c_str(),&Buf) == 0) + if (RealFileExists(Final) == true) { string const LastGoodSig = DestFile + ".reverify"; Rename(Final,LastGoodSig); } } /*}}}*/ +pkgAcqMetaClearSig::~pkgAcqMetaClearSig() /*{{{*/ +{ + // if the file was never queued undo file-changes done in the constructor + if (QueueCounter == 1 && Status == StatIdle && FileSize == 0 && Complete == false) + { + string const Final = _config->FindDir("Dir::State::lists") + URItoFileName(RealURI); + string const LastGoodSig = DestFile + ".reverify"; + if (RealFileExists(Final) == false && RealFileExists(LastGoodSig) == true) + Rename(LastGoodSig, Final); + } +} + /*}}}*/ // pkgAcqMetaClearSig::Custom600Headers - Insert custom request headers /*{{{*/ // --------------------------------------------------------------------- // FIXME: this can go away once the InRelease file is used widely @@ -1683,34 +1736,40 @@ pkgAcqArchive::pkgAcqArchive(pkgAcquire *Owner,pkgSourceList *Sources, } // check if we have one trusted source for the package. if so, switch - // to "TrustedOnly" mode + // to "TrustedOnly" mode - but only if not in AllowUnauthenticated mode + bool const allowUnauth = _config->FindB("APT::Get::AllowUnauthenticated", false); + bool const debugAuth = _config->FindB("Debug::pkgAcquire::Auth", false); + bool seenUntrusted = false; 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)) - { + + if (debugAuth == true) std::cerr << "Checking index: " << Index->Describe() - << "(Trusted=" << Index->IsTrusted() << ")\n"; - } - if (Index->IsTrusted()) { + << "(Trusted=" << Index->IsTrusted() << ")" << std::endl; + + if (Index->IsTrusted() == true) + { Trusted = true; - break; + if (allowUnauth == false) + break; } + else + seenUntrusted = true; } // "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) + if (allowUnauth == true && seenUntrusted == true) Trusted = false; // Select a source 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()); + _error->Error(_("Can't find a source to download version '%s' of '%s'"), + Version.VerStr(), Version.ParentPkg().FullName(false).c_str()); } /*}}}*/ // AcqArchive::QueueNext - Queue the next file source /*{{{*/ @@ -1864,18 +1923,14 @@ void pkgAcqArchive::Done(string Message,unsigned long long Size,string CalcHash, // Check the size if (Size != Version->Size) { - Status = StatError; - ErrorText = _("Size mismatch"); + RenameOnError(SizeMismatch); return; } // Check the hash if(ExpectedHash.toStr() != CalcHash) { - Status = StatError; - ErrorText = _("Hash Sum mismatch"); - if(FileExists(DestFile)) - Rename(DestFile,DestFile + ".FAILED"); + RenameOnError(HashSumMismatch); return; } @@ -2015,9 +2070,7 @@ void pkgAcqFile::Done(string Message,unsigned long long Size,string CalcHash, // Check the hash if(!ExpectedHash.empty() && ExpectedHash.toStr() != CalcHash) { - Status = StatError; - ErrorText = _("Hash Sum mismatch"); - Rename(DestFile,DestFile + ".FAILED"); + RenameOnError(HashSumMismatch); return; } diff --git a/apt-pkg/acquire-item.h b/apt-pkg/acquire-item.h index 51d539450..6b4f73708 100644 --- a/apt-pkg/acquire-item.h +++ b/apt-pkg/acquire-item.h @@ -83,7 +83,7 @@ class pkgAcquire::Item : public WeakPointable * overwritten. */ void Rename(std::string From,std::string To); - + public: /** \brief The current status of this item. */ @@ -281,6 +281,21 @@ class pkgAcquire::Item : public WeakPointable * pkgAcquire::Remove. */ virtual ~Item(); + + protected: + + enum RenameOnErrorState { + HashSumMismatch, + SizeMismatch, + InvalidFormat + }; + + /** \brief Rename failed file and set error + * + * \param state respresenting the error we encountered + * \param errorMsg a message describing the error + */ + bool RenameOnError(RenameOnErrorState const state); }; /*}}}*/ /** \brief Information about an index patch (aka diff). */ /*{{{*/ @@ -774,6 +789,7 @@ class pkgAcqMetaSig : public pkgAcquire::Item std::string MetaIndexURI, std::string MetaIndexURIDesc, std::string MetaIndexShortDesc, const std::vector<struct IndexTarget*>* IndexTargets, indexRecords* MetaIndexParser); + virtual ~pkgAcqMetaSig(); }; /*}}}*/ /** \brief An item that is responsible for downloading the meta-index {{{ @@ -904,6 +920,7 @@ public: std::string const &MetaSigURI, std::string const &MetaSigURIDesc, std::string const &MetaSigShortDesc, const std::vector<struct IndexTarget*>* IndexTargets, indexRecords* MetaIndexParser); + virtual ~pkgAcqMetaClearSig(); }; /*}}}*/ /** \brief An item that is responsible for fetching a package file. {{{ @@ -980,7 +997,7 @@ class pkgAcqArchive : public pkgAcquire::Item * * \param Version The package version to download. * - * \param StoreFilename A location in which the actual filename of + * \param[out] 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. diff --git a/apt-pkg/algorithms.cc b/apt-pkg/algorithms.cc index 85799a11b..69d4acd83 100644 --- a/apt-pkg/algorithms.cc +++ b/apt-pkg/algorithms.cc @@ -459,6 +459,49 @@ bool pkgAllUpgrade(pkgDepCache &Cache) return Fix.ResolveByKeep(); } /*}}}*/ +// AllUpgradeNoDelete - Upgrade without removing packages /*{{{*/ +// --------------------------------------------------------------------- +/* Right now the system must be consistent before this can be called. + * Upgrade as much as possible without deleting anything (useful for + * stable systems) + */ +bool pkgAllUpgradeNoDelete(pkgDepCache &Cache) +{ + pkgDepCache::ActionGroup group(Cache); + + pkgProblemResolver Fix(&Cache); + + if (Cache.BrokenCount() != 0) + return false; + + // provide the initial set of stuff we want to upgrade by marking + // all upgradable packages for upgrade + for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; ++I) + { + if (I->CurrentVer != 0 && Cache[I].InstallVer != 0) + { + if (_config->FindB("APT::Ignore-Hold",false) == false) + if (I->SelectedState == pkgCache::State::Hold) + continue; + + Cache.MarkInstall(I, false, 0, false); + } + } + + // then let auto-install loose + for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; ++I) + if (Cache[I].Install()) + Cache.MarkInstall(I, true, 0, false); + + // ... but it may remove stuff, we we need to clean up afterwards again + for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; ++I) + if (Cache[I].Delete() == true) + Cache.MarkKeep(I, false, false); + + // resolve remaining issues via keep + return Fix.ResolveByKeep(); +} + /*}}}*/ // MinimizeUpgrade - Minimizes the set of packages to be upgraded /*{{{*/ // --------------------------------------------------------------------- /* This simply goes over the entire set of packages and tries to keep @@ -550,14 +593,12 @@ void pkgProblemResolver::MakeScores() unsigned long Size = Cache.Head().PackageCount; memset(Scores,0,sizeof(*Scores)*Size); - // Maps to pkgCache::State::VerPriority - // which is "Important Required Standard Optional Extra" - // (yes, that is confusing, the order of pkgCache::State::VerPriority - // needs to be adjusted but that requires a ABI break) + // maps to pkgCache::State::VerPriority: + // Required Important Standard Optional Extra int PrioMap[] = { 0, - _config->FindI("pkgProblemResolver::Scores::Important",2), _config->FindI("pkgProblemResolver::Scores::Required",3), + _config->FindI("pkgProblemResolver::Scores::Important",2), _config->FindI("pkgProblemResolver::Scores::Standard",1), _config->FindI("pkgProblemResolver::Scores::Optional",-1), _config->FindI("pkgProblemResolver::Scores::Extra",-2) diff --git a/apt-pkg/algorithms.h b/apt-pkg/algorithms.h index 7f58c8eed..a499db8ba 100644 --- a/apt-pkg/algorithms.h +++ b/apt-pkg/algorithms.h @@ -143,7 +143,11 @@ class pkgProblemResolver /*{{{*/ bool pkgDistUpgrade(pkgDepCache &Cache); bool pkgApplyStatus(pkgDepCache &Cache); bool pkgFixBroken(pkgDepCache &Cache); + bool pkgAllUpgrade(pkgDepCache &Cache); + +bool pkgAllUpgradeNoDelete(pkgDepCache &Cache); + bool pkgMinimizeUpgrade(pkgDepCache &Cache); void pkgPrioSortList(pkgCache &Cache,pkgCache::Version **List); diff --git a/apt-pkg/aptconfiguration.cc b/apt-pkg/aptconfiguration.cc index 37c846582..115d11616 100644 --- a/apt-pkg/aptconfiguration.cc +++ b/apt-pkg/aptconfiguration.cc @@ -388,12 +388,12 @@ std::vector<std::string> const Configuration::getArchitectures(bool const &Cache if (dpkgMultiArch == 0) { close(external[0]); std::string const chrootDir = _config->FindDir("DPkg::Chroot-Directory"); - if (chrootDir != "/" && chroot(chrootDir.c_str()) != 0) - _error->WarningE("getArchitecture", "Couldn't chroot into %s for dpkg --print-foreign-architectures", chrootDir.c_str()); int const nullfd = open("/dev/null", O_RDONLY); dup2(nullfd, STDIN_FILENO); dup2(external[1], STDOUT_FILENO); dup2(nullfd, STDERR_FILENO); + if (chrootDir != "/" && chroot(chrootDir.c_str()) != 0 && chdir("/") != 0) + _error->WarningE("getArchitecture", "Couldn't chroot into %s for dpkg --print-foreign-architectures", chrootDir.c_str()); execvp(Args[0], (char**) &Args[0]); _error->WarningE("getArchitecture", "Can't detect foreign architectures supported by dpkg!"); _exit(100); @@ -453,7 +453,7 @@ void Configuration::setDefaultConfigurationForCompressors() { _config->CndSet("Dir::Bin::bzip2", "/bin/bzip2"); _config->CndSet("Dir::Bin::xz", "/usr/bin/xz"); if (FileExists(_config->FindFile("Dir::Bin::xz")) == true) { - _config->Clear("Dir::Bin::lzma"); + _config->Set("Dir::Bin::lzma", _config->FindFile("Dir::Bin::xz")); _config->Set("APT::Compressor::lzma::Binary", "xz"); if (_config->Exists("APT::Compressor::lzma::CompressArg") == false) { _config->Set("APT::Compressor::lzma::CompressArg::", "--format=lzma"); diff --git a/apt-pkg/cachefilter.cc b/apt-pkg/cachefilter.cc index 64cde41d1..57b9af159 100644 --- a/apt-pkg/cachefilter.cc +++ b/apt-pkg/cachefilter.cc @@ -55,6 +55,17 @@ PackageNameMatchesRegEx::~PackageNameMatchesRegEx() { /*{{{*/ } /*}}}*/ +// Fnmatch support /*{{{*/ +//---------------------------------------------------------------------- +bool PackageNameMatchesFnmatch::operator() (pkgCache::PkgIterator const &Pkg) {/*{{{*/ + return fnmatch(Pattern.c_str(), Pkg.Name(), FNM_CASEFOLD) == 0; +} + /*}}}*/ +bool PackageNameMatchesFnmatch::operator() (pkgCache::GrpIterator const &Grp) {/*{{{*/ + return fnmatch(Pattern.c_str(), Grp.Name(), FNM_CASEFOLD) == 0; +} + /*}}}*/ + // CompleteArch to <kernel>-<cpu> tuple /*{{{*/ //---------------------------------------------------------------------- /* The complete architecture, consisting of <kernel>-<cpu>. */ diff --git a/apt-pkg/cachefilter.h b/apt-pkg/cachefilter.h index 25cd43f47..34b7d0b46 100644 --- a/apt-pkg/cachefilter.h +++ b/apt-pkg/cachefilter.h @@ -14,6 +14,10 @@ /*}}}*/ 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) */ @@ -26,6 +30,19 @@ public: ~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 @@ -55,6 +72,73 @@ public: 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 ~PackageMatcher() {}; +}; + +// PackageNameMatchesRegEx /*{{{*/ +class PackageNameMatchesRegEx : public PackageMatcher { + /** \brief dpointer placeholder (for later in case we need it) */ + void *d; + regex_t* pattern; +public: + PackageNameMatchesRegEx(std::string const &Pattern); + virtual bool operator() (pkgCache::PkgIterator const &Pkg); + virtual bool operator() (pkgCache::GrpIterator const &Grp); + virtual ~PackageNameMatchesRegEx(); +}; + /*}}}*/ +// PackageNameMatchesFnmatch /*{{{*/ + class PackageNameMatchesFnmatch : public PackageMatcher{ + /** \brief dpointer placeholder (for later in case we need it) */ + void *d; + const std::string Pattern; +public: + PackageNameMatchesFnmatch(std::string const &Pattern) + : Pattern(Pattern) {}; + virtual bool operator() (pkgCache::PkgIterator const &Pkg); + virtual bool operator() (pkgCache::GrpIterator const &Grp); + virtual ~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 : public PackageMatcher { + 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); + virtual bool operator() (pkgCache::PkgIterator const &Pkg); + virtual bool operator() (pkgCache::VerIterator const &Ver); + virtual ~PackageArchitectureMatchesSpecification(); +}; +#endif /*}}}*/ } } diff --git a/apt-pkg/cacheiterators.h b/apt-pkg/cacheiterators.h index 179a0e963..886d84838 100644 --- a/apt-pkg/cacheiterators.h +++ b/apt-pkg/cacheiterators.h @@ -220,6 +220,7 @@ class pkgCache::VerIterator : public Iterator<Version, VerIterator> { inline VerFileIterator FileList() const; bool Downloadable() const; inline const char *PriorityType() const {return Owner->Priority(S->Priority);}; + const char *MultiArchType() const; std::string RelStr() const; bool Automatic() const; diff --git a/apt-pkg/cacheset.cc b/apt-pkg/cacheset.cc index 1fea4f94a..0147f7e86 100644 --- a/apt-pkg/cacheset.cc +++ b/apt-pkg/cacheset.cc @@ -155,6 +155,69 @@ bool PackageContainerInterface::FromRegEx(PackageContainerInterface * const pci, return true; } /*}}}*/ +// FromFnmatch - Returns the package defined by this fnmatch /*{{{*/ +bool +PackageContainerInterface::FromFnmatch(PackageContainerInterface * const pci, + pkgCacheFile &Cache, + std::string pattern, + CacheSetHelper &helper) +{ + static const char * const isfnmatch = ".?*[]!"; + if (pattern.find_first_of(isfnmatch) == std::string::npos) + return false; + + bool const wasEmpty = pci->empty(); + if (wasEmpty == true) + pci->setConstructor(FNMATCH); + + size_t archfound = pattern.find_last_of(':'); + std::string arch = "native"; + if (archfound != std::string::npos) { + arch = pattern.substr(archfound+1); + if (arch.find_first_of(isfnmatch) == std::string::npos) + pattern.erase(archfound); + else + arch = "native"; + } + + if (unlikely(Cache.GetPkgCache() == 0)) + return false; + + APT::CacheFilter::PackageNameMatchesFnmatch filter(pattern); + + bool found = false; + for (pkgCache::GrpIterator Grp = Cache.GetPkgCache()->GrpBegin(); Grp.end() == false; ++Grp) { + if (filter(Grp) == false) + continue; + pkgCache::PkgIterator Pkg = Grp.FindPkg(arch); + if (Pkg.end() == true) { + if (archfound == std::string::npos) { + std::vector<std::string> archs = APT::Configuration::getArchitectures(); + for (std::vector<std::string>::const_iterator a = archs.begin(); + a != archs.end() && Pkg.end() != true; ++a) + Pkg = Grp.FindPkg(*a); + } + if (Pkg.end() == true) + continue; + } + + pci->insert(Pkg); + helper.showRegExSelection(Pkg, pattern); + found = true; + } + + if (found == false) { + helper.canNotFindRegEx(pci, Cache, pattern); + pci->setConstructor(UNKNOWN); + return false; + } + + if (wasEmpty == false && pci->getConstructor() != UNKNOWN) + pci->setConstructor(UNKNOWN); + + return true; +} + /*}}}*/ // FromName - Returns the package defined by this string /*{{{*/ pkgCache::PkgIterator PackageContainerInterface::FromName(pkgCacheFile &Cache, std::string const &str, CacheSetHelper &helper) { @@ -239,6 +302,7 @@ bool PackageContainerInterface::FromString(PackageContainerInterface * const pci if (FromGroup(pci, Cache, str, helper) == false && FromTask(pci, Cache, str, helper) == false && + FromFnmatch(pci, Cache, str, helper) == false && FromRegEx(pci, Cache, str, helper) == false) { helper.canNotFindPackage(pci, Cache, str); diff --git a/apt-pkg/cacheset.h b/apt-pkg/cacheset.h index 2a45910ba..29103aad9 100644 --- a/apt-pkg/cacheset.h +++ b/apt-pkg/cacheset.h @@ -11,7 +11,6 @@ // Include Files /*{{{*/ #include <iostream> #include <fstream> -#include <list> #include <map> #include <set> #include <list> @@ -132,13 +131,14 @@ public: virtual bool empty() const = 0; virtual void clear() = 0; - enum Constructor { UNKNOWN, REGEX, TASK }; + enum Constructor { UNKNOWN, REGEX, TASK, FNMATCH }; virtual void setConstructor(Constructor const &con) = 0; virtual Constructor getConstructor() const = 0; static bool FromTask(PackageContainerInterface * const pci, pkgCacheFile &Cache, std::string pattern, CacheSetHelper &helper); static bool FromRegEx(PackageContainerInterface * const pci, pkgCacheFile &Cache, std::string pattern, CacheSetHelper &helper); static pkgCache::PkgIterator FromName(pkgCacheFile &Cache, std::string const &pattern, CacheSetHelper &helper); + static bool FromFnmatch(PackageContainerInterface * const pci, pkgCacheFile &Cache, std::string pattern, CacheSetHelper &helper); static bool FromGroup(PackageContainerInterface * const pci, pkgCacheFile &Cache, std::string pattern, CacheSetHelper &helper); static bool FromString(PackageContainerInterface * const pci, pkgCacheFile &Cache, std::string const &pattern, CacheSetHelper &helper); static bool FromCommandLine(PackageContainerInterface * const pci, pkgCacheFile &Cache, const char **cmdline, CacheSetHelper &helper); @@ -260,6 +260,16 @@ public: /*{{{*/ return FromRegEx(Cache, pattern, helper); } + static PackageContainer FromFnmatch(pkgCacheFile &Cache, std::string pattern, CacheSetHelper &helper) { + PackageContainer cont(FNMATCH); + PackageContainerInterface::FromFnmatch(&cont, Cache, pattern, helper); + return cont; + } + static PackageContainer FromFnMatch(pkgCacheFile &Cache, std::string const &pattern) { + CacheSetHelper helper; + return FromFnmatch(Cache, pattern, helper); + } + /** \brief returns a package specified by a string \param Cache the package is in diff --git a/apt-pkg/cdrom.h b/apt-pkg/cdrom.h index 4fc3d3928..7d19eb813 100644 --- a/apt-pkg/cdrom.h +++ b/apt-pkg/cdrom.h @@ -18,7 +18,7 @@ class pkgCdromStatus /*{{{*/ int totalSteps; public: - pkgCdromStatus() {}; + pkgCdromStatus() : totalSteps(0) {}; virtual ~pkgCdromStatus() {}; // total steps diff --git a/apt-pkg/contrib/cdromutl.cc b/apt-pkg/contrib/cdromutl.cc index 187f6bd59..afa01a562 100644 --- a/apt-pkg/contrib/cdromutl.cc +++ b/apt-pkg/contrib/cdromutl.cc @@ -122,8 +122,9 @@ bool MountCdrom(string Path, string DeviceName) if (Child == 0) { // Make all the fds /dev/null + int null_fd = open("/dev/null",O_RDWR); for (int I = 0; I != 3; I++) - dup2(open("/dev/null",O_RDWR),I); + dup2(null_fd, I); if (_config->Exists("Acquire::cdrom::"+Path+"::Mount") == true) { diff --git a/apt-pkg/contrib/cmndline.cc b/apt-pkg/contrib/cmndline.cc index 75d02cad4..2086d91ca 100644 --- a/apt-pkg/contrib/cmndline.cc +++ b/apt-pkg/contrib/cmndline.cc @@ -38,6 +38,42 @@ CommandLine::~CommandLine() delete [] FileList; } /*}}}*/ +// CommandLine::GetCommand - return the first non-option word /*{{{*/ +char const * CommandLine::GetCommand(Dispatch const * const Map, + unsigned int const argc, char const * const * const argv) +{ + // if there is a -- on the line there must be the word we search for around it + // as -- marks the end of the options, just not sure if the command can be + // considered an option or not, so accept both + for (size_t i = 1; i < argc; ++i) + { + if (strcmp(argv[i], "--") != 0) + continue; + ++i; + if (i < argc) + for (size_t j = 0; Map[j].Match != NULL; ++j) + if (strcmp(argv[i], Map[j].Match) == 0) + return Map[j].Match; + i -= 2; + if (i != 0) + for (size_t j = 0; Map[j].Match != NULL; ++j) + if (strcmp(argv[i], Map[j].Match) == 0) + return Map[j].Match; + return NULL; + } + // no --, so search for the first word matching a command + // FIXME: How like is it that an option parameter will be also a valid Match ? + for (size_t i = 1; i < argc; ++i) + { + if (*(argv[i]) == '-') + continue; + for (size_t j = 0; Map[j].Match != NULL; ++j) + if (strcmp(argv[i], Map[j].Match) == 0) + return Map[j].Match; + } + return NULL; +} + /*}}}*/ // CommandLine::Parse - Main action member /*{{{*/ // --------------------------------------------------------------------- /* */ @@ -361,6 +397,7 @@ bool CommandLine::DispatchArg(Dispatch *Map,bool NoMatch) void CommandLine::SaveInConfig(unsigned int const &argc, char const * const * const argv) { char cmdline[100 + argc * 50]; + memset(cmdline, 0, sizeof(cmdline)); unsigned int length = 0; bool lastWasOption = false; bool closeQuote = false; @@ -390,3 +427,15 @@ void CommandLine::SaveInConfig(unsigned int const &argc, char const * const * co _config->Set("CommandLine::AsString", cmdline); } /*}}}*/ +CommandLine::Args CommandLine::MakeArgs(char ShortOpt, char const *LongOpt, char const *ConfName, unsigned long Flags)/*{{{*/ +{ + /* In theory, this should be a constructor for CommandLine::Args instead, + but this breaks compatibility as gcc thinks this is a c++11 initializer_list */ + CommandLine::Args arg; + arg.ShortOpt = ShortOpt; + arg.LongOpt = LongOpt; + arg.ConfName = ConfName; + arg.Flags = Flags; + return arg; +} + /*}}}*/ diff --git a/apt-pkg/contrib/cmndline.h b/apt-pkg/contrib/cmndline.h index 9f505fd41..180276633 100644 --- a/apt-pkg/contrib/cmndline.h +++ b/apt-pkg/contrib/cmndline.h @@ -83,6 +83,12 @@ class CommandLine unsigned int FileSize() const; bool DispatchArg(Dispatch *List,bool NoMatch = true); + static char const * GetCommand(Dispatch const * const Map, + unsigned int const argc, char const * const * const argv); + + static CommandLine::Args MakeArgs(char ShortOpt, char const *LongOpt, + char const *ConfName, unsigned long Flags); + CommandLine(Args *AList,Configuration *Conf); ~CommandLine(); }; diff --git a/apt-pkg/contrib/configuration.cc b/apt-pkg/contrib/configuration.cc index 808a708a1..4ef4663c0 100644 --- a/apt-pkg/contrib/configuration.cc +++ b/apt-pkg/contrib/configuration.cc @@ -422,6 +422,18 @@ void Configuration::Clear(string const &Name, string const &Value) } /*}}}*/ +// Configuration::Clear - Clear everything /*{{{*/ +// --------------------------------------------------------------------- +void Configuration::Clear() +{ + const Configuration::Item *Top = Tree(0); + while( Top != 0 ) + { + Clear(Top->FullTag()); + Top = Top->Next; + } +} + /*}}}*/ // Configuration::Clear - Clear an entire tree /*{{{*/ // --------------------------------------------------------------------- /* */ @@ -811,7 +823,7 @@ bool ReadConfigFile(Configuration &Conf,const string &FName,bool const &AsSectio // Go down a level if (TermChar == '{') { - if (StackPos <= 100) + if (StackPos < sizeof(Stack)/sizeof(std::string)) Stack[StackPos++] = ParentTag; /* Make sectional tags incorperate the section into the diff --git a/apt-pkg/contrib/configuration.h b/apt-pkg/contrib/configuration.h index ea94c2fe6..8e09ea0a6 100644 --- a/apt-pkg/contrib/configuration.h +++ b/apt-pkg/contrib/configuration.h @@ -94,6 +94,7 @@ class Configuration // clear a whole tree void Clear(const std::string &Name); + void Clear(); // remove a certain value from a list (e.g. the list of "APT::Keep-Fds") void Clear(std::string const &List, std::string const &Value); diff --git a/apt-pkg/contrib/error.cc b/apt-pkg/contrib/error.cc index 122e2c809..d457781c3 100644 --- a/apt-pkg/contrib/error.cc +++ b/apt-pkg/contrib/error.cc @@ -67,9 +67,10 @@ bool GlobalError::NAME (const char *Function, const char *Description,...) { \ int const errsv = errno; \ while (true) { \ va_start(args,Description); \ - if (InsertErrno(TYPE, Function, Description, args, errsv, msgSize) == false) \ - break; \ + bool const retry = InsertErrno(TYPE, Function, Description, args, errsv, msgSize); \ va_end(args); \ + if (retry == false) \ + break; \ } \ return false; \ } @@ -88,9 +89,10 @@ bool GlobalError::InsertErrno(MsgType const &type, const char *Function, int const errsv = errno; while (true) { va_start(args,Description); - if (InsertErrno(type, Function, Description, args, errsv, msgSize) == false) - break; + bool const retry = InsertErrno(type, Function, Description, args, errsv, msgSize); va_end(args); + if (retry == false) + break; } return false; } diff --git a/apt-pkg/contrib/fileutl.cc b/apt-pkg/contrib/fileutl.cc index 0f88923cf..0261119ba 100644 --- a/apt-pkg/contrib/fileutl.cc +++ b/apt-pkg/contrib/fileutl.cc @@ -41,6 +41,8 @@ #include <dirent.h> #include <signal.h> #include <errno.h> +#include <glob.h> + #include <set> #include <algorithm> @@ -244,17 +246,20 @@ int GetLock(string File,bool Errors) fl.l_len = 0; if (fcntl(FD,F_SETLK,&fl) == -1) { + // always close to not leak resources + int Tmp = errno; + close(FD); + errno = Tmp; + if (errno == ENOLCK) { _error->Warning(_("Not using locking for nfs mounted lock file %s"),File.c_str()); return dup(0); // Need something for the caller to close - } + } + if (Errors == true) _error->Errno("open",_("Could not get lock %s"),File.c_str()); - int Tmp = errno; - close(FD); - errno = Tmp; return -1; } @@ -651,9 +656,9 @@ string flNoLink(string File) while (1) { // Read the link - int Res; + ssize_t Res; if ((Res = readlink(NFile.c_str(),Buffer,sizeof(Buffer))) <= 0 || - (unsigned)Res >= sizeof(Buffer)) + (size_t)Res >= sizeof(Buffer)) return File; // Append or replace the previous path @@ -941,9 +946,6 @@ bool FileFd::Open(string FileName,unsigned int const Mode,APT::Configuration::Co if ((Mode & Atomic) == Atomic) { Flags |= Replace; - char *name = strdup((FileName + ".XXXXXX").c_str()); - TemporaryFileName = string(mktemp(name)); - free(name); } else if ((Mode & (Exclusive | Create)) == (Exclusive | Create)) { @@ -966,11 +968,24 @@ bool FileFd::Open(string FileName,unsigned int const Mode,APT::Configuration::Co if_FLAGGED_SET(Create, O_CREAT); if_FLAGGED_SET(Empty, O_TRUNC); if_FLAGGED_SET(Exclusive, O_EXCL); - else if_FLAGGED_SET(Atomic, O_EXCL); #undef if_FLAGGED_SET - if (TemporaryFileName.empty() == false) - iFd = open(TemporaryFileName.c_str(), fileflags, Perms); + if ((Mode & Atomic) == Atomic) + { + char *name = strdup((FileName + ".XXXXXX").c_str()); + + if((iFd = mkstemp(name)) == -1) + { + free(name); + return FileFdErrno("mkstemp", "Could not create temporary file for %s", FileName.c_str()); + } + + TemporaryFileName = string(name); + free(name); + + if(Perms != 600 && fchmod(iFd, Perms) == -1) + return FileFdErrno("fchmod", "Could not change permissions for temporary file %s", TemporaryFileName.c_str()); + } else iFd = open(FileName.c_str(), fileflags, Perms); @@ -1218,11 +1233,9 @@ FileFd::~FileFd() { Close(); if (d != NULL) - { d->CloseDown(FileName); - delete d; - d = NULL; - } + delete d; + d = NULL; } /*}}}*/ // FileFd::Read - Read a bit of the file /*{{{*/ @@ -1231,7 +1244,7 @@ FileFd::~FileFd() gracefully. */ bool FileFd::Read(void *To,unsigned long long Size,unsigned long long *Actual) { - int Res; + ssize_t Res; errno = 0; if (Actual != 0) *Actual = 0; @@ -1331,7 +1344,7 @@ char* FileFd::ReadLine(char *To, unsigned long long const Size) /* */ bool FileFd::Write(const void *From,unsigned long long Size) { - int Res; + ssize_t Res; errno = 0; do { @@ -1385,7 +1398,7 @@ bool FileFd::Write(const void *From,unsigned long long Size) } bool FileFd::Write(int Fd, const void *From, unsigned long long Size) { - int Res; + ssize_t Res; errno = 0; do { @@ -1458,14 +1471,14 @@ bool FileFd::Seek(unsigned long long To) d->seekpos = To; return true; } - int res; + off_t res; #ifdef HAVE_ZLIB if (d != NULL && d->gz) res = gzseek(d->gz,To,SEEK_SET); else #endif res = lseek(iFd,To,SEEK_SET); - if (res != (signed)To) + if (res != (off_t)To) return FileFdError("Unable to seek to %llu", To); if (d != NULL) @@ -1496,7 +1509,7 @@ bool FileFd::Skip(unsigned long long Over) return true; } - int res; + off_t res; #ifdef HAVE_ZLIB if (d != NULL && d->gz != NULL) res = gzseek(d->gz,Over,SEEK_CUR); @@ -1598,7 +1611,11 @@ unsigned long long FileFd::Size() char ignore[1000]; unsigned long long read = 0; do { - Read(ignore, sizeof(ignore), &read); + if (Read(ignore, sizeof(ignore), &read) == false) + { + Seek(oldSeek); + return 0; + } } while(read != 0); size = Tell(); Seek(oldSeek); @@ -1615,10 +1632,16 @@ unsigned long long FileFd::Size() * bits of the file */ // FIXME: Size for gz-files is limited by 32bitโฆ no largefile support if (lseek(iFd, -4, SEEK_END) < 0) - return FileFdErrno("lseek","Unable to seek to end of gzipped file"); - size = 0L; + { + FileFdErrno("lseek","Unable to seek to end of gzipped file"); + return 0; + } + size = 0; if (read(iFd, &size, 4) != 4) - return FileFdErrno("read","Unable to read original size of gzipped file"); + { + FileFdErrno("read","Unable to read original size of gzipped file"); + return 0; + } #ifdef WORDS_BIGENDIAN uint32_t tmp_size = size; @@ -1628,7 +1651,10 @@ unsigned long long FileFd::Size() #endif if (lseek(iFd, oldPos, SEEK_SET) < 0) - return FileFdErrno("lseek","Unable to seek in gzipped file"); + { + FileFdErrno("lseek","Unable to seek in gzipped file"); + return 0; + } return size; } @@ -1752,3 +1778,33 @@ bool FileFd::FileFdError(const char *Description,...) { /*}}}*/ gzFile FileFd::gzFd() { return (gzFile) d->gz; } + + +// Glob - wrapper around "glob()" /*{{{*/ +// --------------------------------------------------------------------- +/* */ +std::vector<std::string> Glob(std::string const &pattern, int flags) +{ + std::vector<std::string> result; + glob_t globbuf; + int glob_res; + unsigned int i; + + glob_res = glob(pattern.c_str(), flags, NULL, &globbuf); + + if (glob_res != 0) + { + if(glob_res != GLOB_NOMATCH) { + _error->Errno("glob", "Problem with glob"); + return result; + } + } + + // append results + for(i=0;i<globbuf.gl_pathc;i++) + result.push_back(string(globbuf.gl_pathv[i])); + + globfree(&globbuf); + return result; +} + /*}}}*/ diff --git a/apt-pkg/contrib/fileutl.h b/apt-pkg/contrib/fileutl.h index 3ec01dd9a..decd64d9d 100644 --- a/apt-pkg/contrib/fileutl.h +++ b/apt-pkg/contrib/fileutl.h @@ -191,4 +191,7 @@ std::string flNoLink(std::string File); std::string flExtension(std::string File); std::string flCombine(std::string Dir,std::string File); +// simple c++ glob +std::vector<std::string> Glob(std::string const &pattern, int flags=0); + #endif diff --git a/apt-pkg/contrib/sha2.h b/apt-pkg/contrib/sha2.h index 51c921dbd..8e0c99a1b 100644 --- a/apt-pkg/contrib/sha2.h +++ b/apt-pkg/contrib/sha2.h @@ -60,10 +60,11 @@ class SHA256Summation : public SHA2SummationBase res.Set(Sum); return res; }; - SHA256Summation() + SHA256Summation() { SHA256_Init(&ctx); Done = false; + memset(&Sum, 0, sizeof(Sum)); }; }; @@ -96,6 +97,7 @@ class SHA512Summation : public SHA2SummationBase { SHA512_Init(&ctx); Done = false; + memset(&Sum, 0, sizeof(Sum)); }; }; diff --git a/apt-pkg/contrib/strutl.cc b/apt-pkg/contrib/strutl.cc index d0e74d8c5..9f794927d 100644 --- a/apt-pkg/contrib/strutl.cc +++ b/apt-pkg/contrib/strutl.cc @@ -36,7 +36,22 @@ using namespace std; /*}}}*/ - +// Strip - Remove white space from the front and back of a string /*{{{*/ +// --------------------------------------------------------------------- +namespace APT { + namespace String { +std::string Strip(const std::string &s) +{ + size_t start = s.find_first_not_of(" \t\n"); + // only whitespace + if (start == string::npos) + return ""; + size_t end = s.find_last_not_of(" \t\n"); + return s.substr(start, end-start+1); +} +} +} + /*}}}*/ // UTF8ToCodeset - Convert some UTF-8 string for some codeset /*{{{*/ // --------------------------------------------------------------------- /* This is handy to use before display some information for enduser */ @@ -943,6 +958,8 @@ bool StrToTime(const string &Val,time_t &Result) Tm.tm_isdst = 0; if (Month[0] != 0) Tm.tm_mon = MonthConv(Month); + else + Tm.tm_mon = 0; // we don't have a month, so pick something Tm.tm_year -= 1900; // Convert to local time and then to GMT @@ -1116,6 +1133,37 @@ vector<string> VectorizeString(string const &haystack, char const &split) return exploded; } /*}}}*/ +// StringSplit - split a string into a string vector by token /*{{{*/ +// --------------------------------------------------------------------- +/* See header for details. + */ +vector<string> StringSplit(std::string const &s, std::string const &sep, + unsigned int maxsplit) +{ + vector<string> split; + size_t start, pos; + + // no seperator given, this is bogus + if(sep.size() == 0) + return split; + + start = pos = 0; + while (pos != string::npos) + { + pos = s.find(sep, start); + split.push_back(s.substr(start, pos-start)); + + // if maxsplit is reached, the remaining string is the last item + if(split.size() >= maxsplit) + { + split[split.size()-1] = s.substr(start); + break; + } + start = pos+sep.size(); + } + return split; +} + /*}}}*/ // RegexChoice - Simple regex list/list matcher /*{{{*/ // --------------------------------------------------------------------- /* */ @@ -1233,12 +1281,12 @@ char *safe_snprintf(char *Buffer,char *End,const char *Format,...) va_list args; int Did; - va_start(args,Format); - if (End <= Buffer) return End; - + va_start(args,Format); Did = vsnprintf(Buffer,End - Buffer,Format,args); + va_end(args); + if (Did < 0 || Buffer + Did > End) return End; return Buffer + Did; @@ -1291,6 +1339,18 @@ bool CheckDomainList(const string &Host,const string &List) return false; } /*}}}*/ +// strv_length - Return the length of a NULL-terminated string array /*{{{*/ +// --------------------------------------------------------------------- +/* */ +size_t strv_length(const char **str_array) +{ + size_t i; + for (i=0; str_array[i] != NULL; i++) + /* nothing */ + ; + return i; +} + // DeEscapeString - unescape (\0XX and \xXX) from a string /*{{{*/ // --------------------------------------------------------------------- /* */ diff --git a/apt-pkg/contrib/strutl.h b/apt-pkg/contrib/strutl.h index e92f91dc0..c8fc317c0 100644 --- a/apt-pkg/contrib/strutl.h +++ b/apt-pkg/contrib/strutl.h @@ -17,7 +17,7 @@ #define STRUTL_H - +#include <limits> #include <stdlib.h> #include <string> #include <cstring> @@ -33,6 +33,13 @@ using std::vector; using std::ostream; #endif +namespace APT { + namespace String { + std::string Strip(const std::string &s); + }; +}; + + bool UTF8ToCodeset(const char *codeset, const std::string &orig, std::string *dest); char *_strstrip(char *String); char *_strrstrip(char *String); // right strip only @@ -62,9 +69,32 @@ bool StrToNum(const char *Str,unsigned long &Res,unsigned Len,unsigned Base = 0) bool StrToNum(const char *Str,unsigned long long &Res,unsigned Len,unsigned Base = 0); bool Base256ToNum(const char *Str,unsigned long &Res,unsigned int Len); bool Hex2Num(const std::string &Str,unsigned char *Num,unsigned int Length); + +// input changing string split bool TokSplitString(char Tok,char *Input,char **List, unsigned long ListMax); + +// split a given string by a char std::vector<std::string> VectorizeString(std::string const &haystack, char const &split) __attrib_const; + +/* \brief Return a vector of strings from string "input" where "sep" + * is used as the delimiter string. + * + * \param input The input string. + * + * \param sep The seperator to use. + * + * \param maxsplit (optional) The maximum amount of splitting that + * should be done . + * + * The optional "maxsplit" argument can be used to limit the splitting, + * if used the string is only split on maxsplit places and the last + * item in the vector contains the remainder string. + */ +std::vector<std::string> StringSplit(std::string const &input, + std::string const &sep, + unsigned int maxsplit=std::numeric_limits<unsigned int>::max()) __attrib_const; + void ioprintf(std::ostream &out,const char *format,...) __like_printf(2); void strprintf(std::string &out,const char *format,...) __like_printf(2); char *safe_snprintf(char *Buffer,char *End,const char *Format,...) __like_printf(3); @@ -108,6 +138,10 @@ inline int stringcasecmp(std::string::const_iterator A,std::string::const_iterat APT_MKSTRCMP2(stringcmp,stringcmp); APT_MKSTRCMP2(stringcasecmp,stringcasecmp); +// Return the length of a NULL-terminated string array +size_t strv_length(const char **str_array); + + inline const char *DeNull(const char *s) {return (s == 0?"(null)":s);}; class URI diff --git a/apt-pkg/deb/deblistparser.cc b/apt-pkg/deb/deblistparser.cc index 28857176b..68d544e1f 100644 --- a/apt-pkg/deb/deblistparser.cc +++ b/apt-pkg/deb/deblistparser.cc @@ -635,7 +635,7 @@ bool debListParser::ParseDepends(pkgCache::VerIterator &Ver, string Version; unsigned int Op; - Start = ParseDepends(Start,Stop,Package,Version,Op,false,!MultiArchEnabled); + Start = ParseDepends(Start, Stop, Package, Version, Op, false, false); if (Start == 0) return _error->Error("Problem parsing dependency %s",Tag); size_t const found = Package.rfind(':'); @@ -717,9 +717,7 @@ bool debListParser::ParseProvides(pkgCache::VerIterator &Ver) } } - if (MultiArchEnabled == false) - return true; - else if ((Ver->MultiArch & pkgCache::Version::Allowed) == pkgCache::Version::Allowed) + if ((Ver->MultiArch & pkgCache::Version::Allowed) == pkgCache::Version::Allowed) { string const Package = string(Ver.ParentPkg().Name()).append(":").append("any"); return NewProvidesAllArch(Ver, Package, Ver.VerStr()); @@ -805,94 +803,28 @@ bool debListParser::LoadReleaseInfo(pkgCache::PkgFileIterator &FileI, map_ptrloc const storage = WriteUniqString(component); FileI->Component = storage; - // FIXME: should use FileFd and TagSection - FILE* release = fdopen(dup(File.Fd()), "r"); - if (release == NULL) + pkgTagFile TagFile(&File, File.Size()); + pkgTagSection Section; + if (_error->PendingError() == true || TagFile.Step(Section) == false) return false; - char buffer[101]; - while (fgets(buffer, sizeof(buffer), release) != NULL) - { - size_t len = 0; - - // Skip empty lines - for (; buffer[len] == '\r' && buffer[len] == '\n'; ++len) - /* nothing */ - ; - if (buffer[len] == '\0') - continue; - - // seperate the tag from the data - const char* dataStart = strchr(buffer + len, ':'); - if (dataStart == NULL) - continue; - len = dataStart - buffer; - for (++dataStart; *dataStart == ' '; ++dataStart) - /* nothing */ - ; - const char* dataEnd = (const char*)rawmemchr(dataStart, '\0'); - // The last char should be a newline, but we can never be sure: #633350 - const char* lineEnd = dataEnd; - for (--lineEnd; *lineEnd == '\r' || *lineEnd == '\n'; --lineEnd) - /* nothing */ - ; - ++lineEnd; - - // which datastorage need to be updated - enum { Suite, Component, Version, Origin, Codename, Label, None } writeTo = None; - if (buffer[0] == ' ') - ; - #define APT_PARSER_WRITETO(X) else if (strncmp(#X, buffer, len) == 0) writeTo = X; - APT_PARSER_WRITETO(Suite) - APT_PARSER_WRITETO(Component) - APT_PARSER_WRITETO(Version) - APT_PARSER_WRITETO(Origin) - APT_PARSER_WRITETO(Codename) - APT_PARSER_WRITETO(Label) - #undef APT_PARSER_WRITETO - #define APT_PARSER_FLAGIT(X) else if (strncmp(#X, buffer, len) == 0) \ - pkgTagSection::FindFlag(FileI->Flags, pkgCache::Flag:: X, dataStart, lineEnd); - APT_PARSER_FLAGIT(NotAutomatic) - APT_PARSER_FLAGIT(ButAutomaticUpgrades) - #undef APT_PARSER_FLAGIT - - // load all data from the line and save it - string data; - if (writeTo != None) - data.append(dataStart, dataEnd); - if (sizeof(buffer) - 1 == (dataEnd - buffer)) - { - while (fgets(buffer, sizeof(buffer), release) != NULL) - { - if (writeTo != None) - data.append(buffer); - if (strlen(buffer) != sizeof(buffer) - 1) - break; - } - } - if (writeTo != None) - { - // remove spaces and stuff from the end of the data line - for (std::string::reverse_iterator s = data.rbegin(); - s != data.rend(); ++s) - { - if (*s != '\r' && *s != '\n' && *s != ' ') - break; - *s = '\0'; - } - map_ptrloc const storage = WriteUniqString(data); - switch (writeTo) { - case Suite: FileI->Archive = storage; break; - case Component: FileI->Component = storage; break; - case Version: FileI->Version = storage; break; - case Origin: FileI->Origin = storage; break; - case Codename: FileI->Codename = storage; break; - case Label: FileI->Label = storage; break; - case None: break; - } - } + std::string data; + #define APT_INRELEASE(TAG, STORE) \ + data = Section.FindS(TAG); \ + if (data.empty() == false) \ + { \ + map_ptrloc const storage = WriteUniqString(data); \ + STORE = storage; \ } - fclose(release); + APT_INRELEASE("Suite", FileI->Archive) + APT_INRELEASE("Component", FileI->Component) + APT_INRELEASE("Version", FileI->Version) + APT_INRELEASE("Origin", FileI->Origin) + APT_INRELEASE("Codename", FileI->Codename) + APT_INRELEASE("Label", FileI->Label) + #undef APT_INRELEASE + Section.FindFlag("NotAutomatic", FileI->Flags, pkgCache::Flag::NotAutomatic); + Section.FindFlag("ButAutomaticUpgrades", FileI->Flags, pkgCache::Flag::ButAutomaticUpgrades); return !_error->PendingError(); } diff --git a/apt-pkg/deb/debmetaindex.cc b/apt-pkg/deb/debmetaindex.cc index 7a88d71e3..b597b6f3c 100644 --- a/apt-pkg/deb/debmetaindex.cc +++ b/apt-pkg/deb/debmetaindex.cc @@ -238,6 +238,7 @@ bool debReleaseIndex::GetIndexes(pkgAcquire *Owner, bool const &GetAll) const new pkgAcqIndex(Owner, (*Target)->URI, (*Target)->Description, (*Target)->ShortDesc, HashString()); } + delete targets; // this is normally created in pkgAcqMetaSig, but if we run // in --print-uris mode, we add it here @@ -373,10 +374,29 @@ class debSLTypeDebian : public pkgSourceList::Type string const &Dist, string const &Section, bool const &IsSrc, map<string, string> const &Options) const { - map<string, string>::const_iterator const arch = Options.find("arch"); - vector<string> const Archs = + // parse arch=, arch+= and arch-= settings + map<string, string>::const_iterator arch = Options.find("arch"); + vector<string> Archs = (arch != Options.end()) ? VectorizeString(arch->second, ',') : APT::Configuration::getArchitectures(); + if ((arch = Options.find("arch+")) != Options.end()) + { + std::vector<std::string> const plusArch = VectorizeString(arch->second, ','); + for (std::vector<std::string>::const_iterator plus = plusArch.begin(); plus != plusArch.end(); ++plus) + if (std::find(Archs.begin(), Archs.end(), *plus) == Archs.end()) + Archs.push_back(*plus); + } + if ((arch = Options.find("arch-")) != Options.end()) + { + std::vector<std::string> const minusArch = VectorizeString(arch->second, ','); + for (std::vector<std::string>::const_iterator minus = minusArch.begin(); minus != minusArch.end(); ++minus) + { + std::vector<std::string>::iterator kill = std::find(Archs.begin(), Archs.end(), *minus); + if (kill != Archs.end()) + Archs.erase(kill); + } + } + map<string, string>::const_iterator const trusted = Options.find("trusted"); for (vector<metaIndex *>::const_iterator I = List.begin(); diff --git a/apt-pkg/deb/dpkgpm.cc b/apt-pkg/deb/dpkgpm.cc index 3dec4bb39..9731060be 100644 --- a/apt-pkg/deb/dpkgpm.cc +++ b/apt-pkg/deb/dpkgpm.cc @@ -36,6 +36,7 @@ #include <map> #include <pwd.h> #include <grp.h> +#include <iomanip> #include <termios.h> #include <unistd.h> @@ -51,9 +52,16 @@ class pkgDPkgPMPrivate { public: pkgDPkgPMPrivate() : stdin_is_dev_null(false), dpkgbuf_pos(0), - term_out(NULL), history_out(NULL) + term_out(NULL), history_out(NULL), + last_reported_progress(0.0), nr_terminal_rows(0), + fancy_progress_output(false) { dpkgbuf[0] = '\0'; + if(_config->FindB("Dpkg::Progress-Fancy", false) == true) + { + fancy_progress_output = true; + _config->Set("DpkgPM::Progress", true); + } } bool stdin_is_dev_null; // the buffer we use for the dpkg status-fd reading @@ -62,6 +70,10 @@ public: FILE *term_out; FILE *history_out; string dpkg_error; + + float last_reported_progress; + int nr_terminal_rows; + bool fancy_progress_output; }; namespace @@ -133,6 +145,8 @@ static void dpkgChrootDirectory() std::cerr << "Chrooting into " << chrootDir << std::endl; if (chroot(chrootDir.c_str()) != 0) _exit(100); + if (chdir("/") != 0) + _exit(100); } /*}}}*/ @@ -237,15 +251,23 @@ bool pkgDPkgPM::Remove(PkgIterator Pkg,bool Purge) return true; } /*}}}*/ -// DPkgPM::SendV2Pkgs - Send version 2 package info /*{{{*/ +// DPkgPM::SendPkgInfo - Send info for install-pkgs hook /*{{{*/ // --------------------------------------------------------------------- /* This is part of the helper script communication interface, it sends very complete information down to the other end of the pipe.*/ bool pkgDPkgPM::SendV2Pkgs(FILE *F) { - fprintf(F,"VERSION 2\n"); - - /* Write out all of the configuration directives by walking the + return SendPkgsInfo(F, 2); +} +bool pkgDPkgPM::SendPkgsInfo(FILE * const F, unsigned int const &Version) +{ + // This version of APT supports only v3, so don't sent higher versions + if (Version <= 3) + fprintf(F,"VERSION %u\n", Version); + else + fprintf(F,"VERSION 3\n"); + + /* Write out all of the configuration directives by walking the configuration tree */ const Configuration::Item *Top = _config->Tree(0); for (; Top != 0;) @@ -279,30 +301,51 @@ bool pkgDPkgPM::SendV2Pkgs(FILE *F) pkgDepCache::StateCache &S = Cache[I->Pkg]; fprintf(F,"%s ",I->Pkg.Name()); - // Current version - if (I->Pkg->CurrentVer == 0) - fprintf(F,"- "); + + // Current version which we are going to replace + pkgCache::VerIterator CurVer = I->Pkg.CurrentVer(); + if (CurVer.end() == true && (I->Op == Item::Remove || I->Op == Item::Purge)) + CurVer = FindNowVersion(I->Pkg); + + if (CurVer.end() == true) + { + if (Version <= 2) + fprintf(F, "- "); + else + fprintf(F, "- - none "); + } else - fprintf(F,"%s ",I->Pkg.CurrentVer().VerStr()); - - // Show the compare operator - // Target version + { + fprintf(F, "%s ", CurVer.VerStr()); + if (Version >= 3) + fprintf(F, "%s %s ", CurVer.Arch(), CurVer.MultiArchType()); + } + + // Show the compare operator between current and install version if (S.InstallVer != 0) { + pkgCache::VerIterator const InstVer = S.InstVerIter(Cache); int Comp = 2; - if (I->Pkg->CurrentVer != 0) - Comp = S.InstVerIter(Cache).CompareVer(I->Pkg.CurrentVer()); + if (CurVer.end() == false) + Comp = InstVer.CompareVer(CurVer); if (Comp < 0) fprintf(F,"> "); - if (Comp == 0) + else if (Comp == 0) fprintf(F,"= "); - if (Comp > 0) + else if (Comp > 0) fprintf(F,"< "); - fprintf(F,"%s ",S.InstVerIter(Cache).VerStr()); + fprintf(F, "%s ", InstVer.VerStr()); + if (Version >= 3) + fprintf(F, "%s %s ", InstVer.Arch(), InstVer.MultiArchType()); } else - fprintf(F,"> - "); - + { + if (Version <= 2) + fprintf(F, "> - "); + else + fprintf(F, "> - - none "); + } + // Show the filename/operation if (I->Op == Item::Install) { @@ -312,9 +355,9 @@ bool pkgDPkgPM::SendV2Pkgs(FILE *F) else fprintf(F,"%s\n",I->File.c_str()); } - if (I->Op == Item::Configure) + else if (I->Op == Item::Configure) fprintf(F,"**CONFIGURE**\n"); - if (I->Op == Item::Remove || + else if (I->Op == Item::Remove || I->Op == Item::Purge) fprintf(F,"**REMOVE**\n"); @@ -350,24 +393,32 @@ bool pkgDPkgPM::RunScriptsWithPkgs(const char *Cnf) OptSec = "DPkg::Tools::Options::" + string(Opts->Value.c_str(),Pos); unsigned int Version = _config->FindI(OptSec+"::Version",1); + unsigned int InfoFD = _config->FindI(OptSec + "::InfoFD", STDIN_FILENO); // Create the pipes int Pipes[2]; if (pipe(Pipes) != 0) return _error->Errno("pipe","Failed to create IPC pipe to subprocess"); - SetCloseExec(Pipes[0],true); + if (InfoFD != (unsigned)Pipes[0]) + SetCloseExec(Pipes[0],true); + else + _config->Set("APT::Keep-Fds::", Pipes[0]); SetCloseExec(Pipes[1],true); - + // Purified Fork for running the script - pid_t Process = ExecFork(); + pid_t Process = ExecFork(); if (Process == 0) { // Setup the FDs - dup2(Pipes[0],STDIN_FILENO); + dup2(Pipes[0], InfoFD); SetCloseExec(STDOUT_FILENO,false); - SetCloseExec(STDIN_FILENO,false); + SetCloseExec(STDIN_FILENO,false); SetCloseExec(STDERR_FILENO,false); + string hookfd; + strprintf(hookfd, "%d", InfoFD); + setenv("APT_HOOK_INFO_FD", hookfd.c_str(), 1); + dpkgChrootDirectory(); const char *Args[4]; Args[0] = "/bin/sh"; @@ -377,6 +428,8 @@ bool pkgDPkgPM::RunScriptsWithPkgs(const char *Cnf) execv(Args[0],(char **)Args); _exit(100); } + if (InfoFD == (unsigned)Pipes[0]) + _config->Clear("APT::Keep-Fds", Pipes[0]); close(Pipes[0]); FILE *F = fdopen(Pipes[1],"w"); if (F == 0) @@ -403,7 +456,7 @@ bool pkgDPkgPM::RunScriptsWithPkgs(const char *Cnf) } } else - SendV2Pkgs(F); + SendPkgsInfo(F, Version); fclose(F); @@ -462,142 +515,209 @@ void pkgDPkgPM::DoTerminalPty(int master) void pkgDPkgPM::ProcessDpkgStatusLine(int OutStatusFd, char *line) { bool const Debug = _config->FindB("Debug::pkgDPkgProgressReporting",false); - // the status we output - ostringstream status; - if (Debug == true) std::clog << "got from dpkg '" << line << "'" << std::endl; - /* dpkg sends strings like this: - 'status: <pkg>: <pkg qstate>' - errors look like this: - 'status: /var/cache/apt/archives/krecipes_0.8.1-0ubuntu1_i386.deb : error : trying to overwrite `/usr/share/doc/kde/HTML/en/krecipes/krectip.png', which is also in package krecipes-data - and conffile-prompt like this - 'status: conffile-prompt: conffile : 'current-conffile' 'new-conffile' useredited distedited + 'status: <pkg>: <pkg qstate>' + 'status: <pkg>:<arch>: <pkg qstate>' - Newer versions of dpkg sent also: - 'processing: install: pkg' - 'processing: configure: pkg' - 'processing: remove: pkg' - 'processing: purge: pkg' - 'processing: disappear: pkg' - 'processing: trigproc: trigger' - + 'processing: {install,configure,remove,purge,disappear,trigproc}: pkg' + 'processing: {install,configure,remove,purge,disappear,trigproc}: trigger' */ - char* list[6]; - // dpkg sends multiline error messages sometimes (see - // #374195 for a example. we should support this by - // either patching dpkg to not send multiline over the - // statusfd or by rewriting the code here to deal with - // it. for now we just ignore it and not crash - TokSplitString(':', line, list, sizeof(list)/sizeof(list[0])); - if( list[0] == NULL || list[1] == NULL || list[2] == NULL) + + // we need to split on ": " (note the appended space) as the ':' is + // part of the pkgname:arch information that dpkg sends + // + // A dpkg error message may contain additional ":" (like + // "failed in buffer_write(fd) (10, ret=-1): backend dpkg-deb ..." + // so we need to ensure to not split too much + std::vector<std::string> list = StringSplit(line, ": ", 4); + if(list.size() < 3) { if (Debug == true) std::clog << "ignoring line: not enough ':'" << std::endl; return; } - const char* const pkg = list[1]; - const char* action = _strstrip(list[2]); + + // build the (prefix, pkgname, action) tuple, position of this + // is different for "processing" or "status" messages + std::string prefix = APT::String::Strip(list[0]); + std::string pkgname; + std::string action; + ostringstream status; + + // "processing" has the form "processing: action: pkg or trigger" + // with action = ["install", "configure", "remove", "purge", "disappear", + // "trigproc"] + if (prefix == "processing") + { + pkgname = APT::String::Strip(list[2]); + action = APT::String::Strip(list[1]); + + // this is what we support in the processing stage + if(action != "install" && action != "configure" && + action != "remove" && action != "purge" && action != "purge") + { + if (Debug == true) + std::clog << "ignoring processing action: '" << action + << "'" << std::endl; + return; + } + } + // "status" has the form: "status: pkg: state" + // with state in ["half-installed", "unpacked", "half-configured", + // "installed", "config-files", "not-installed"] + else if (prefix == "status") + { + pkgname = APT::String::Strip(list[1]); + action = APT::String::Strip(list[2]); + } else { + if (Debug == true) + std::clog << "unknown prefix '" << prefix << "'" << std::endl; + return; + } + + + /* handle the special cases first: + + errors look like this: + 'status: /var/cache/apt/archives/krecipes_0.8.1-0ubuntu1_i386.deb : error : trying to overwrite `/usr/share/doc/kde/HTML/en/krecipes/krectip.png', which is also in package krecipes-data + and conffile-prompt like this + 'status: conffile-prompt: conffile : 'current-conffile' 'new-conffile' useredited distedited + */ + if (prefix == "status") + { + if(action == "error") + { + status << "pmerror:" << list[1] + << ":" << (PackagesDone/float(PackagesTotal)*100.0) + << ":" << list[3] + << endl; + if(OutStatusFd > 0) + FileFd::Write(OutStatusFd, status.str().c_str(), status.str().size()); + if (Debug == true) + std::clog << "send: '" << status.str() << "'" << endl; + pkgFailures++; + WriteApportReport(list[1].c_str(), list[3].c_str()); + return; + } + else if(action == "conffile") + { + status << "pmconffile:" << list[1] + << ":" << (PackagesDone/float(PackagesTotal)*100.0) + << ":" << list[3] + << endl; + if(OutStatusFd > 0) + FileFd::Write(OutStatusFd, status.str().c_str(), status.str().size()); + if (Debug == true) + std::clog << "send: '" << status.str() << "'" << endl; + return; + } + } + + // at this point we know that we should have a valid pkgname, so build all + // the info from it + + // dpkg does not send always send "pkgname:arch" so we add it here + // if needed + if (pkgname.find(":") == std::string::npos) + { + // find the package in the group that is in a touched by dpkg + // if there are multiple dpkg will send us a full pkgname:arch + pkgCache::GrpIterator Grp = Cache.FindGrp(pkgname); + if (Grp.end() == false) + { + pkgCache::PkgIterator P = Grp.PackageList(); + for (; P.end() != true; P = Grp.NextPkg(P)) + { + if(Cache[P].Mode != pkgDepCache::ModeKeep) + { + pkgname = P.FullName(); + break; + } + } + } + } + + const char* const pkg = pkgname.c_str(); + std::string short_pkgname = StringSplit(pkgname, ":")[0]; + std::string arch = ""; + if (pkgname.find(":") != string::npos) + arch = StringSplit(pkgname, ":")[1]; + std::string i18n_pkgname = pkgname; + if (arch.size() != 0) + strprintf(i18n_pkgname, "%s (%s)", short_pkgname.c_str(), arch.c_str()); // 'processing' from dpkg looks like // 'processing: action: pkg' - if(strncmp(list[0], "processing", strlen("processing")) == 0) + if(prefix == "processing") { - char s[200]; - const char* const pkg_or_trigger = _strstrip(list[2]); - action = _strstrip( list[1]); const std::pair<const char *, const char *> * const iter = std::find_if(PackageProcessingOpsBegin, PackageProcessingOpsEnd, - MatchProcessingOp(action)); + MatchProcessingOp(action.c_str())); if(iter == PackageProcessingOpsEnd) { if (Debug == true) std::clog << "ignoring unknown action: " << action << std::endl; return; } - snprintf(s, sizeof(s), _(iter->second), pkg_or_trigger); + std::string msg; + strprintf(msg, _(iter->second), short_pkgname.c_str()); - status << "pmstatus:" << pkg_or_trigger + status << "pmstatus:" << short_pkgname << ":" << (PackagesDone/float(PackagesTotal)*100.0) - << ":" << s + << ":" << msg << endl; if(OutStatusFd > 0) FileFd::Write(OutStatusFd, status.str().c_str(), status.str().size()); if (Debug == true) std::clog << "send: '" << status.str() << "'" << endl; - if (strncmp(action, "disappear", strlen("disappear")) == 0) - handleDisappearAction(pkg_or_trigger); - return; - } - - if(strncmp(action,"error",strlen("error")) == 0) - { - // urgs, sometime has ":" in its error string so that we - // end up with the error message split between list[3] - // and list[4], e.g. the message: - // "failed in buffer_write(fd) (10, ret=-1): backend dpkg-deb ..." - // concat them again - if( list[4] != NULL ) - list[3][strlen(list[3])] = ':'; - - status << "pmerror:" << list[1] - << ":" << (PackagesDone/float(PackagesTotal)*100.0) - << ":" << list[3] - << endl; - if(OutStatusFd > 0) - FileFd::Write(OutStatusFd, status.str().c_str(), status.str().size()); - if (Debug == true) - std::clog << "send: '" << status.str() << "'" << endl; - pkgFailures++; - WriteApportReport(list[1], list[3]); - return; - } - else if(strncmp(action,"conffile",strlen("conffile")) == 0) - { - status << "pmconffile:" << list[1] - << ":" << (PackagesDone/float(PackagesTotal)*100.0) - << ":" << list[3] - << endl; - if(OutStatusFd > 0) - FileFd::Write(OutStatusFd, status.str().c_str(), status.str().size()); - if (Debug == true) - std::clog << "send: '" << status.str() << "'" << endl; + // FIXME: this needs a muliarch testcase + // FIXME2: is "pkgname" here reliable with dpkg only sending us + // short pkgnames? + if (action == "disappear") + handleDisappearAction(pkgname); return; - } + } - vector<struct DpkgState> const &states = PackageOps[pkg]; - const char *next_action = NULL; - if(PackageOpsDone[pkg] < states.size()) - next_action = states[PackageOpsDone[pkg]].state; - // check if the package moved to the next dpkg state - if(next_action && (strcmp(action, next_action) == 0)) + if (prefix == "status") { - // only read the translation if there is actually a next - // action - const char *translation = _(states[PackageOpsDone[pkg]].str); - char s[200]; - snprintf(s, sizeof(s), translation, pkg); - - // we moved from one dpkg state to a new one, report that - PackageOpsDone[pkg]++; - PackagesDone++; - // build the status str - status << "pmstatus:" << pkg - << ":" << (PackagesDone/float(PackagesTotal)*100.0) - << ":" << s - << endl; - if(OutStatusFd > 0) - FileFd::Write(OutStatusFd, status.str().c_str(), status.str().size()); - if (Debug == true) - std::clog << "send: '" << status.str() << "'" << endl; + vector<struct DpkgState> const &states = PackageOps[pkg]; + const char *next_action = NULL; + if(PackageOpsDone[pkg] < states.size()) + next_action = states[PackageOpsDone[pkg]].state; + // check if the package moved to the next dpkg state + if(next_action && (action == next_action)) + { + // only read the translation if there is actually a next + // action + const char *translation = _(states[PackageOpsDone[pkg]].str); + std::string msg; + strprintf(msg, translation, short_pkgname.c_str()); + + // we moved from one dpkg state to a new one, report that + PackageOpsDone[pkg]++; + PackagesDone++; + // build the status str + status << "pmstatus:" << short_pkgname + << ":" << (PackagesDone/float(PackagesTotal)*100.0) + << ":" << msg + << endl; + if(_config->FindB("DPkgPM::Progress", false) == true) + SendTerminalProgress(PackagesDone/float(PackagesTotal)*100.0); + + if(OutStatusFd > 0) + FileFd::Write(OutStatusFd, status.str().c_str(), status.str().size()); + if (Debug == true) + std::clog << "send: '" << status.str() << "'" << endl; + } + if (Debug == true) + std::clog << "(parsed from dpkg) pkg: " << short_pkgname + << " action: " << action << endl; } - if (Debug == true) - std::clog << "(parsed from dpkg) pkg: " << pkg - << " action: " << action << endl; } /*}}}*/ // DPkgPM::handleDisappearAction /*{{{*/ @@ -719,13 +839,15 @@ bool pkgDPkgPM::OpenLog() return _error->WarningE("OpenLog", _("Could not open file '%s'"), logfile_name.c_str()); setvbuf(d->term_out, NULL, _IONBF, 0); SetCloseExec(fileno(d->term_out), true); - struct passwd *pw; - struct group *gr; - pw = getpwnam("root"); - gr = getgrnam("adm"); - if (pw != NULL && gr != NULL) - chown(logfile_name.c_str(), pw->pw_uid, gr->gr_gid); - chmod(logfile_name.c_str(), 0640); + if (getuid() == 0) // if we aren't root, we can't chown a file, so don't try it + { + struct passwd *pw = getpwnam("root"); + struct group *gr = getgrnam("adm"); + if (pw != NULL && gr != NULL && chown(logfile_name.c_str(), pw->pw_uid, gr->gr_gid) != 0) + _error->WarningE("OpenLog", "chown to root:adm of file %s failed", logfile_name.c_str()); + } + if (chmod(logfile_name.c_str(), 0640) != 0) + _error->WarningE("OpenLog", "chmod 0640 of file %s failed", logfile_name.c_str()); fprintf(d->term_out, "\nLog started: %s\n", timestr); } @@ -830,6 +952,51 @@ bool pkgDPkgPM::CloseLog() return true; } /*}}}*/ +// DPkgPM::SendTerminalProgress /*{{{*/ +// --------------------------------------------------------------------- +/* Send progress info to the terminal + */ +void pkgDPkgPM::SendTerminalProgress(float percentage) +{ + int reporting_steps = _config->FindI("DpkgPM::Reporting-Steps", 1); + + if(percentage < (d->last_reported_progress + reporting_steps)) + return; + + std::string progress_str; + strprintf(progress_str, _("Progress: [%3i%%]"), (int)percentage); + if (d->fancy_progress_output) + { + int row = d->nr_terminal_rows; + + static string save_cursor = "\033[s"; + static string restore_cursor = "\033[u"; + + static string set_bg_color = "\033[42m"; // green + static string set_fg_color = "\033[30m"; // black + + static string restore_bg = "\033[49m"; + static string restore_fg = "\033[39m"; + + std::cout << save_cursor + // move cursor position to last row + << "\033[" << row << ";0f" + << set_bg_color + << set_fg_color + << progress_str + << restore_cursor + << restore_bg + << restore_fg; + } + else + { + std::cout << progress_str << "\r\n"; + } + std::flush(std::cout); + + d->last_reported_progress = percentage; +} + /*}}}*/ /*{{{*/ // This implements a racy version of pselect for those architectures // that don't have a working implementation. @@ -851,6 +1018,43 @@ static int racy_pselect(int nfds, fd_set *readfds, fd_set *writefds, return retval; } /*}}}*/ + +void pkgDPkgPM::SetupTerminalScrollArea(int nr_rows) +{ + if(!d->fancy_progress_output) + return; + + // scroll down a bit to avoid visual glitch when the screen + // area shrinks by one row + std::cout << "\n"; + + // save cursor + std::cout << "\033[s"; + + // set scroll region (this will place the cursor in the top left) + std::cout << "\033[1;" << nr_rows - 1 << "r"; + + // restore cursor but ensure its inside the scrolling area + std::cout << "\033[u"; + static const char *move_cursor_up = "\033[1A"; + std::cout << move_cursor_up; + std::flush(std::cout); +} + +void pkgDPkgPM::CleanupTerminal() +{ + // reset scroll area + SetupTerminalScrollArea(d->nr_terminal_rows + 1); + if(d->fancy_progress_output) + { + // override the progress line (sledgehammer) + static const char* clear_screen_below_cursor = "\033[J"; + std::cout << clear_screen_below_cursor; + std::flush(std::cout); + } +} + + // DPkgPM::Go - Run the sequence /*{{{*/ // --------------------------------------------------------------------- /* This globs the operations and calls dpkg @@ -976,7 +1180,7 @@ bool pkgDPkgPM::Go(int OutStatusFd) if((*I).Pkg.end() == true) continue; - string const name = (*I).Pkg.Name(); + string const name = (*I).Pkg.FullName(); PackageOpsDone[name] = 0; for(int i=0; (DpkgStatesOpMap[(*I).Op][i]).state != NULL; ++i) { @@ -1204,16 +1408,14 @@ bool pkgDPkgPM::Go(int OutStatusFd) // if tcgetattr does not return zero there was a error // and we do not do any pty magic - if (tcgetattr(0, &tt) == 0) + _error->PushToStack(); + if (tcgetattr(STDOUT_FILENO, &tt) == 0) { - ioctl(0, TIOCGWINSZ, (char *)&win); - if (openpty(&master, &slave, NULL, &tt, &win) < 0) + ioctl(1, TIOCGWINSZ, (char *)&win); + d->nr_terminal_rows = win.ws_row; + if (openpty(&master, &slave, NULL, &tt, &win) < 0) { - const char *s = _("Can not write log, openpty() " - "failed (/dev/pts not mounted?)\n"); - fprintf(stderr, "%s",s); - if(d->term_out) - fprintf(d->term_out, "%s",s); + _error->Errno("openpty", _("Can not write log (%s)"), _("Is /dev/pts mounted?")); master = slave = -1; } else { struct termios rtt; @@ -1231,6 +1433,15 @@ bool pkgDPkgPM::Go(int OutStatusFd) sigprocmask(SIG_SETMASK, &original_sigmask, 0); } } + // complain only if stdout is either a terminal (but still failed) or is an invalid + // descriptor otherwise we would complain about redirection to e.g. /dev/null as well. + else if (isatty(STDOUT_FILENO) == 1 || errno == EBADF) + _error->Errno("tcgetattr", _("Can not write log (%s)"), _("Is stdout a terminal?")); + + if (_error->PendingError() == true) + _error->DumpErrors(std::cerr); + _error->RevertToStack(); + // Fork dpkg pid_t Child; _config->Set("APT::Keep-Fds::",fd[1]); @@ -1243,11 +1454,12 @@ bool pkgDPkgPM::Go(int OutStatusFd) << endl; FileFd::Write(OutStatusFd, status.str().c_str(), status.str().size()); } + Child = ExecFork(); - // This is the child if (Child == 0) { + if(slave >= 0 && master >= 0) { setsid(); @@ -1264,7 +1476,7 @@ bool pkgDPkgPM::Go(int OutStatusFd) if (chdir(_config->FindDir("DPkg::Run-Directory","/").c_str()) != 0) _exit(100); - + if (_config->FindB("DPkg::FlushSTDIN",true) == true && isatty(STDIN_FILENO)) { int Flags,dummy; @@ -1280,6 +1492,9 @@ bool pkgDPkgPM::Go(int OutStatusFd) if (fcntl(STDIN_FILENO,F_SETFL,Flags & (~(long)O_NONBLOCK)) < 0) _exit(100); } + // setup terminal + SetupTerminalScrollArea(d->nr_terminal_rows); + SendTerminalProgress(PackagesDone/float(PackagesTotal)*100.0); /* No Job Control Stop Env is a magic dpkg var that prevents it from using sigstop */ @@ -1379,7 +1594,7 @@ bool pkgDPkgPM::Go(int OutStatusFd) tcsetattr(0, TCSAFLUSH, &tt); close(master); } - + // Check for an error code. if (WIFEXITED(Status) == 0 || WEXITSTATUS(Status) != 0) { @@ -1404,12 +1619,19 @@ bool pkgDPkgPM::Go(int OutStatusFd) if(stopOnError) { CloseLog(); + CleanupTerminal(); return false; } } } CloseLog(); - + + // dpkg is done at this point + if(_config->FindB("DPkgPM::Progress", false) == true) + SendTerminalProgress(100); + + CleanupTerminal(); + if (pkgPackageManager::SigINTStop) _error->Warning(_("Operation was interrupted before it could finish")); diff --git a/apt-pkg/deb/dpkgpm.h b/apt-pkg/deb/dpkgpm.h index aab39f633..1a58e1af5 100644 --- a/apt-pkg/deb/dpkgpm.h +++ b/apt-pkg/deb/dpkgpm.h @@ -14,6 +14,7 @@ #include <vector> #include <map> #include <stdio.h> +#include <apt-pkg/macros.h> #ifndef APT_8_CLEANER_HEADERS using std::vector; @@ -79,9 +80,15 @@ class pkgDPkgPM : public pkgPackageManager // Helpers bool RunScriptsWithPkgs(const char *Cnf); - bool SendV2Pkgs(FILE *F); + __deprecated bool SendV2Pkgs(FILE *F); + bool SendPkgsInfo(FILE * const F, unsigned int const &Version); void WriteHistoryTag(std::string const &tag, std::string value); + // Terminal progress + void SetupTerminalScrollArea(int nr_scrolled_rows); + void SendTerminalProgress(float percentage); + void CleanupTerminal(); + // apport integration void WriteApportReport(const char *pkgpath, const char *errormsg); diff --git a/apt-pkg/depcache.cc b/apt-pkg/depcache.cc index 08c1bd809..a06789cdf 100644 --- a/apt-pkg/depcache.cc +++ b/apt-pkg/depcache.cc @@ -865,6 +865,11 @@ bool pkgDepCache::MarkDelete(PkgIterator const &Pkg, bool rPurge, bool pkgDepCache::IsDeleteOk(PkgIterator const &Pkg,bool rPurge, unsigned long Depth, bool FromUser) { + return IsDeleteOkProtectInstallRequests(Pkg, rPurge, Depth, FromUser); +} +bool pkgDepCache::IsDeleteOkProtectInstallRequests(PkgIterator const &Pkg, + bool const rPurge, unsigned long const Depth, bool const FromUser) +{ if (FromUser == false && Pkg->CurrentVer == 0) { StateCache &P = PkgState[Pkg->ID]; @@ -891,6 +896,7 @@ char const* PrintMode(char const mode) case pkgDepCache::ModeInstall: return "Install"; case pkgDepCache::ModeKeep: return "Keep"; case pkgDepCache::ModeDelete: return "Delete"; + case pkgDepCache::ModeGarbage: return "Garbage"; default: return "UNKNOWN"; } } @@ -1047,9 +1053,10 @@ bool pkgDepCache::MarkInstall(PkgIterator const &Pkg,bool AutoInst, return true; } - // check if we are allowed to install the package - if (IsInstallOk(Pkg,AutoInst,Depth,FromUser) == false) - return false; + // check if we are allowed to install the package (if we haven't already) + if (P.Mode != ModeInstall || P.InstallVer != P.CandidateVer) + if (IsInstallOk(Pkg,AutoInst,Depth,FromUser) == false) + return false; ActionGroup group(*this); P.iFlags &= ~AutoKept; @@ -1271,11 +1278,50 @@ bool pkgDepCache::MarkInstall(PkgIterator const &Pkg,bool AutoInst, /*}}}*/ // DepCache::IsInstallOk - check if it is ok to install this package /*{{{*/ // --------------------------------------------------------------------- -/* The default implementation does nothing. +/* The default implementation checks if the installation of an M-A:same + package would lead us into a version-screw and if so forbids it. dpkg holds are enforced by the private IsModeChangeOk */ bool pkgDepCache::IsInstallOk(PkgIterator const &Pkg,bool AutoInst, unsigned long Depth, bool FromUser) { + return IsInstallOkMultiArchSameVersionSynced(Pkg,AutoInst, Depth, FromUser); +} +bool pkgDepCache::IsInstallOkMultiArchSameVersionSynced(PkgIterator const &Pkg, + bool const AutoInst, unsigned long const Depth, bool const FromUser) +{ + if (FromUser == true) // as always: user is always right + return true; + + // ignore packages with none-M-A:same candidates + VerIterator const CandVer = PkgState[Pkg->ID].CandidateVerIter(*this); + if (unlikely(CandVer.end() == true) || CandVer == Pkg.CurrentVer() || + (CandVer->MultiArch & pkgCache::Version::Same) != pkgCache::Version::Same) + return true; + + GrpIterator const Grp = Pkg.Group(); + for (PkgIterator P = Grp.PackageList(); P.end() == false; P = Grp.NextPkg(P)) + { + // not installed or version synced: fine by definition + // (simple string-compare as stuff like '1' == '0:1-0' can't happen here) + if (P->CurrentVer == 0 || strcmp(Pkg.CandVersion(), P.CandVersion()) == 0) + continue; + // packages loosing M-A:same can be out-of-sync + VerIterator CV = PkgState[P->ID].CandidateVerIter(*this); + if (unlikely(CV.end() == true) || + (CV->MultiArch & pkgCache::Version::Same) != pkgCache::Version::Same) + continue; + + // not downloadable means the package is obsolete, so allow out-of-sync + if (CV.Downloadable() == false) + continue; + + PkgState[Pkg->ID].iFlags |= AutoKept; + if (unlikely(DebugMarker == true)) + std::clog << OutputInDepth(Depth) << "Ignore MarkInstall of " << Pkg + << " as its M-A:same siblings are not version-synced" << std::endl; + return false; + } + return true; } /*}}}*/ @@ -1681,8 +1727,6 @@ bool pkgDepCache::MarkRequired(InRootSetFunc &userFunc) follow_recommends = MarkFollowsRecommends(); follow_suggests = MarkFollowsSuggests(); - - // do the mark part, this is the core bit of the algorithm for(PkgIterator p = PkgBegin(); !p.end(); ++p) { @@ -1693,7 +1737,9 @@ bool pkgDepCache::MarkRequired(InRootSetFunc &userFunc) // be nice even then a required package violates the policy (#583517) // and do the full mark process also for required packages (p.CurrentVer().end() != true && - p.CurrentVer()->Priority == pkgCache::State::Required)) + p.CurrentVer()->Priority == pkgCache::State::Required) || + // packages which can't be changed (like holds) can't be garbage + (IsModeChangeOk(ModeGarbage, p, 0, false) == false)) { // the package is installed (and set to keep) if(PkgState[p->ID].Keep() && !p.CurrentVer().end()) diff --git a/apt-pkg/depcache.h b/apt-pkg/depcache.h index 7358048ed..61c9aa559 100644 --- a/apt-pkg/depcache.h +++ b/apt-pkg/depcache.h @@ -128,7 +128,7 @@ class pkgDepCache : protected pkgCache::Namespace enum InternalFlags {AutoKept = (1 << 0), Purge = (1 << 1), ReInstall = (1 << 2), Protected = (1 << 3)}; enum VersionTypes {NowVersion, InstallVersion, CandidateVersion}; - enum ModeList {ModeDelete = 0, ModeKeep = 1, ModeInstall = 2}; + enum ModeList {ModeDelete = 0, ModeKeep = 1, ModeInstall = 2, ModeGarbage = 3}; /** \brief Represents an active action group. * @@ -442,16 +442,15 @@ class pkgDepCache : protected pkgCache::Namespace /** \return \b true if it's OK for MarkInstall to install * the given package. * - * See the default implementation for a simple example how this - * method can be used. - * Overriding implementations should use the hold-state-flag to cache - * results from previous checks of this package - also it should - * be used if the default resolver implementation is also used to - * ensure that these packages are handled like "normal" dpkg holds. + * The default implementation simply calls all IsInstallOk* + * method mentioned below. + * + * Overriding implementations should use the hold-state-flag to + * cache results from previous checks of this package - if possible. * * The parameters are the same as in the calling MarkInstall: * \param Pkg the package that MarkInstall wants to install. - * \param AutoInst needs a previous MarkInstall this package? + * \param AutoInst install this and all its dependencies * \param Depth recursive deep of this Marker call * \param FromUser was the install requested by the user? */ @@ -461,12 +460,8 @@ class pkgDepCache : protected pkgCache::Namespace /** \return \b true if it's OK for MarkDelete to remove * the given package. * - * See the default implementation for a simple example how this - * method can be used. - * Overriding implementations should use the hold-state-flag to cache - * results from previous checks of this package - also it should - * be used if the default resolver implementation is also used to - * ensure that these packages are handled like "normal" dpkg holds. + * The default implementation simply calls all IsDeleteOk* + * method mentioned below, see also #IsInstallOk. * * The parameters are the same as in the calling MarkDelete: * \param Pkg the package that MarkDelete wants to remove. @@ -498,6 +493,15 @@ class pkgDepCache : protected pkgCache::Namespace pkgDepCache(pkgCache *Cache,Policy *Plcy = 0); virtual ~pkgDepCache(); + protected: + // methods call by IsInstallOk + bool IsInstallOkMultiArchSameVersionSynced(PkgIterator const &Pkg, + bool const AutoInst, unsigned long const Depth, bool const FromUser); + + // methods call by IsDeleteOk + bool IsDeleteOkProtectInstallRequests(PkgIterator const &Pkg, + bool const rPurge, unsigned long const Depth, bool const FromUser); + private: bool IsModeChangeOk(ModeList const mode, PkgIterator const &Pkg, unsigned long const Depth, bool const FromUser); diff --git a/apt-pkg/indexcopy.cc b/apt-pkg/indexcopy.cc index 1d61b974d..7694cb1dd 100644 --- a/apt-pkg/indexcopy.cc +++ b/apt-pkg/indexcopy.cc @@ -106,9 +106,9 @@ bool IndexCopy::CopyPackages(string CDROM,string Name,vector<string> &List, } else { Target.Open(TargetF,FileFd::WriteAtomic); } - FILE *TargetFl = fdopen(dup(Target.Fd()),"w"); if (_error->PendingError() == true) return false; + FILE *TargetFl = fdopen(dup(Target.Fd()),"w"); if (TargetFl == 0) return _error->Errno("fdopen","Failed to reopen fd"); @@ -601,6 +601,7 @@ bool SigVerify::CopyAndVerify(string CDROM,string Name,vector<string> &SigList, (useInRelease ? inrelease.c_str() : releasegpg.c_str())); // something went wrong, don't copy the Release.gpg // FIXME: delete any existing gpg file? + delete MetaIndex; continue; } @@ -714,9 +715,9 @@ bool TranslationsCopy::CopyTranslations(string CDROM,string Name, /*{{{*/ } else { Target.Open(TargetF,FileFd::WriteAtomic); } - FILE *TargetFl = fdopen(dup(Target.Fd()),"w"); if (_error->PendingError() == true) return false; + FILE *TargetFl = fdopen(dup(Target.Fd()),"w"); if (TargetFl == 0) return _error->Errno("fdopen","Failed to reopen fd"); diff --git a/apt-pkg/indexrecords.cc b/apt-pkg/indexrecords.cc index e37a78cfb..8a72ca151 100644 --- a/apt-pkg/indexrecords.cc +++ b/apt-pkg/indexrecords.cc @@ -62,7 +62,7 @@ bool indexRecords::Load(const string Filename) /*{{{*/ if (OpenMaybeClearSignedFile(Filename, Fd) == false) return false; - pkgTagFile TagFile(&Fd, Fd.Size() + 256); // XXX + pkgTagFile TagFile(&Fd, Fd.Size()); if (_error->PendingError() == true) { strprintf(ErrorText, _("Unable to parse Release file %s"),Filename.c_str()); @@ -71,16 +71,11 @@ bool indexRecords::Load(const string Filename) /*{{{*/ pkgTagSection Section; const char *Start, *End; - // Skip over sections beginning with ----- as this is an idicator for clearsigns - do { - if (TagFile.Step(Section) == false) - { - strprintf(ErrorText, _("No sections in Release file %s"), Filename.c_str()); - return false; - } - - Section.Get (Start, End, 0); - } while (End - Start > 5 && strncmp(Start, "-----", 5) == 0); + if (TagFile.Step(Section) == false) + { + strprintf(ErrorText, _("No sections in Release file %s"), Filename.c_str()); + return false; + } Suite = Section.FindS("Suite"); Dist = Section.FindS("Codename"); diff --git a/apt-pkg/pkgcache.cc b/apt-pkg/pkgcache.cc index d7725563b..52e814c0b 100644 --- a/apt-pkg/pkgcache.cc +++ b/apt-pkg/pkgcache.cc @@ -924,6 +924,18 @@ string pkgCache::VerIterator::RelStr() const return Res; } /*}}}*/ +// VerIterator::MultiArchType - string representing MultiArch flag /*{{{*/ +const char * pkgCache::VerIterator::MultiArchType() const +{ + if ((S->MultiArch & pkgCache::Version::Same) == pkgCache::Version::Same) + return "same"; + else if ((S->MultiArch & pkgCache::Version::Foreign) == pkgCache::Version::Foreign) + return "foreign"; + else if ((S->MultiArch & pkgCache::Version::Allowed) == pkgCache::Version::Allowed) + return "allowed"; + return "none"; +} + /*}}}*/ // PkgFileIterator::IsOk - Checks if the cache is in sync with the file /*{{{*/ // --------------------------------------------------------------------- /* This stats the file and compares its stats with the ones that were diff --git a/apt-pkg/policy.cc b/apt-pkg/policy.cc index 4ae3b5f87..0a06cc6e3 100644 --- a/apt-pkg/policy.cc +++ b/apt-pkg/policy.cc @@ -166,11 +166,15 @@ pkgCache::VerIterator pkgPolicy::GetCandidateVer(pkgCache::PkgIterator const &Pk tracks the default when the default is taken away, and a permanent pin that stays at that setting. */ + bool PrefSeen = false; for (pkgCache::VerIterator Ver = Pkg.VersionList(); Ver.end() == false; ++Ver) { /* Lets see if this version is the installed version */ bool instVer = (Pkg.CurrentVer() == Ver); + if (Pref == Ver) + PrefSeen = true; + for (pkgCache::VerFileIterator VF = Ver.FileList(); VF.end() == false; ++VF) { /* If this is the status file, and the current version is not the @@ -187,26 +191,33 @@ pkgCache::VerIterator pkgPolicy::GetCandidateVer(pkgCache::PkgIterator const &Pk { Pref = Ver; Max = Prio; + PrefSeen = true; } if (Prio > MaxAlt) { PrefAlt = Ver; MaxAlt = Prio; - } - } - + } + } + if (instVer == true && Max < 1000) { + /* Not having seen the Pref yet means we have a specific pin below 1000 + on a version below the current installed one, so ignore the specific pin + as this would be a downgrade otherwise */ + if (PrefSeen == false || Pref.end() == true) + { + Pref = Ver; + PrefSeen = true; + } /* Elevate our current selection (or the status file itself) to the Pseudo-status priority. */ - if (Pref.end() == true) - Pref = Ver; Max = 1000; - + // Fast path optimize. if (StatusOverride == false) break; - } + } } // If we do not find our candidate, use the one with the highest pin. // This means that if there is a version available with pin > 0; there diff --git a/apt-pkg/tagfile.cc b/apt-pkg/tagfile.cc index 1c79ee74f..e0802e3d5 100644 --- a/apt-pkg/tagfile.cc +++ b/apt-pkg/tagfile.cc @@ -50,21 +50,27 @@ public: /* */ pkgTagFile::pkgTagFile(FileFd *pFd,unsigned long long Size) { + /* The size is increased by 4 because if we start with the Size of the + filename we need to try to read 1 char more to see an EOF faster, 1 + char the end-pointer can be on and maybe 2 newlines need to be added + to the end of the file -> 4 extra chars */ + Size += 4; d = new pkgTagFilePrivate(pFd, Size); if (d->Fd.IsOpen() == false) - { d->Start = d->End = d->Buffer = 0; + else + d->Buffer = (char*)malloc(sizeof(char) * Size); + + if (d->Buffer == NULL) d->Done = true; - d->iOffset = 0; - return; - } - - d->Buffer = new char[Size]; + else + d->Done = false; + d->Start = d->End = d->Buffer; - d->Done = false; d->iOffset = 0; - Fill(); + if (d->Done == false) + Fill(); } /*}}}*/ // TagFile::~pkgTagFile - Destructor /*{{{*/ @@ -72,11 +78,11 @@ pkgTagFile::pkgTagFile(FileFd *pFd,unsigned long long Size) /* */ pkgTagFile::~pkgTagFile() { - delete [] d->Buffer; + free(d->Buffer); delete d; } /*}}}*/ -// TagFile::Offset - Return the current offset in the buffer /*{{{*/ +// TagFile::Offset - Return the current offset in the buffer /*{{{*/ unsigned long pkgTagFile::Offset() { return d->iOffset; @@ -89,19 +95,22 @@ unsigned long pkgTagFile::Offset() */ bool pkgTagFile::Resize() { - char *tmp; - unsigned long long EndSize = d->End - d->Start; - // fail is the buffer grows too big if(d->Size > 1024*1024+1) return false; + return Resize(d->Size * 2); +} +bool pkgTagFile::Resize(unsigned long long const newSize) +{ + unsigned long long const EndSize = d->End - d->Start; + // get new buffer and use it - tmp = new char[2*d->Size]; - memcpy(tmp, d->Buffer, d->Size); - d->Size = d->Size*2; - delete [] d->Buffer; - d->Buffer = tmp; + char* newBuffer = (char*)realloc(d->Buffer, sizeof(char) * newSize); + if (newBuffer == NULL) + return false; + d->Buffer = newBuffer; + d->Size = newSize; // update the start/end pointers to the new buffer d->Start = d->Buffer; @@ -152,9 +161,10 @@ bool pkgTagFile::Fill() if (d->Done == false) { // See if only a bit of the file is left - if (d->Fd.Read(d->End, d->Size - (d->End - d->Buffer),&Actual) == false) + unsigned long long const dataSize = d->Size - ((d->End - d->Buffer) + 1); + if (d->Fd.Read(d->End, dataSize, &Actual) == false) return false; - if (Actual != d->Size - (d->End - d->Buffer)) + if (Actual != dataSize) d->Done = true; d->End += Actual; } @@ -171,8 +181,13 @@ bool pkgTagFile::Fill() for (const char *E = d->End - 1; E - d->End < 6 && (*E == '\n' || *E == '\r'); E--) if (*E == '\n') LineCount++; - for (; LineCount < 2; LineCount++) - *d->End++ = '\n'; + if (LineCount < 2) + { + if ((unsigned)(d->End - d->Buffer) >= d->Size) + Resize(d->Size + 3); + for (; LineCount < 2; LineCount++) + *d->End++ = '\n'; + } return true; } @@ -218,6 +233,16 @@ bool pkgTagFile::Jump(pkgTagSection &Tag,unsigned long long Offset) return true; } /*}}}*/ +// pkgTagSection::pkgTagSection - Constructor /*{{{*/ +// --------------------------------------------------------------------- +/* */ +pkgTagSection::pkgTagSection() + : Section(0), TagCount(0), d(NULL), Stop(0) +{ + memset(&Indexes, 0, sizeof(Indexes)); + memset(&AlphaIndexes, 0, sizeof(AlphaIndexes)); +} + /*}}}*/ // TagSection::Scan - Scan for the end of the header information /*{{{*/ // --------------------------------------------------------------------- /* This looks for the first double new line in the data stream. diff --git a/apt-pkg/tagfile.h b/apt-pkg/tagfile.h index 4718f5101..518d3dbcd 100644 --- a/apt-pkg/tagfile.h +++ b/apt-pkg/tagfile.h @@ -84,7 +84,7 @@ class pkgTagSection Stop = this->Stop; }; - pkgTagSection() : Section(0), TagCount(0), Stop(0) {}; + pkgTagSection(); virtual ~pkgTagSection() {}; }; @@ -95,6 +95,7 @@ class pkgTagFile bool Fill(); bool Resize(); + bool Resize(unsigned long long const newSize); public: diff --git a/apt-pkg/vendorlist.cc b/apt-pkg/vendorlist.cc index ecfc7db87..602425624 100644 --- a/apt-pkg/vendorlist.cc +++ b/apt-pkg/vendorlist.cc @@ -66,7 +66,7 @@ bool pkgVendorList::CreateList(Configuration& Cnf) /*{{{*/ Configuration Block(Top); string VendorID = Top->Tag; vector <struct Vendor::Fingerprint *> *Fingerprints = new vector<Vendor::Fingerprint *>; - struct Vendor::Fingerprint *Fingerprint = new struct Vendor::Fingerprint; + struct Vendor::Fingerprint *Fingerprint = new struct Vendor::Fingerprint(); string Origin = Block.Find("Origin"); Fingerprint->Print = Block.Find("Fingerprint"); |