summaryrefslogtreecommitdiffstats
path: root/apt-pkg/deb/debsrcrecords.cc
diff options
context:
space:
mode:
Diffstat (limited to 'apt-pkg/deb/debsrcrecords.cc')
-rw-r--r--apt-pkg/deb/debsrcrecords.cc324
1 files changed, 324 insertions, 0 deletions
diff --git a/apt-pkg/deb/debsrcrecords.cc b/apt-pkg/deb/debsrcrecords.cc
new file mode 100644
index 0000000..9656fca
--- /dev/null
+++ b/apt-pkg/deb/debsrcrecords.cc
@@ -0,0 +1,324 @@
+// -*- mode: cpp; mode: fold -*-
+// Description /*{{{*/
+/* ######################################################################
+
+ Debian Source Package Records - Parser implementation for Debian style
+ source indexes
+
+ ##################################################################### */
+ /*}}}*/
+// Include Files /*{{{*/
+#include <config.h>
+
+#include <apt-pkg/aptconfiguration.h>
+#include <apt-pkg/deblistparser.h>
+#include <apt-pkg/debsrcrecords.h>
+#include <apt-pkg/error.h>
+#include <apt-pkg/gpgv.h>
+#include <apt-pkg/hashes.h>
+#include <apt-pkg/srcrecords.h>
+#include <apt-pkg/strutl.h>
+#include <apt-pkg/tagfile-keys.h>
+#include <apt-pkg/tagfile.h>
+
+#include <algorithm>
+#include <string>
+#include <vector>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+ /*}}}*/
+
+using std::max;
+using std::string;
+
+debSrcRecordParser::debSrcRecordParser(std::string const &File,pkgIndexFile const *Index)
+ : Parser(Index), d(NULL), Tags(&Fd), iOffset(0), Buffer(NULL)
+{
+ if (File.empty() == false)
+ {
+ if (Fd.Open(File, FileFd::ReadOnly, FileFd::Extension))
+ Tags.Init(&Fd, 102400);
+ }
+}
+std::string debSrcRecordParser::Package() const /*{{{*/
+{
+ auto const name = Sect.Find(pkgTagSection::Key::Package);
+ if (iIndex != nullptr || name.empty() == false)
+ return name.to_string();
+ return Sect.Find(pkgTagSection::Key::Source).to_string();
+}
+ /*}}}*/
+// SrcRecordParser::Binaries - Return the binaries field /*{{{*/
+// ---------------------------------------------------------------------
+/* This member parses the binaries field into a pair of class arrays and
+ returns a list of strings representing all of the components of the
+ binaries field. The returned array need not be freed and will be
+ reused by the next Binaries function call. This function is commonly
+ used during scanning to find the right package */
+const char **debSrcRecordParser::Binaries()
+{
+ const char *Start, *End;
+ if (Sect.Find(pkgTagSection::Key::Binary, Start, End) == false)
+ return NULL;
+ for (; isspace_ascii(*Start) != 0; ++Start);
+ if (Start >= End)
+ return NULL;
+
+ StaticBinList.clear();
+ free(Buffer);
+ Buffer = strndup(Start, End - Start);
+
+ char* bin = Buffer;
+ do {
+ char* binStartNext = strchrnul(bin, ',');
+ // Found a comma, clean up any space before it
+ if (binStartNext > Buffer) {
+ char* binEnd = binStartNext - 1;
+ for (; binEnd > Buffer && isspace_ascii(*binEnd) != 0; --binEnd)
+ *binEnd = 0;
+ }
+ StaticBinList.push_back(bin);
+ if (*binStartNext != ',')
+ break;
+ *binStartNext = '\0';
+ for (bin = binStartNext + 1; isspace_ascii(*bin) != 0; ++bin)
+ ;
+ } while (*bin != '\0');
+ StaticBinList.push_back(NULL);
+
+ return &StaticBinList[0];
+}
+ /*}}}*/
+// SrcRecordParser::BuildDepends - Return the Build-Depends information /*{{{*/
+// ---------------------------------------------------------------------
+/* This member parses the build-depends information and returns a list of
+ package/version records representing the build dependency. The returned
+ array need not be freed and will be reused by the next call to this
+ function */
+bool debSrcRecordParser::BuildDepends(std::vector<pkgSrcRecords::Parser::BuildDepRec> &BuildDeps,
+ bool const &ArchOnly, bool const &StripMultiArch)
+{
+ BuildDeps.clear();
+
+ pkgTagSection::Key const fields[] = {
+ pkgTagSection::Key::Build_Depends,
+ pkgTagSection::Key::Build_Depends_Indep,
+ pkgTagSection::Key::Build_Conflicts,
+ pkgTagSection::Key::Build_Conflicts_Indep,
+ pkgTagSection::Key::Build_Depends_Arch,
+ pkgTagSection::Key::Build_Conflicts_Arch,
+ };
+ for (unsigned short I = 0; I < sizeof(fields) / sizeof(fields[0]); ++I)
+ {
+ if (ArchOnly && (fields[I] == pkgTagSection::Key::Build_Depends_Indep || fields[I] == pkgTagSection::Key::Build_Conflicts_Indep))
+ continue;
+
+ const char *Start, *Stop;
+ if (Sect.Find(fields[I], Start, Stop) == false)
+ continue;
+
+ if (Start == Stop)
+ continue;
+
+ while (1)
+ {
+ BuildDepRec rec;
+ Start = debListParser::ParseDepends(Start, Stop,
+ rec.Package, rec.Version, rec.Op, true, StripMultiArch, true);
+
+ if (Start == 0)
+ return _error->Error("Problem parsing dependency: %s", BuildDepType(I));
+ rec.Type = I;
+
+ // We parsed a package that was ignored (wrong architecture restriction
+ // or something).
+ if (rec.Package.empty())
+ {
+ // If we are in an OR group, we need to set the "Or" flag of the
+ // previous entry to our value.
+ if (BuildDeps.empty() == false && (BuildDeps[BuildDeps.size() - 1].Op & pkgCache::Dep::Or) == pkgCache::Dep::Or)
+ {
+ BuildDeps[BuildDeps.size() - 1].Op &= ~pkgCache::Dep::Or;
+ BuildDeps[BuildDeps.size() - 1].Op |= (rec.Op & pkgCache::Dep::Or);
+ }
+ } else {
+ BuildDeps.emplace_back(std::move(rec));
+ }
+
+ if (Start == Stop)
+ break;
+ }
+ }
+
+ return true;
+}
+ /*}}}*/
+// SrcRecordParser::Files - Return a list of files for this source /*{{{*/
+// ---------------------------------------------------------------------
+/* This parses the list of files and returns it, each file is required to have
+ a complete source package */
+bool debSrcRecordParser::Files(std::vector<pkgSrcRecords::File> &F)
+{
+ std::vector<pkgSrcRecords::File2> F2;
+ if (Files2(F2) == false)
+ return false;
+ for (std::vector<pkgSrcRecords::File2>::const_iterator f2 = F2.begin(); f2 != F2.end(); ++f2)
+ {
+ pkgSrcRecords::File2 f;
+#if __GNUC__ >= 4
+ #pragma GCC diagnostic push
+ #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+#endif
+ f.MD5Hash = f2->MD5Hash;
+ f.Size = f2->Size;
+#if __GNUC__ >= 4
+ #pragma GCC diagnostic pop
+#endif
+ f.Path = f2->Path;
+ f.Type = f2->Type;
+ F.push_back(f);
+ }
+ return true;
+}
+bool debSrcRecordParser::Files2(std::vector<pkgSrcRecords::File2> &List)
+{
+ List.clear();
+
+ // Stash the / terminated directory prefix
+ std::string Base = Sect.Find(pkgTagSection::Key::Directory).to_string();
+ if (Base.empty() == false && Base[Base.length()-1] != '/')
+ Base += '/';
+
+ std::vector<std::string> const compExts = APT::Configuration::getCompressorExtensions();
+
+ for (char const * const * type = HashString::SupportedHashes(); *type != NULL; ++type)
+ {
+ // derive field from checksum type
+ std::string checksumField("Checksums-");
+ if (strcmp(*type, "MD5Sum") == 0)
+ checksumField = "Files"; // historic name for MD5 checksums
+ else
+ checksumField.append(*type);
+
+ string const Files = Sect.FindS(checksumField.c_str());
+ if (Files.empty() == true)
+ continue;
+
+ // Iterate over the entire list grabbing each triplet
+ const char *C = Files.c_str();
+ while (*C != 0)
+ {
+ string hash, size, path;
+
+ // Parse each of the elements
+ if (ParseQuoteWord(C, hash) == false ||
+ ParseQuoteWord(C, size) == false ||
+ ParseQuoteWord(C, path) == false)
+ return _error->Error("Error parsing file record in %s of source package %s", checksumField.c_str(), Package().c_str());
+
+ if (iIndex == nullptr && checksumField == "Files")
+ {
+ // the Files field has a different format than the rest in deb-changes files
+ std::string ignore;
+ if (ParseQuoteWord(C, ignore) == false ||
+ ParseQuoteWord(C, path) == false)
+ return _error->Error("Error parsing file record in %s of source package %s", checksumField.c_str(), Package().c_str());
+ }
+
+ HashString const hashString(*type, hash);
+ if (Base.empty() == false)
+ path = Base + path;
+
+ // look if we have a record for this file already
+ std::vector<pkgSrcRecords::File2>::iterator file = List.begin();
+ for (; file != List.end(); ++file)
+ if (file->Path == path)
+ break;
+
+ // we have it already, store the new hash and be done
+ if (file != List.end())
+ {
+ if (checksumField == "Files")
+ {
+ APT_IGNORE_DEPRECATED_PUSH
+ file->MD5Hash = hash;
+ APT_IGNORE_DEPRECATED_POP
+ }
+ // an error here indicates that we have two different hashes for the same file
+ if (file->Hashes.push_back(hashString) == false)
+ return _error->Error("Error parsing checksum in %s of source package %s", checksumField.c_str(), Package().c_str());
+ continue;
+ }
+
+ // we haven't seen this file yet
+ pkgSrcRecords::File2 F;
+ F.Path = path;
+ F.FileSize = strtoull(size.c_str(), NULL, 10);
+ F.Hashes.push_back(hashString);
+ F.Hashes.FileSize(F.FileSize);
+
+ APT_IGNORE_DEPRECATED_PUSH
+ F.Size = F.FileSize;
+ if (checksumField == "Files")
+ F.MD5Hash = hash;
+ APT_IGNORE_DEPRECATED_POP
+
+ // Try to guess what sort of file it is we are getting.
+ string::size_type Pos = F.Path.length()-1;
+ while (1)
+ {
+ string::size_type Tmp = F.Path.rfind('.',Pos);
+ if (Tmp == string::npos)
+ break;
+ if (F.Type == "tar") {
+ // source v3 has extension 'debian.tar.*' instead of 'diff.*'
+ if (string(F.Path, Tmp+1, Pos-Tmp) == "debian")
+ F.Type = "diff";
+ break;
+ }
+ F.Type = string(F.Path,Tmp+1,Pos-Tmp);
+
+ if (std::find(compExts.begin(), compExts.end(), std::string(".").append(F.Type)) != compExts.end() ||
+ F.Type == "tar")
+ {
+ Pos = Tmp-1;
+ continue;
+ }
+
+ break;
+ }
+ List.push_back(F);
+ }
+ }
+
+ return true;
+}
+ /*}}}*/
+// SrcRecordParser::~SrcRecordParser - Destructor /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+debSrcRecordParser::~debSrcRecordParser()
+{
+ // was allocated via strndup()
+ free(Buffer);
+}
+ /*}}}*/
+
+
+debDscRecordParser::debDscRecordParser(std::string const &DscFile, pkgIndexFile const *Index)
+ : debSrcRecordParser("", Index)
+{
+ // support clear signed files
+ if (OpenMaybeClearSignedFile(DscFile, Fd) == false)
+ {
+ _error->Error("Failed to open %s", DscFile.c_str());
+ return;
+ }
+
+ // re-init to ensure the updated Fd is used
+ Tags.Init(&Fd, pkgTagFile::SUPPORT_COMMENTS);
+ // read the first (and only) record
+ Step();
+
+}