diff options
author | David Kalnischkies <david@kalnischkies.de> | 2015-01-08 21:07:37 +0100 |
---|---|---|
committer | David Kalnischkies <david@kalnischkies.de> | 2015-03-16 18:01:13 +0100 |
commit | 2f6a2fbbdc9f76dc4eace83a427013f4e1c03afc (patch) | |
tree | c831f594596241ef1ef56c20dbd1f4e39a6840b9 /apt-pkg | |
parent | 3de7789a75c58204bcc979c72899cfdacba4e2ac (diff) |
properly implement pkgRecord::Parser for *.deb files
Implementing FileName() works for most cases for us, but other
frontends might need more and even for us its not very stable as
the normal Jump() implementation is pretty bad on a deb file and
produce errors on its own at times.
So, replacing this makeshift with a complete implementation by
mostly just shuffling code around.
Diffstat (limited to 'apt-pkg')
-rw-r--r-- | apt-pkg/deb/debindexfile.cc | 73 | ||||
-rw-r--r-- | apt-pkg/deb/debindexfile.h | 8 | ||||
-rw-r--r-- | apt-pkg/deb/debrecords.cc | 108 | ||||
-rw-r--r-- | apt-pkg/deb/debrecords.h | 49 | ||||
-rw-r--r-- | apt-pkg/tagfile.cc | 6 |
5 files changed, 133 insertions, 111 deletions
diff --git a/apt-pkg/deb/debindexfile.cc b/apt-pkg/deb/debindexfile.cc index cecfe41a9..49c6e8cc0 100644 --- a/apt-pkg/deb/debindexfile.cc +++ b/apt-pkg/deb/debindexfile.cc @@ -34,6 +34,7 @@ #include <stdio.h> #include <iostream> +#include <sstream> #include <string> #include <sys/stat.h> /*}}}*/ @@ -671,8 +672,7 @@ APT_CONST bool debStatusIndex::Exists() const } /*}}}*/ -// debDebPkgFile - Single .deb file /*{{{*/ -// --------------------------------------------------------------------- +// debDebPkgFile - Single .deb file /*{{{*/ debDebPkgFileIndex::debDebPkgFileIndex(std::string DebFile) : pkgIndexFile(true), DebFile(DebFile) { @@ -688,53 +688,56 @@ bool debDebPkgFileIndex::Exists() const { return FileExists(DebFile); } -bool debDebPkgFileIndex::Merge(pkgCacheGenerator& Gen, OpProgress* Prog) const +bool debDebPkgFileIndex::GetContent(std::ostream &content, std::string const &debfile) { - if(Prog) - Prog->SubProgress(0, "Reading deb file"); - - // get the control data out of the deb file vid dpkg -I - // ... can I haz libdpkg? - Configuration::Item const *Opts = _config->Tree("DPkg::Options"); - std::string dpkg = _config->Find("Dir::Bin::dpkg","dpkg"); + // get the control data out of the deb file via dpkg-deb -I + std::string dpkg = _config->Find("Dir::Bin::dpkg","dpkg-deb"); std::vector<const char *> Args; Args.push_back(dpkg.c_str()); - if (Opts != 0) - { - Opts = Opts->Child; - for (; Opts != 0; Opts = Opts->Next) - { - if (Opts->Value.empty() == true) - continue; - Args.push_back(Opts->Value.c_str()); - } - } Args.push_back("-I"); - Args.push_back(DebFile.c_str()); + Args.push_back(debfile.c_str()); Args.push_back("control"); Args.push_back(NULL); FileFd PipeFd; pid_t Child; if(Popen((const char**)&Args[0], 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"); + + char buffer[1024]; + do { + unsigned long long actual = 0; + if (PipeFd.Read(buffer, sizeof(buffer)-1, &actual) == false) + return _error->Errno("read", "Failed to read dpkg pipe"); + if (actual == 0) + break; + buffer[actual] = '\0'; + content << buffer; + } while(true); ExecWait(Child, "Popen"); - // now write the control data to a tempfile + content << "Filename: " << debfile << "\n"; + struct stat Buf; + if (stat(debfile.c_str(), &Buf) != 0) + return false; + content << "Size: " << Buf.st_size << "\n"; + + return true; +} +bool debDebPkgFileIndex::Merge(pkgCacheGenerator& Gen, OpProgress* Prog) const +{ + if(Prog) + Prog->SubProgress(0, "Reading deb file"); + + // write the control data to a tempfile SPtr<FileFd> DebControl = GetTempFile("deb-file-" + flNotDir(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 + std::ostringstream content; + if (GetContent(content, DebFile) == false) + return false; + std::string const contentstr = content.str(); + DebControl->Write(contentstr.c_str(), contentstr.length()); + // rewind for the listparser DebControl->Seek(0); // and give it to the list parser @@ -838,7 +841,7 @@ class APT_HIDDEN debIFTypeDebPkgFile : public pkgIndexFile::Type public: virtual pkgRecords::Parser *CreatePkgParser(pkgCache::PkgFileIterator File) const { - return new debDebFileRecordParser(File.FileName(),*File.Cache()); + return new debDebFileRecordParser(File.FileName()); }; debIFTypeDebPkgFile() {Label = "deb Package file";}; }; diff --git a/apt-pkg/deb/debindexfile.h b/apt-pkg/deb/debindexfile.h index 312e915f1..81914f203 100644 --- a/apt-pkg/deb/debindexfile.h +++ b/apt-pkg/deb/debindexfile.h @@ -177,6 +177,14 @@ class APT_HIDDEN debDebPkgFileIndex : public pkgIndexFile return DebFile; } + /** get the control (file) content of the deb file + * + * @param[out] content of the control file + * @param debfile is the filename of the .deb-file + * @return \b true if successful, otherwise \b false. + */ + static bool GetContent(std::ostream &content, std::string const &debfile); + // Interface for the Cache Generator virtual bool Exists() const; virtual bool HasPackages() const { diff --git a/apt-pkg/deb/debrecords.cc b/apt-pkg/deb/debrecords.cc index b41aa5584..335bcfda0 100644 --- a/apt-pkg/deb/debrecords.cc +++ b/apt-pkg/deb/debrecords.cc @@ -11,35 +11,35 @@ #include <config.h> #include <apt-pkg/debrecords.h> +#include <apt-pkg/debindexfile.h> #include <apt-pkg/strutl.h> #include <apt-pkg/aptconfiguration.h> #include <apt-pkg/fileutl.h> #include <apt-pkg/cacheiterators.h> #include <apt-pkg/pkgcache.h> #include <apt-pkg/tagfile.h> +#include <apt-pkg/error.h> #include <string.h> #include <algorithm> +#include <sstream> #include <string> #include <vector> #include <langinfo.h> + +#include <apti18n.h> /*}}}*/ using std::string; // RecordParser::debRecordParser - Constructor /*{{{*/ -// --------------------------------------------------------------------- -/* */ -debRecordParser::debRecordParser(string FileName,pkgCache &Cache) : - File(FileName,FileFd::ReadOnly, FileFd::Extension), - Tags(&File, std::max(Cache.Head().MaxVerFileSize, - Cache.Head().MaxDescFileSize) + 200) +debRecordParser::debRecordParser(string FileName,pkgCache &Cache) : + debRecordParserBase(), File(FileName, FileFd::ReadOnly, FileFd::Extension), + Tags(&File, std::max(Cache.Head().MaxVerFileSize, Cache.Head().MaxDescFileSize) + 200) { } /*}}}*/ // RecordParser::Jump - Jump to a specific record /*{{{*/ -// --------------------------------------------------------------------- -/* */ bool debRecordParser::Jump(pkgCache::VerFileIterator const &Ver) { return Tags.Jump(Section,Ver->Offset); @@ -49,32 +49,28 @@ bool debRecordParser::Jump(pkgCache::DescFileIterator const &Desc) return Tags.Jump(Section,Desc->Offset); } /*}}}*/ -// RecordParser::FileName - Return the archive filename on the site /*{{{*/ -// --------------------------------------------------------------------- -/* */ -string debRecordParser::FileName() +debRecordParser::~debRecordParser() {} + +// RecordParserBase::FileName - Return the archive filename on the site /*{{{*/ +string debRecordParserBase::FileName() { return Section.FindS("Filename"); } /*}}}*/ -// RecordParser::Name - Return the package name /*{{{*/ -// --------------------------------------------------------------------- -/* */ -string debRecordParser::Name() +// RecordParserBase::Name - Return the package name /*{{{*/ +string debRecordParserBase::Name() { return Section.FindS("Package"); } /*}}}*/ -// RecordParser::Homepage - Return the package homepage /*{{{*/ -// --------------------------------------------------------------------- -/* */ -string debRecordParser::Homepage() +// RecordParserBase::Homepage - Return the package homepage /*{{{*/ +string debRecordParserBase::Homepage() { return Section.FindS("Homepage"); } /*}}}*/ -// RecordParser::Hashes - return the available archive hashes /*{{{*/ -HashStringList debRecordParser::Hashes() const +// RecordParserBase::Hashes - return the available archive hashes /*{{{*/ +HashStringList debRecordParserBase::Hashes() const { HashStringList hashes; for (char const * const * type = HashString::SupportedHashes(); *type != NULL; ++type) @@ -86,27 +82,20 @@ HashStringList debRecordParser::Hashes() const return hashes; } /*}}}*/ -// RecordParser::Maintainer - Return the maintainer email /*{{{*/ -// --------------------------------------------------------------------- -/* */ -string debRecordParser::Maintainer() +// RecordParserBase::Maintainer - Return the maintainer email /*{{{*/ +string debRecordParserBase::Maintainer() { return Section.FindS("Maintainer"); } /*}}}*/ -// RecordParser::RecordField - Return the value of an arbitrary field /*{{*/ -// --------------------------------------------------------------------- -/* */ -string debRecordParser::RecordField(const char *fieldName) +// RecordParserBase::RecordField - Return the value of an arbitrary field /*{{*/ +string debRecordParserBase::RecordField(const char *fieldName) { return Section.FindS(fieldName); } - - /*}}}*/ -// RecordParser::ShortDesc - Return a 1 line description /*{{{*/ -// --------------------------------------------------------------------- -/* */ -string debRecordParser::ShortDesc(std::string const &lang) + /*}}}*/ +// RecordParserBase::ShortDesc - Return a 1 line description /*{{{*/ +string debRecordParserBase::ShortDesc(std::string const &lang) { string const Res = LongDesc(lang); if (Res.empty() == true) @@ -117,10 +106,8 @@ string debRecordParser::ShortDesc(std::string const &lang) return string(Res,0,Pos); } /*}}}*/ -// RecordParser::LongDesc - Return a longer description /*{{{*/ -// --------------------------------------------------------------------- -/* */ -string debRecordParser::LongDesc(std::string const &lang) +// RecordParserBase::LongDesc - Return a longer description /*{{{*/ +string debRecordParserBase::LongDesc(std::string const &lang) { string orig; if (lang.empty() == true) @@ -162,12 +149,9 @@ string debRecordParser::LongDesc(std::string const &lang) } /*}}}*/ -static const char *SourceVerSeparators = " ()"; - -// RecordParser::SourcePkg - Return the source package name if any /*{{{*/ -// --------------------------------------------------------------------- -/* */ -string debRecordParser::SourcePkg() +static const char * const SourceVerSeparators = " ()"; +// RecordParserBase::SourcePkg - Return the source package name if any /*{{{*/ +string debRecordParserBase::SourcePkg() { string Res = Section.FindS("Source"); string::size_type Pos = Res.find_first_of(SourceVerSeparators); @@ -176,10 +160,8 @@ string debRecordParser::SourcePkg() return string(Res,0,Pos); } /*}}}*/ -// RecordParser::SourceVer - Return the source version number if present /*{{{*/ -// --------------------------------------------------------------------- -/* */ -string debRecordParser::SourceVer() +// RecordParserBase::SourceVer - Return the source version number if present /*{{{*/ +string debRecordParserBase::SourceVer() { string Pkg = Section.FindS("Source"); string::size_type Pos = Pkg.find_first_of(SourceVerSeparators); @@ -199,13 +181,29 @@ string debRecordParser::SourceVer() return string(Pkg, VerStart, VerEnd - VerStart); } /*}}}*/ -// RecordParser::GetRec - Return the whole record /*{{{*/ -// --------------------------------------------------------------------- -/* */ -void debRecordParser::GetRec(const char *&Start,const char *&Stop) +// RecordParserBase::GetRec - Return the whole record /*{{{*/ +void debRecordParserBase::GetRec(const char *&Start,const char *&Stop) { Section.GetSection(Start,Stop); } /*}}}*/ +debRecordParserBase::~debRecordParserBase() {} -debRecordParser::~debRecordParser() {} +bool debDebFileRecordParser::LoadContent() +{ + // load content only once + if (controlContent.empty() == false) + return true; + + std::ostringstream content; + if (debDebPkgFileIndex::GetContent(content, debFileName) == false) + return false; + // add two newlines to make sure the scanner finds the section, + // which is usually done by pkgTagFile automatically if needed. + content << "\n\n"; + + controlContent = content.str(); + if (Section.Scan(controlContent.c_str(), controlContent.length()) == false) + return _error->Error(_("Unable to parse package file %s (%d)"), debFileName.c_str(), 3); + return true; +} diff --git a/apt-pkg/deb/debrecords.h b/apt-pkg/deb/debrecords.h index 7091c38e6..38e071940 100644 --- a/apt-pkg/deb/debrecords.h +++ b/apt-pkg/deb/debrecords.h @@ -25,21 +25,12 @@ #include <apt-pkg/indexfile.h> #endif -class APT_HIDDEN debRecordParser : public pkgRecords::Parser +class APT_HIDDEN debRecordParserBase : public pkgRecords::Parser { - /** \brief dpointer placeholder (for later in case we need it) */ - void *d; - protected: - FileFd File; - pkgTagFile Tags; pkgTagSection Section; - - 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(); virtual std::string SourcePkg(); @@ -58,20 +49,42 @@ class APT_HIDDEN debRecordParser : public pkgRecords::Parser virtual std::string RecordField(const char *fieldName); virtual void GetRec(const char *&Start,const char *&Stop); - + + debRecordParserBase() : Parser() {} + virtual ~debRecordParserBase(); +}; + +class APT_HIDDEN debRecordParser : public debRecordParserBase +{ + protected: + FileFd File; + pkgTagFile Tags; + + virtual bool Jump(pkgCache::VerFileIterator const &Ver); + virtual bool Jump(pkgCache::DescFileIterator const &Desc); + + public: debRecordParser(std::string FileName,pkgCache &Cache); virtual ~debRecordParser(); }; // custom record parser that reads deb files directly -class APT_HIDDEN debDebFileRecordParser : public debRecordParser +class APT_HIDDEN debDebFileRecordParser : public debRecordParserBase { + std::string debFileName; + std::string controlContent; + + APT_HIDDEN bool LoadContent(); + protected: + // single file files, so no jumping whatsoever + bool Jump(pkgCache::VerFileIterator const &) { return LoadContent(); } + bool Jump(pkgCache::DescFileIterator const &) { return LoadContent(); } + public: - virtual std::string FileName() { - return File.Name(); - } - debDebFileRecordParser(std::string FileName,pkgCache &Cache) - : debRecordParser(FileName, Cache) {}; + virtual std::string FileName() { return debFileName; } + + debDebFileRecordParser(std::string FileName) + : debRecordParserBase(), debFileName(FileName) {}; }; #endif diff --git a/apt-pkg/tagfile.cc b/apt-pkg/tagfile.cc index 590206f17..9c40c8c92 100644 --- a/apt-pkg/tagfile.cc +++ b/apt-pkg/tagfile.cc @@ -183,8 +183,8 @@ bool pkgTagFile::Step(pkgTagSection &Tag) break; if (Resize() == false) - return _error->Error(_("Unable to parse package file %s (1)"), - d->Fd.Name().c_str()); + return _error->Error(_("Unable to parse package file %s (%d)"), + d->Fd.Name().c_str(), 1); } while (Tag.Scan(d->Start,d->End - d->Start, false) == false); } @@ -283,7 +283,7 @@ bool pkgTagFile::Jump(pkgTagSection &Tag,unsigned long long Offset) return false; if (Tag.Scan(d->Start, d->End - d->Start, false) == false) - return _error->Error(_("Unable to parse package file %s (2)"),d->Fd.Name().c_str()); + return _error->Error(_("Unable to parse package file %s (%d)"),d->Fd.Name().c_str(), 2); return true; } |