apt  2.2.4
About: Apt (Advanced Package Tool) is a management system for software packages (Debian/Ubuntu). Release series 2.2.
  Fossies Dox: apt-2.2.4.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

debsrcrecords.cc
Go to the documentation of this file.
1 // -*- mode: cpp; mode: fold -*-
2 // Description /*{{{*/
3 /* ######################################################################
4 
5  Debian Source Package Records - Parser implementation for Debian style
6  source indexes
7 
8  ##################################################################### */
9  /*}}}*/
10 // Include Files /*{{{*/
11 #include <config.h>
12 
14 #include <apt-pkg/deblistparser.h>
15 #include <apt-pkg/debsrcrecords.h>
16 #include <apt-pkg/error.h>
17 #include <apt-pkg/gpgv.h>
18 #include <apt-pkg/hashes.h>
19 #include <apt-pkg/srcrecords.h>
20 #include <apt-pkg/strutl.h>
21 #include <apt-pkg/tagfile-keys.h>
22 #include <apt-pkg/tagfile.h>
23 
24 #include <algorithm>
25 #include <string>
26 #include <vector>
27 #include <ctype.h>
28 #include <stdlib.h>
29 #include <string.h>
30  /*}}}*/
31 
32 using std::max;
33 using std::string;
34 
35 debSrcRecordParser::debSrcRecordParser(std::string const &File,pkgIndexFile const *Index)
36  : Parser(Index), d(NULL), Tags(&Fd), iOffset(0), Buffer(NULL)
37 {
38  if (File.empty() == false)
39  {
41  Tags.Init(&Fd, 102400);
42  }
43 }
44 std::string debSrcRecordParser::Package() const /*{{{*/
45 {
46  auto const name = Sect.Find(pkgTagSection::Key::Package);
47  if (iIndex != nullptr || name.empty() == false)
48  return name.to_string();
49  return Sect.Find(pkgTagSection::Key::Source).to_string();
50 }
51  /*}}}*/
52 // SrcRecordParser::Binaries - Return the binaries field /*{{{*/
53 // ---------------------------------------------------------------------
54 /* This member parses the binaries field into a pair of class arrays and
55  returns a list of strings representing all of the components of the
56  binaries field. The returned array need not be freed and will be
57  reused by the next Binaries function call. This function is commonly
58  used during scanning to find the right package */
60 {
61  const char *Start, *End;
62  if (Sect.Find(pkgTagSection::Key::Binary, Start, End) == false)
63  return NULL;
64  for (; isspace_ascii(*Start) != 0; ++Start);
65  if (Start >= End)
66  return NULL;
67 
68  StaticBinList.clear();
69  free(Buffer);
70  Buffer = strndup(Start, End - Start);
71 
72  char* bin = Buffer;
73  do {
74  char* binStartNext = strchrnul(bin, ',');
75  // Found a comma, clean up any space before it
76  if (binStartNext > Buffer) {
77  char* binEnd = binStartNext - 1;
78  for (; binEnd > Buffer && isspace_ascii(*binEnd) != 0; --binEnd)
79  *binEnd = 0;
80  }
81  StaticBinList.push_back(bin);
82  if (*binStartNext != ',')
83  break;
84  *binStartNext = '\0';
85  for (bin = binStartNext + 1; isspace_ascii(*bin) != 0; ++bin)
86  ;
87  } while (*bin != '\0');
88  StaticBinList.push_back(NULL);
89 
90  return &StaticBinList[0];
91 }
92  /*}}}*/
93 // SrcRecordParser::BuildDepends - Return the Build-Depends information /*{{{*/
94 // ---------------------------------------------------------------------
95 /* This member parses the build-depends information and returns a list of
96  package/version records representing the build dependency. The returned
97  array need not be freed and will be reused by the next call to this
98  function */
99 bool debSrcRecordParser::BuildDepends(std::vector<pkgSrcRecords::Parser::BuildDepRec> &BuildDeps,
100  bool const &ArchOnly, bool const &StripMultiArch)
101 {
102  BuildDeps.clear();
103 
104  pkgTagSection::Key const fields[] = {
105  pkgTagSection::Key::Build_Depends,
106  pkgTagSection::Key::Build_Depends_Indep,
107  pkgTagSection::Key::Build_Conflicts,
108  pkgTagSection::Key::Build_Conflicts_Indep,
109  pkgTagSection::Key::Build_Depends_Arch,
110  pkgTagSection::Key::Build_Conflicts_Arch,
111  };
112  for (unsigned short I = 0; I < sizeof(fields) / sizeof(fields[0]); ++I)
113  {
114  if (ArchOnly && (fields[I] == pkgTagSection::Key::Build_Depends_Indep || fields[I] == pkgTagSection::Key::Build_Conflicts_Indep))
115  continue;
116 
117  const char *Start, *Stop;
118  if (Sect.Find(fields[I], Start, Stop) == false)
119  continue;
120 
121  if (Start == Stop)
122  continue;
123 
124  while (1)
125  {
126  BuildDepRec rec;
127  Start = debListParser::ParseDepends(Start, Stop,
128  rec.Package, rec.Version, rec.Op, true, StripMultiArch, true);
129 
130  if (Start == 0)
131  return _error->Error("Problem parsing dependency: %s", BuildDepType(I));
132  rec.Type = I;
133 
134  // We parsed a package that was ignored (wrong architecture restriction
135  // or something).
136  if (rec.Package.empty())
137  {
138  // If we are in an OR group, we need to set the "Or" flag of the
139  // previous entry to our value.
140  if (BuildDeps.empty() == false && (BuildDeps[BuildDeps.size() - 1].Op & pkgCache::Dep::Or) == pkgCache::Dep::Or)
141  {
142  BuildDeps[BuildDeps.size() - 1].Op &= ~~pkgCache::Dep::Or;
143  BuildDeps[BuildDeps.size() - 1].Op |= (rec.Op & pkgCache::Dep::Or);
144  }
145  } else {
146  BuildDeps.emplace_back(std::move(rec));
147  }
148 
149  if (Start == Stop)
150  break;
151  }
152  }
153 
154  return true;
155 }
156  /*}}}*/
157 // SrcRecordParser::Files - Return a list of files for this source /*{{{*/
158 // ---------------------------------------------------------------------
159 /* This parses the list of files and returns it, each file is required to have
160  a complete source package */
161 bool debSrcRecordParser::Files(std::vector<pkgSrcRecords::File> &List)
162 {
163  List.clear();
164 
165  // Stash the / terminated directory prefix
166  std::string Base = Sect.Find(pkgTagSection::Key::Directory).to_string();
167  if (Base.empty() == false && Base[Base.length()-1] != '/')
168  Base += '/';
169 
170  std::vector<std::string> const compExts = APT::Configuration::getCompressorExtensions();
171 
172  for (char const * const * type = HashString::SupportedHashes(); *type != NULL; ++type)
173  {
174  // derive field from checksum type
175  std::string checksumField("Checksums-");
176  if (strcmp(*type, "MD5Sum") == 0)
177  checksumField = "Files"; // historic name for MD5 checksums
178  else
179  checksumField.append(*type);
180 
181  string const Files = Sect.FindS(checksumField.c_str());
182  if (Files.empty() == true)
183  continue;
184 
185  // Iterate over the entire list grabbing each triplet
186  const char *C = Files.c_str();
187  while (*C != 0)
188  {
189  string hash, size, path;
190 
191  // Parse each of the elements
192  if (ParseQuoteWord(C, hash) == false ||
193  ParseQuoteWord(C, size) == false ||
194  ParseQuoteWord(C, path) == false)
195  return _error->Error("Error parsing file record in %s of source package %s", checksumField.c_str(), Package().c_str());
196 
197  if (iIndex == nullptr && checksumField == "Files")
198  {
199  // the Files field has a different format than the rest in deb-changes files
200  std::string ignore;
201  if (ParseQuoteWord(C, ignore) == false ||
202  ParseQuoteWord(C, path) == false)
203  return _error->Error("Error parsing file record in %s of source package %s", checksumField.c_str(), Package().c_str());
204  }
205 
206  HashString const hashString(*type, hash);
207  if (Base.empty() == false)
208  path = Base + path;
209 
210  // look if we have a record for this file already
211  std::vector<pkgSrcRecords::File>::iterator file = List.begin();
212  for (; file != List.end(); ++file)
213  if (file->Path == path)
214  break;
215 
216  // we have it already, store the new hash and be done
217  if (file != List.end())
218  {
219  // an error here indicates that we have two different hashes for the same file
220  if (file->Hashes.push_back(hashString) == false)
221  return _error->Error("Error parsing checksum in %s of source package %s", checksumField.c_str(), Package().c_str());
222  continue;
223  }
224 
225  // we haven't seen this file yet
227  F.Path = path;
228  F.FileSize = strtoull(size.c_str(), NULL, 10);
229  F.Hashes.push_back(hashString);
230  F.Hashes.FileSize(F.FileSize);
231 
232  // Try to guess what sort of file it is we are getting.
233  string::size_type Pos = F.Path.length()-1;
234  while (1)
235  {
236  string::size_type Tmp = F.Path.rfind('.',Pos);
237  if (Tmp == string::npos)
238  break;
239  if (F.Type == "tar") {
240  // source v3 has extension 'debian.tar.*' instead of 'diff.*'
241  if (string(F.Path, Tmp+1, Pos-Tmp) == "debian")
242  F.Type = "diff";
243  break;
244  }
245  F.Type = string(F.Path,Tmp+1,Pos-Tmp);
246 
247  if (std::find(compExts.begin(), compExts.end(), std::string(".").append(F.Type)) != compExts.end() ||
248  F.Type == "tar")
249  {
250  Pos = Tmp-1;
251  continue;
252  }
253 
254  break;
255  }
256  List.push_back(F);
257  }
258  }
259 
260  return true;
261 }
262  /*}}}*/
263 // SrcRecordParser::~SrcRecordParser - Destructor /*{{{*/
264 // ---------------------------------------------------------------------
265 /* */
267 {
268  // was allocated via strndup()
269  free(Buffer);
270 }
271  /*}}}*/
272 
273 
275  : debSrcRecordParser("", Index)
276 {
277  // support clear signed files
278  if (OpenMaybeClearSignedFile(DscFile, Fd) == false)
279  {
280  _error->Error("Failed to open %s", DscFile.c_str());
281  return;
282  }
283 
284  // re-init to ensure the updated Fd is used
286  // read the first (and only) record
287  Step();
288 
289 }
static bool std::string const metaIndex const *const pkgAcqMetaClearSig *const pkgAcquire::Item *const I
bool OpenMaybeClearSignedFile(std::string const &ClearSignedFileName, FileFd &MessageFile)
open a file which might be clear-signed
Definition: gpgv.cc:538
@ Extension
Definition: fileutl.h:80
@ ReadOnly
Definition: fileutl.h:59
bool Open(std::string FileName, unsigned int const Mode, CompressMode Compress, unsigned long const AccessMode=0666)
Definition: fileutl.cc:2415
bool push_back(const HashString &hashString)
Definition: hashes.cc:232
unsigned long long FileSize() const
Definition: hashes.cc:210
static APT_PURE const char ** SupportedHashes()
Definition: hashes.cc:135
debDscRecordParser(std::string const &DscFile, pkgIndexFile const *Index)
bool ParseDepends(pkgCache::VerIterator &Ver, pkgTagSection::Key Key, unsigned int Type)
virtual std::string Package() const APT_OVERRIDE
virtual bool Step() APT_OVERRIDE
Definition: debsrcrecords.h:39
std::vector< const char * > StaticBinList
Definition: debsrcrecords.h:32
debSrcRecordParser(std::string const &File, pkgIndexFile const *Index)
virtual const char ** Binaries() APT_OVERRIDE
virtual bool BuildDepends(std::vector< BuildDepRec > &BuildDeps, bool const &ArchOnly, bool const &StripMultiArch=true) APT_OVERRIDE
pkgTagSection Sect
Definition: debsrcrecords.h:31
virtual bool Files(std::vector< pkgSrcRecords::File > &F) APT_OVERRIDE
virtual ~debSrcRecordParser()
const pkgIndexFile * iIndex
Definition: srcrecords.h:43
static const char * BuildDepType(unsigned char const &Type) APT_PURE
Definition: srcrecords.cc:136
void Init(FileFd *const F, pkgTagFile::Flags const Flags, unsigned long long Size=32 *1024)
Definition: tagfile.cc:127
@ SUPPORT_COMMENTS
Definition: tagfile.h:190
std::string FindS(APT::StringView sv) const
Definition: tagfile.h:70
APT_HIDDEN bool Find(Key key, const char *&Start, const char *&End) const
Definition: tagfile.cc:690
APT_PUBLIC std::vector< std::string > const getCompressorExtensions()
Return a vector of extensions supported for data.tar's.
std::string Path
Definition: srcrecords.h:31
std::string Type
Definition: srcrecords.h:32
unsigned long long FileSize
Definition: srcrecords.h:33
HashStringList Hashes
Definition: srcrecords.h:34
int isspace_ascii(int const c) APT_PURE APT_COLD
Definition: strutl.cc:1517
bool ParseQuoteWord(const char *&String, string &Res)
Definition: strutl.cc:288