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)  

deblistparser.cc
Go to the documentation of this file.
1 // -*- mode: cpp; mode: fold -*-
2 // Description /*{{{*/
3 /* ######################################################################
4 
5  Package Cache Generator - Generator for the cache structure.
6 
7  This builds the cache structure from the abstract package list parser.
8 
9  ##################################################################### */
10  /*}}}*/
11 // Include Files /*{{{*/
12 #include <config.h>
13 
14 #include <apt-pkg/algorithms.h>
16 #include <apt-pkg/cachefilter.h>
17 #include <apt-pkg/configuration.h>
18 #include <apt-pkg/deblistparser.h>
19 #include <apt-pkg/error.h>
20 #include <apt-pkg/hashes.h>
21 #include <apt-pkg/macros.h>
22 #include <apt-pkg/pkgcache.h>
23 #include <apt-pkg/strutl.h>
24 #include <apt-pkg/tagfile-keys.h>
25 #include <apt-pkg/tagfile.h>
26 
27 #include <algorithm>
28 #include <string>
29 #include <vector>
30 #include <ctype.h>
31 #include <stddef.h>
32 #include <string.h>
33  /*}}}*/
34 
35 using std::string;
36 using APT::StringView;
37 
39  {"required",pkgCache::State::Required},
40  {"important",pkgCache::State::Important},
41  {"standard",pkgCache::State::Standard},
42  {"optional",pkgCache::State::Optional},
43  {"extra",pkgCache::State::Extra},
44  {"", 0}};
45 
46 // ListParser::debListParser - Constructor /*{{{*/
47 // ---------------------------------------------------------------------
48 /* Provide an architecture and only this one and "all" will be accepted
49  in Step(), if no Architecture is given we will accept every arch
50  we would accept in general with checkArchitecture() */
52  pkgCacheListParser(), Tags(File)
53 {
54  // this dance allows an empty value to override the default
55  if (_config->Exists("pkgCacheGen::ForceEssential"))
56  {
57  forceEssential = _config->FindVector("pkgCacheGen::ForceEssential");
58  if (forceEssential.empty() == false && _config->Find("pkgCacheGen::ForceEssential").empty())
59  forceEssential.emplace_back("apt");
60  }
61  else
62  forceEssential.emplace_back("apt");
63  forceImportant = _config->FindVector("pkgCacheGen::ForceImportant");
64  myArch = _config->Find("APT::Architecture");
65 }
66  /*}}}*/
67 // ListParser::Package - Return the package name /*{{{*/
68 // ---------------------------------------------------------------------
69 /* This is to return the name of the package this section describes */
71  string Result = Section.Find(pkgTagSection::Key::Package).to_string();
72 
73  // Normalize mixed case package names to lower case, like dpkg does
74  // See Bug#807012 for details.
75  // Only do this when the package name does not contain a / - as that
76  // indicates that the package name was derived from a filename given
77  // to install or build-dep or similar (Bug#854794)
78  if (likely(Result.find('/') == string::npos))
79  {
80  for (char &c: Result)
81  {
82  char l = tolower_ascii_inline(c);
83  if (unlikely(l != c))
84  c = l;
85  }
86  }
87 
88  if(unlikely(Result.empty() == true))
89  _error->Error("Encountered a section with no Package: header");
90  return Result;
91 }
92  /*}}}*/
93 // ListParser::Architecture - Return the package arch /*{{{*/
94 // ---------------------------------------------------------------------
95 /* This will return the Architecture of the package this section describes */
97  auto const Arch = Section.Find(pkgTagSection::Key::Architecture);
98  return Arch.empty() ? "none" : Arch;
99 }
100  /*}}}*/
101 // ListParser::ArchitectureAll /*{{{*/
102 // ---------------------------------------------------------------------
103 /* */
105  return Section.Find(pkgTagSection::Key::Architecture) == "all";
106 }
107  /*}}}*/
108 // ListParser::Version - Return the version string /*{{{*/
109 // ---------------------------------------------------------------------
110 /* This is to return the string describing the version in debian form,
111  epoch:upstream-release. If this returns the blank string then the
112  entry is assumed to only describe package properties */
114 {
115  return Section.Find(pkgTagSection::Key::Version);
116 }
117  /*}}}*/
118 unsigned char debListParser::ParseMultiArch(bool const showErrors) /*{{{*/
119 {
120  unsigned char MA;
121  auto const MultiArch = Section.Find(pkgTagSection::Key::Multi_Arch);
122  if (MultiArch.empty() == true || MultiArch == "no")
124  else if (MultiArch == "same") {
125  if (ArchitectureAll() == true)
126  {
127  if (showErrors == true)
128  _error->Warning("Architecture: all package '%s' can't be Multi-Arch: same",
129  Section.FindS("Package").c_str());
131  }
132  else
134  }
135  else if (MultiArch == "foreign")
137  else if (MultiArch == "allowed")
139  else
140  {
141  if (showErrors == true)
142  _error->Warning("Unknown Multi-Arch type '%s' for package '%s'",
143  MultiArch.to_string().c_str(), Section.FindS("Package").c_str());
145  }
146 
147  if (ArchitectureAll() == true)
149 
150  return MA;
151 }
152  /*}}}*/
153 // ListParser::NewVersion - Fill in the version structure /*{{{*/
154 // ---------------------------------------------------------------------
155 /* */
157 {
158  const char *Start;
159  const char *Stop;
160 
161  // Parse the section
162  if (Section.Find(pkgTagSection::Key::Section,Start,Stop) == true)
163  {
164  map_stringitem_t const idx = StoreString(pkgCacheGenerator::SECTION, Start, Stop - Start);
165  Ver->Section = idx;
166  }
167  // Parse the source package name
168  pkgCache::GrpIterator G = Ver.ParentPkg().Group();
169 
170  // Setup the defaults
171  Ver->SourcePkgName = G->Name;
172  Ver->SourceVerStr = Ver->VerStr;
173 
174  // Parse the name and version str
175  if (Section.Find(pkgTagSection::Key::Source,Start,Stop) == true)
176  {
177  const char * const Space = static_cast<const char *>(memchr(Start, ' ', Stop - Start));
179 
180  if (Space != NULL)
181  {
182  const char * const Open = static_cast<const char *>(memchr(Space, '(', Stop - Space));
183  if (likely(Open != NULL))
184  {
185  const char * const Close = static_cast<const char *>(memchr(Open, ')', Stop - Open));
186  if (likely(Close != NULL))
187  {
188  APT::StringView const version(Open + 1, (Close - Open) - 1);
189  if (version != Ver.VerStr())
190  {
192  G = Ver.ParentPkg().Group();
193  Ver->SourceVerStr = idx;
194  }
195  }
196  }
197  Stop = Space;
198  }
199 
200  APT::StringView const pkgname(Start, Stop - Start);
201  // Oh, our group is the wrong one for the source package. Make a new one.
202  if (pkgname != G.Name())
203  {
204  if (not NewGroup(G, pkgname))
205  return false;
206  }
207  }
208 
209  // Link into by source package group.
210  Ver->SourcePkgName = G->Name;
211  Ver->NextInSource = G->VersionsInSource;
212  G->VersionsInSource = Ver.MapPointer();
213 
214  Ver->MultiArch = ParseMultiArch(true);
215  // Archive Size
216  Ver->Size = Section.FindULL(pkgTagSection::Key::Size);
217  // Unpacked Size (in K)
218  Ver->InstalledSize = Section.FindULL(pkgTagSection::Key::Installed_Size);
219  Ver->InstalledSize *= 1024;
220 
221  // Priority
222  if (Section.Find(pkgTagSection::Key::Priority,Start,Stop) == true)
223  {
224  if (GrabWord(StringView(Start,Stop-Start),PrioList,Ver->Priority) == false)
225  Ver->Priority = pkgCache::State::Extra;
226  }
227 
228  if (ParseDepends(Ver,pkgTagSection::Key::Pre_Depends,pkgCache::Dep::PreDepends) == false)
229  return false;
231  return false;
232  if (ParseDepends(Ver,pkgTagSection::Key::Conflicts,pkgCache::Dep::Conflicts) == false)
233  return false;
234  if (ParseDepends(Ver,pkgTagSection::Key::Breaks,pkgCache::Dep::DpkgBreaks) == false)
235  return false;
236  if (ParseDepends(Ver,pkgTagSection::Key::Recommends,pkgCache::Dep::Recommends) == false)
237  return false;
238  if (ParseDepends(Ver,pkgTagSection::Key::Suggests,pkgCache::Dep::Suggests) == false)
239  return false;
240  if (ParseDepends(Ver,pkgTagSection::Key::Replaces,pkgCache::Dep::Replaces) == false)
241  return false;
242  if (ParseDepends(Ver,pkgTagSection::Key::Enhances,pkgCache::Dep::Enhances) == false)
243  return false;
244  // Obsolete.
245  if (ParseDepends(Ver,pkgTagSection::Key::Optional,pkgCache::Dep::Suggests) == false)
246  return false;
247 
248  if (ParseProvides(Ver) == false)
249  return false;
250  if (not APT::KernelAutoRemoveHelper::getUname(Ver.ParentPkg().Name()).empty())
251  {
252  if (not NewProvides(Ver, "$kernel", "any", Ver.VerStr(), pkgCache::Flag::MultiArchImplicit))
253  return false;
254  }
255 
256  return true;
257 }
258  /*}}}*/
259 // ListParser::AvailableDescriptionLanguages /*{{{*/
261 {
262  std::vector<std::string> const understood = APT::Configuration::getLanguages(true);
263  std::vector<std::string> avail;
264  static constexpr int prefixLen = 12;
265  char buf[32] = "Description-";
266  if (Section.Exists("Description") == true)
267  avail.push_back("");
268  for (std::vector<std::string>::const_iterator lang = understood.begin(); lang != understood.end(); ++lang)
269  {
270  if (unlikely(lang->size() > sizeof(buf) - prefixLen)) {
271  _error->Warning("Ignoring translated description %s", lang->c_str());
272  continue;
273  }
274  memcpy(buf + prefixLen, lang->c_str(), lang->size());
275  if (Section.Exists(StringView(buf, prefixLen + lang->size())) == true)
276  avail.push_back(*lang);
277  }
278  return avail;
279 }
280  /*}}}*/
281 // ListParser::Description_md5 - Return the description_md5 MD5SumValue /*{{{*/
282 // ---------------------------------------------------------------------
283 /* This is to return the md5 string to allow the check if it is the right
284  description. If no Description-md5 is found in the section it will be
285  calculated.
286  */
288 {
289  StringView const value = Section.Find(pkgTagSection::Key::Description_md5);
290  if (unlikely(value.empty() == true))
291  {
292  StringView const desc = Section.Find(pkgTagSection::Key::Description);
293  if (desc == "\n")
294  return StringView();
295 
296  Hashes md5(Hashes::MD5SUM);
297  md5.Add(desc.data(), desc.size());
298  md5.Add("\n");
300  return StringView(MD5Buffer);
301  }
302  else if (likely(value.size() == 32))
303  {
304  return value;
305  }
306  _error->Error("Malformed Description-md5 line; doesn't have the required length (32 != %d) '%.*s'", (int)value.size(), (int)value.length(), value.data());
307  return StringView();
308 }
309  /*}}}*/
310 // ListParser::UsePackage - Update a package structure /*{{{*/
311 // ---------------------------------------------------------------------
312 /* This is called to update the package with any new information
313  that might be found in the section */
316 {
317  string const static myArch = _config->Find("APT::Architecture");
318  // Possible values are: "all", "native", "installed" and "none"
319  // The "installed" mode is handled by ParseStatus(), See #544481 and friends.
320  string const static essential = _config->Find("pkgCacheGen::Essential", "all");
321  if (essential == "all" ||
322  (essential == "native" && Pkg->Arch != 0 && myArch == Pkg.Arch()))
323  if (Section.FindFlag(pkgTagSection::Key::Essential,Pkg->Flags,pkgCache::Flag::Essential) == false)
324  return false;
325  if (Section.FindFlag(pkgTagSection::Key::Important,Pkg->Flags,pkgCache::Flag::Important) == false)
326  return false;
327  if (Section.FindFlag(pkgTagSection::Key::Protected, Pkg->Flags, pkgCache::Flag::Important) == false)
328  return false;
329 
330  if (std::find(forceEssential.begin(), forceEssential.end(), Pkg.Name()) != forceEssential.end())
331  {
332  if ((essential == "native" && Pkg->Arch != 0 && myArch == Pkg.Arch()) ||
333  essential == "all")
335  else
336  Pkg->Flags |= pkgCache::Flag::Important;
337  }
338  else if (std::find(forceImportant.begin(), forceImportant.end(), Pkg.Name()) != forceImportant.end())
339  Pkg->Flags |= pkgCache::Flag::Important;
340 
341  auto phased = Section.FindULL(pkgTagSection::Key::Phased_Update_Percentage, 100);
342  if (phased != 100)
343  {
344  if (not Ver.PhasedUpdatePercentage(phased))
345  _error->Warning("Ignoring invalid Phased-Update-Percentage value");
346  }
347 
348  if (ParseStatus(Pkg,Ver) == false)
349  return false;
350  return true;
351 }
352  /*}}}*/
353 // ListParser::VersionHash - Compute a unique hash for this version /*{{{*/
354 // ---------------------------------------------------------------------
355 /* */
357 {
358  static constexpr pkgTagSection::Key Sections[] ={
359  pkgTagSection::Key::Installed_Size,
361  pkgTagSection::Key::Pre_Depends,
362 // pkgTagSection::Key::Suggests,
363 // pkgTagSection::Key::Recommends",
364  pkgTagSection::Key::Conflicts,
365  pkgTagSection::Key::Breaks,
366  pkgTagSection::Key::Replaces};
367  unsigned long Result = 5381;
368  for (auto I : Sections)
369  {
370  const char *Start;
371  const char *End;
372  if (Section.Find(I,Start,End) == false)
373  continue;
374 
375  /* Strip out any spaces from the text, this undoes dpkgs reformatting
376  of certain fields. dpkg also has the rather interesting notion of
377  reformatting depends operators < -> <=, so we drop all = from the
378  string to make that not matter. */
379  for (; Start != End; ++Start)
380  {
381  // Strip away 0: epochs from input
382  if (*Start == '0' && Start[1] == ':') {
383  Start++; // Skip the :
384  continue; // Skip the 0
385  }
386  if (isspace_ascii(*Start) != 0 || *Start == '=')
387  continue;
388  Result = 33 * Result + tolower_ascii_unsafe(*Start);
389  }
390 
391 
392  }
393 
394  return Result;
395 }
396  /*}}}*/
397 // StatusListParser::ParseStatus - Parse the status field /*{{{*/
398 // ---------------------------------------------------------------------
399 /* Status lines are of the form,
400  Status: want flag status
401  want = unknown, install, hold, deinstall, purge
402  flag = ok, reinstreq
403  status = not-installed, config-files, half-installed, unpacked,
404  half-configured, triggers-awaited, triggers-pending, installed
405  */
408 {
409  return true;
410 }
413 {
414  const char *Start;
415  const char *Stop;
416  if (Section.Find(pkgTagSection::Key::Status,Start,Stop) == false)
417  return true;
418 
419  // UsePackage() is responsible for setting the flag in the default case
420  bool const static essential = _config->Find("pkgCacheGen::Essential", "") == "installed";
421  if (essential == true &&
422  Section.FindFlag(pkgTagSection::Key::Essential,Pkg->Flags,pkgCache::Flag::Essential) == false)
423  return false;
424 
425  // Isolate the first word
426  const char *I = Start;
427  for(; I < Stop && *I != ' '; I++);
428  if (I >= Stop || *I != ' ')
429  return _error->Error("Malformed Status line");
430 
431  // Process the want field
432  WordList WantList[] = {{"unknown",pkgCache::State::Unknown},
433  {"install",pkgCache::State::Install},
434  {"hold",pkgCache::State::Hold},
435  {"deinstall",pkgCache::State::DeInstall},
436  {"purge",pkgCache::State::Purge},
437  {"", 0}};
438  if (GrabWord(StringView(Start,I-Start),WantList,Pkg->SelectedState) == false)
439  return _error->Error("Malformed 1st word in the Status line");
440 
441  // Isloate the next word
442  I++;
443  Start = I;
444  for(; I < Stop && *I != ' '; I++);
445  if (I >= Stop || *I != ' ')
446  return _error->Error("Malformed status line, no 2nd word");
447 
448  // Process the flag field
449  WordList FlagList[] = {{"ok",pkgCache::State::Ok},
450  {"reinstreq",pkgCache::State::ReInstReq},
451  {"hold",pkgCache::State::HoldInst},
452  {"hold-reinstreq",pkgCache::State::HoldReInstReq},
453  {"", 0}};
454  if (GrabWord(StringView(Start,I-Start),FlagList,Pkg->InstState) == false)
455  return _error->Error("Malformed 2nd word in the Status line");
456 
457  // Isloate the last word
458  I++;
459  Start = I;
460  for(; I < Stop && *I != ' '; I++);
461  if (I != Stop)
462  return _error->Error("Malformed Status line, no 3rd word");
463 
464  // Process the flag field
465  WordList StatusList[] = {{"not-installed",pkgCache::State::NotInstalled},
466  {"config-files",pkgCache::State::ConfigFiles},
467  {"half-installed",pkgCache::State::HalfInstalled},
468  {"unpacked",pkgCache::State::UnPacked},
469  {"half-configured",pkgCache::State::HalfConfigured},
470  {"triggers-awaited",pkgCache::State::TriggersAwaited},
471  {"triggers-pending",pkgCache::State::TriggersPending},
472  {"installed",pkgCache::State::Installed},
473  {"", 0}};
474  if (GrabWord(StringView(Start,I-Start),StatusList,Pkg->CurrentState) == false)
475  return _error->Error("Malformed 3rd word in the Status line");
476 
477  /* A Status line marks the package as indicating the current
478  version as well. Only if it is actually installed.. Otherwise
479  the interesting dpkg handling of the status file creates bogus
480  entries. */
481  if (!(Pkg->CurrentState == pkgCache::State::NotInstalled ||
482  Pkg->CurrentState == pkgCache::State::ConfigFiles))
483  {
484  if (Ver.end() == true)
485  _error->Warning("Encountered status field in a non-version description");
486  else
487  Pkg->CurrentVer = Ver.MapPointer();
488  }
489 
490  return true;
491 }
492 
493 const char *debListParser::ConvertRelation(const char *I,unsigned int &Op)
494 {
495  // Determine the operator
496  switch (*I)
497  {
498  case '<':
499  I++;
500  if (*I == '=')
501  {
502  I++;
504  break;
505  }
506 
507  if (*I == '<')
508  {
509  I++;
510  Op = pkgCache::Dep::Less;
511  break;
512  }
513 
514  // < is the same as <= and << is really Cs < for some reason
516  break;
517 
518  case '>':
519  I++;
520  if (*I == '=')
521  {
522  I++;
524  break;
525  }
526 
527  if (*I == '>')
528  {
529  I++;
531  break;
532  }
533 
534  // > is the same as >= and >> is really Cs > for some reason
536  break;
537 
538  case '=':
540  I++;
541  break;
542 
543  // HACK around bad package definitions
544  default:
546  break;
547  }
548  return I;
549 }
550  /*}}}*/
551 // ListParser::ParseDepends - Parse a dependency element /*{{{*/
552 // ---------------------------------------------------------------------
553 /* This parses the dependency elements out of a standard string in place,
554  bit by bit. */
555 const char *debListParser::ParseDepends(const char *Start,const char *Stop,
556  string &Package,string &Ver,
557  unsigned int &Op, bool const &ParseArchFlags,
558  bool const &StripMultiArch,
559  bool const &ParseRestrictionsList,
560  string const &Arch)
561 {
562  StringView PackageView;
563  StringView VerView;
564 
565  auto res = ParseDepends(Start, Stop, PackageView, VerView, Op, (bool)ParseArchFlags,
566  (bool) StripMultiArch, (bool) ParseRestrictionsList, Arch);
567  Package = PackageView.to_string();
568  Ver = VerView.to_string();
569 
570  return res;
571 }
572 
573 const char *debListParser::ParseDepends(const char *Start, const char *Stop,
574  StringView &Package, StringView &Ver,
575  unsigned int &Op, bool ParseArchFlags,
576  bool StripMultiArch,
577  bool ParseRestrictionsList, string Arch)
578 {
579  if (Arch.empty())
580  Arch = _config->Find("APT::Architecture");
581  // Strip off leading space
582  for (;Start != Stop && isspace_ascii(*Start) != 0; ++Start);
583 
584  // Parse off the package name
585  const char *I = Start;
586  for (;I != Stop && isspace_ascii(*I) == 0 && *I != '(' && *I != ')' &&
587  *I != ',' && *I != '|' && *I != '[' && *I != ']' &&
588  *I != '<' && *I != '>'; ++I);
589 
590  // Malformed, no '('
591  if (I != Stop && *I == ')')
592  return 0;
593 
594  if (I == Start)
595  return 0;
596 
597  // Stash the package name
598  Package = StringView(Start, I - Start);
599 
600  // We don't want to confuse library users which can't handle MultiArch
601  if (StripMultiArch == true) {
602  size_t const found = Package.rfind(':');
603  if (found != StringView::npos &&
604  (Package.substr(found) == ":any" ||
605  Package.substr(found) == ":native" ||
606  Package.substr(found +1) == Arch))
607  Package = Package.substr(0,found);
608  }
609 
610  // Skip white space to the '('
611  for (;I != Stop && isspace_ascii(*I) != 0 ; I++);
612 
613  // Parse a version
614  if (I != Stop && *I == '(')
615  {
616  // Skip the '('
617  for (I++; I != Stop && isspace_ascii(*I) != 0 ; I++);
618  if (I + 3 >= Stop)
619  return 0;
620  I = ConvertRelation(I,Op);
621 
622  // Skip whitespace
623  for (;I != Stop && isspace_ascii(*I) != 0; I++);
624  Start = I;
625  I = (const char*) memchr(I, ')', Stop - I);
626  if (I == NULL || Start == I)
627  return 0;
628 
629  // Skip trailing whitespace
630  const char *End = I;
631  for (; End > Start && isspace_ascii(End[-1]); End--);
632 
633  Ver = StringView(Start,End-Start);
634  I++;
635  }
636  else
637  {
638  Ver = StringView();
639  Op = pkgCache::Dep::NoOp;
640  }
641 
642  // Skip whitespace
643  for (;I != Stop && isspace_ascii(*I) != 0; I++);
644 
645  if (unlikely(ParseArchFlags == true))
646  {
648 
649  // Parse an architecture
650  if (I != Stop && *I == '[')
651  {
652  ++I;
653  // malformed
654  if (unlikely(I == Stop))
655  return 0;
656 
657  const char *End = I;
658  bool Found = false;
659  bool NegArch = false;
660  while (I != Stop)
661  {
662  // look for whitespace or ending ']'
663  for (;End != Stop && !isspace_ascii(*End) && *End != ']'; ++End);
664 
665  if (unlikely(End == Stop))
666  return 0;
667 
668  if (*I == '!')
669  {
670  NegArch = true;
671  ++I;
672  }
673 
674  std::string const arch(I, End);
675  if (arch.empty() == false && matchesArch(arch.c_str()) == true)
676  {
677  Found = true;
678  if (I[-1] != '!')
679  NegArch = false;
680  // we found a match, so fast-forward to the end of the wildcards
681  for (; End != Stop && *End != ']'; ++End);
682  }
683 
684  if (*End++ == ']') {
685  I = End;
686  break;
687  }
688 
689  I = End;
690  for (;I != Stop && isspace_ascii(*I) != 0; I++);
691  }
692 
693  if (NegArch == true)
694  Found = !Found;
695 
696  if (Found == false)
697  Package = ""; /* not for this arch */
698  }
699 
700  // Skip whitespace
701  for (;I != Stop && isspace_ascii(*I) != 0; I++);
702  }
703 
704  if (unlikely(ParseRestrictionsList == true))
705  {
706  // Parse a restrictions formula which is in disjunctive normal form:
707  // (foo AND bar) OR (blub AND bla)
708 
709  std::vector<string> const profiles = APT::Configuration::getBuildProfiles();
710 
711  // if the next character is a restriction list, then by default the
712  // dependency does not apply and the conditions have to be checked
713  // if the next character is not a restriction list, then by default the
714  // dependency applies
715  bool applies1 = (*I != '<');
716  while (I != Stop)
717  {
718  if (*I != '<')
719  break;
720 
721  ++I;
722  // malformed
723  if (unlikely(I == Stop))
724  return 0;
725 
726  const char *End = I;
727 
728  // if of the prior restriction list is already fulfilled, then
729  // we can just skip to the end of the current list
730  if (applies1) {
731  for (;End != Stop && *End != '>'; ++End);
732  I = ++End;
733  // skip whitespace
734  for (;I != Stop && isspace_ascii(*I) != 0; I++);
735  } else {
736  bool applies2 = true;
737  // all the conditions inside a restriction list have to be
738  // met so once we find one that is not met, we can skip to
739  // the end of this list
740  while (I != Stop)
741  {
742  // look for whitespace or ending '>'
743  // End now points to the character after the current term
744  for (;End != Stop && !isspace_ascii(*End) && *End != '>'; ++End);
745 
746  if (unlikely(End == Stop))
747  return 0;
748 
749  bool NegRestriction = false;
750  if (*I == '!')
751  {
752  NegRestriction = true;
753  ++I;
754  }
755 
756  std::string const restriction(I, End);
757  if (restriction.empty() == false && profiles.empty() == false &&
758  std::find(profiles.begin(), profiles.end(), restriction) != profiles.end())
759  {
760  if (NegRestriction) {
761  applies2 = false;
762  // since one of the terms does not apply we don't have to check the others
763  for (; End != Stop && *End != '>'; ++End);
764  }
765  } else {
766  if (!NegRestriction) {
767  applies2 = false;
768  // since one of the terms does not apply we don't have to check the others
769  for (; End != Stop && *End != '>'; ++End);
770  }
771  }
772 
773  if (*End++ == '>') {
774  I = End;
775  // skip whitespace
776  for (;I != Stop && isspace_ascii(*I) != 0; I++);
777  break;
778  }
779 
780  I = End;
781  // skip whitespace
782  for (;I != Stop && isspace_ascii(*I) != 0; I++);
783  }
784  if (applies2) {
785  applies1 = true;
786  }
787  }
788  }
789 
790  if (applies1 == false) {
791  Package = ""; //not for this restriction
792  }
793  }
794 
795  if (I != Stop && *I == '|')
796  Op |= pkgCache::Dep::Or;
797 
798  if (I == Stop || *I == ',' || *I == '|')
799  {
800  if (I != Stop)
801  for (I++; I != Stop && isspace_ascii(*I) != 0; I++);
802  return I;
803  }
804 
805  return 0;
806 }
807  /*}}}*/
808 // ListParser::ParseDepends - Parse a dependency list /*{{{*/
809 // ---------------------------------------------------------------------
810 /* This is the higher level depends parser. It takes a tag and generates
811  a complete depends tree for the given version. */
813  pkgTagSection::Key Key,unsigned int Type)
814 {
815  const char *Start;
816  const char *Stop;
817  if (Section.Find(Key,Start,Stop) == false || Start == Stop)
818  return true;
819 
820  string const pkgArch = Ver.Arch();
821 
822  while (1)
823  {
826  unsigned int Op;
827 
828  Start = ParseDepends(Start, Stop, Package, Version, Op, false, false, false, myArch);
829  if (Start == 0)
830  return _error->Error("Problem parsing dependency %zu of %s:%s=%s", static_cast<size_t>(Key), // TODO
831  Ver.ParentPkg().Name(), Ver.Arch(), Ver.VerStr());
832  size_t const found = Package.rfind(':');
833 
834  if (found == string::npos)
835  {
836  if (NewDepends(Ver,Package,pkgArch,Version,Op,Type) == false)
837  return false;
838  }
839  else if (Package.substr(found) == ":any")
840  {
841  if (NewDepends(Ver,Package,"any",Version,Op,Type) == false)
842  return false;
843  }
844  else
845  {
846  // Such dependencies are not supposed to be accepted …
847  // … but this is probably the best thing to do anyway
848  if (Package.substr(found + 1) == "native")
849  {
850  std::string const Pkg = Package.substr(0, found).to_string() + ':' + Ver.Cache()->NativeArch();
851  if (NewDepends(Ver, Pkg, "any", Version, Op | pkgCache::Dep::ArchSpecific, Type) == false)
852  return false;
853  }
854  else if (NewDepends(Ver, Package, "any", Version, Op | pkgCache::Dep::ArchSpecific, Type) == false)
855  return false;
856  }
857 
858  if (Start == Stop)
859  break;
860  }
861  return true;
862 }
863  /*}}}*/
864 // ListParser::ParseProvides - Parse the provides list /*{{{*/
865 // ---------------------------------------------------------------------
866 /* */
868 {
869  /* it is unlikely, but while parsing dependencies, we might have already
870  picked up multi-arch implicit provides which we do not want to duplicate here */
871  bool hasProvidesAlready = false;
872  std::string const spzName = Ver.ParentPkg().FullName(false);
873  {
874  for (pkgCache::PrvIterator Prv = Ver.ProvidesList(); Prv.end() == false; ++Prv)
875  {
876  if (Prv.IsMultiArchImplicit() == false || (Prv->Flags & pkgCache::Flag::ArchSpecific) == 0)
877  continue;
878  if (spzName != Prv.OwnerPkg().FullName(false))
879  continue;
880  hasProvidesAlready = true;
881  break;
882  }
883  }
884 
885  string const Arch = Ver.Arch();
886  const char *Start;
887  const char *Stop;
888  if (Section.Find(pkgTagSection::Key::Provides,Start,Stop) == true)
889  {
892  unsigned int Op;
893 
894  do
895  {
896  Start = ParseDepends(Start,Stop,Package,Version,Op, false, false, false);
897  const size_t archfound = Package.rfind(':');
898  if (Start == 0)
899  return _error->Error("Problem parsing Provides line of %s:%s=%s", Ver.ParentPkg().Name(), Ver.Arch(), Ver.VerStr());
900  if (unlikely(Op != pkgCache::Dep::NoOp && Op != pkgCache::Dep::Equals)) {
901  _error->Warning("Ignoring non-equal Provides for package %s in %s:%s=%s", Package.to_string().c_str(), Ver.ParentPkg().Name(), Ver.Arch(), Ver.VerStr());
902  } else if (archfound != string::npos) {
903  StringView spzArch = Package.substr(archfound + 1);
904  if (spzArch != "any")
905  {
906  if (NewProvides(Ver, Package.substr(0, archfound), spzArch, Version, pkgCache::Flag::MultiArchImplicit | pkgCache::Flag::ArchSpecific) == false)
907  return false;
908  }
909  if (NewProvides(Ver, Package, "any", Version, pkgCache::Flag::ArchSpecific) == false)
910  return false;
911  } else if ((Ver->MultiArch & pkgCache::Version::Foreign) == pkgCache::Version::Foreign) {
913  {
914  if (NewProvidesAllArch(Ver, Package, Version, 0) == false)
915  return false;
916  }
917  else if (NewProvides(Ver, Package, Arch, Version, 0) == false)
918  return false;
919  } else {
920  if ((Ver->MultiArch & pkgCache::Version::Allowed) == pkgCache::Version::Allowed)
921  {
922  if (NewProvides(Ver, Package.to_string().append(":any"), "any", Version, pkgCache::Flag::MultiArchImplicit) == false)
923  return false;
924  }
925  if (NewProvides(Ver, Package, Arch, Version, 0) == false)
926  return false;
927  }
928  if (archfound == std::string::npos)
929  {
930  string spzName = Package.to_string();
931  spzName.push_back(':');
932  spzName.append(Ver.ParentPkg().Arch());
933  pkgCache::PkgIterator const spzPkg = Ver.Cache()->FindPkg(spzName, "any");
934  if (spzPkg.end() == false)
935  {
937  return false;
938  }
939  }
940  } while (Start != Stop);
941  }
942 
944  {
945  if ((Ver->MultiArch & pkgCache::Version::Allowed) == pkgCache::Version::Allowed)
946  {
947  string const Package = string(Ver.ParentPkg().Name()).append(":").append("any");
948  if (NewProvides(Ver, Package, "any", Ver.VerStr(), pkgCache::Flag::MultiArchImplicit) == false)
949  return false;
950  }
951  else if ((Ver->MultiArch & pkgCache::Version::Foreign) == pkgCache::Version::Foreign)
952  {
953  if (NewProvidesAllArch(Ver, Ver.ParentPkg().Name(), Ver.VerStr(), pkgCache::Flag::MultiArchImplicit) == false)
954  return false;
955  }
956  }
957 
958  if (hasProvidesAlready == false)
959  {
960  pkgCache::PkgIterator const spzPkg = Ver.Cache()->FindPkg(spzName, "any");
961  if (spzPkg.end() == false)
962  {
963  if (NewProvides(Ver, spzName, "any", Ver.VerStr(), pkgCache::Flag::MultiArchImplicit | pkgCache::Flag::ArchSpecific) == false)
964  return false;
965  }
966  }
967  return true;
968 }
969  /*}}}*/
970 // ListParser::GrabWord - Matches a word and returns /*{{{*/
971 // ---------------------------------------------------------------------
972 /* Looks for a word in a list of words - for ParseStatus */
973 bool debListParser::GrabWord(StringView Word, WordList const *List, unsigned char &Out)
974 {
975  for (unsigned int C = 0; List[C].Str.empty() == false; C++)
976  {
977  if (Word.length() == List[C].Str.length() &&
978  strncasecmp(Word.data(), List[C].Str.data(), Word.length()) == 0)
979  {
980  Out = List[C].Val;
981  return true;
982  }
983  }
984  return false;
985 }
986  /*}}}*/
987 // ListParser::Step - Move to the next section in the file /*{{{*/
988 // ---------------------------------------------------------------------
989 /* This has to be careful to only process the correct architecture */
991 {
992  iOffset = Tags.Offset();
993  return Tags.Step(Section);
994 }
995  /*}}}*/
996 // ListParser::GetPrio - Convert the priority from a string /*{{{*/
997 // ---------------------------------------------------------------------
998 /* */
999 unsigned char debListParser::GetPrio(string Str)
1000 {
1001  unsigned char Out;
1002  if (GrabWord(Str,PrioList,Out) == false)
1003  Out = pkgCache::State::Extra;
1004 
1005  return Out;
1006 }
1007  /*}}}*/
1008 bool debListParser::SameVersion(uint32_t Hash, /*{{{*/
1009  pkgCache::VerIterator const &Ver)
1010 {
1011  if (pkgCacheListParser::SameVersion(Hash, Ver) == false)
1012  return false;
1013  // status file has no (Download)Size, but all others are fair game
1014  // status file is parsed last, so the first version we encounter is
1015  // probably also the version we have downloaded
1016  unsigned long long const Size = Section.FindULL(pkgTagSection::Key::Size);
1017  if (Size != 0 && Ver->Size != 0 && Size != Ver->Size)
1018  return false;
1019  // available everywhere, but easier to check here than to include in VersionHash
1020  unsigned char MultiArch = ParseMultiArch(false);
1021  if (MultiArch != Ver->MultiArch)
1022  return false;
1023  // for all practical proposes (we can check): same version
1024  return true;
1025 }
1026  /*}}}*/
1027 
1029  : debListParser(File), DebFile(DebFile)
1030 {
1031 }
1032 
1034  pkgCache::VerIterator &Ver)
1035 {
1036  if (not debListParser::UsePackage(Pkg, Ver))
1037  return false;
1038  // we use the full file path as a provides so that the file is found by its name
1039  // using the MultiArchImplicit flag for this is a bit of a stretch
1040  return NewProvides(Ver, DebFile, Pkg.Cache()->NativeArch(), Ver.VerStr(), pkgCache::Flag::MultiArchImplicit | pkgCache::Flag::ArchSpecific);
1041 }
1042 
static bool std::string const metaIndex const *const pkgAcqMetaClearSig *const pkgAcquire::Item *const I
I Status
Simple subset of std::string_view from C++17.
Definition: string_view.h:27
constexpr size_t length() const
Definition: string_view.h:138
constexpr const char * data() const
Definition: string_view.h:133
std::string to_string() const
Definition: string_view.h:106
constexpr size_t size() const
Definition: string_view.h:137
constexpr bool empty() const
Definition: string_view.h:132
bool Exists(const std::string &Name) const
Definition: configuration.h:98
std::vector< std::string > FindVector(const char *Name, std::string const &Default="", bool const Keys=false) const
std::string Find(const char *Name, const char *Default=0) const
static pkgCache * Cache
Definition: fileutl.h:39
std::string HashValue() const
Definition: hashes.h:44
Definition: hashes.h:170
@ MD5SUM
Definition: hashes.h:185
HashString GetHashString(SupportedHashes hash)
Definition: hashes.cc:442
bool Add(const unsigned char *const Data, unsigned long long const Size) APT_NONNULL(2)
Definition: hashes.cc:353
debDebFileParser(FileFd *File, std::string const &DebFile)
virtual bool UsePackage(pkgCache::PkgIterator &Pkg, pkgCache::VerIterator &Ver) APT_OVERRIDE
virtual bool ParseStatus(pkgCache::PkgIterator &Pkg, pkgCache::VerIterator &Ver)
virtual bool SameVersion(uint32_t Hash, pkgCache::VerIterator const &Ver) APT_OVERRIDE
static APT_PUBLIC unsigned char GetPrio(std::string Str)
virtual APT::StringView Architecture() APT_OVERRIDE
pkgTagSection Section
Definition: deblistparser.h:44
bool ParseProvides(pkgCache::VerIterator &Ver)
virtual bool NewVersion(pkgCache::VerIterator &Ver) APT_OVERRIDE
static APT_HIDDEN bool GrabWord(APT::StringView Word, const WordList *List, unsigned char &Out)
debListParser(FileFd *File)
virtual std::string Package() APT_OVERRIDE
pkgTagFile Tags
Definition: deblistparser.h:43
APT_HIDDEN unsigned char ParseMultiArch(bool const showErrors)
std::vector< std::string > forceEssential
Definition: deblistparser.h:37
bool ParseDepends(pkgCache::VerIterator &Ver, pkgTagSection::Key Key, unsigned int Type)
virtual std::vector< std::string > AvailableDescriptionLanguages() APT_OVERRIDE
std::string myArch
Definition: deblistparser.h:40
virtual APT::StringView Version() APT_OVERRIDE
virtual ~debListParser()
std::vector< std::string > forceImportant
Definition: deblistparser.h:38
virtual bool UsePackage(pkgCache::PkgIterator &Pkg, pkgCache::VerIterator &Ver) APT_OVERRIDE
virtual bool Step() APT_OVERRIDE
map_filesize_t iOffset
Definition: deblistparser.h:45
virtual bool ArchitectureAll() APT_OVERRIDE
virtual uint32_t VersionHash() APT_OVERRIDE
virtual APT::StringView Description_md5() APT_OVERRIDE
virtual map_filesize_t Size() APT_OVERRIDE
Definition: deblistparser.h:72
static APT_PUBLIC const char * ConvertRelation(const char *I, unsigned int &Op)
std::string MD5Buffer
Definition: deblistparser.h:39
virtual bool ParseStatus(pkgCache::PkgIterator &Pkg, pkgCache::VerIterator &Ver) APT_OVERRIDE
virtual bool SameVersion(uint32_t Hash, pkgCache::VerIterator const &Ver)
map_stringitem_t StoreString(pkgCacheGenerator::StringType const type, const char *S, unsigned int Size)
Definition: pkgcachegen.h:184
bool NewGroup(pkgCache::GrpIterator &Grp, APT::StringView Name)
Definition: pkgcachegen.h:183
bool NewDepends(pkgCache::VerIterator &Ver, APT::StringView Package, APT::StringView Arch, APT::StringView Version, uint8_t const Op, uint8_t const Type)
bool NewProvidesAllArch(pkgCache::VerIterator &Ver, APT::StringView Package, APT::StringView Version, uint8_t const Flags)
bool NewProvides(pkgCache::VerIterator &Ver, APT::StringView PkgName, APT::StringView PkgArch, APT::StringView Version, uint8_t const Flags)
bool Step(pkgTagSection &Section)
Definition: tagfile.cc:204
unsigned long Offset()
Definition: tagfile.cc:163
std::string FindS(APT::StringView sv) const
Definition: tagfile.h:70
APT_HIDDEN bool Exists(Key key) const
APT_HIDDEN bool Find(Key key, const char *&Start, const char *&End) const
Definition: tagfile.cc:690
APT_HIDDEN bool FindFlag(Key key, uint8_t &Flags, uint8_t const Flag) const
Definition: tagfile.cc:858
APT_HIDDEN unsigned long long FindULL(Key key, unsigned long long const &Default=0) const
Definition: tagfile.cc:812
Configuration * _config
static const debListParser::WordList PrioList[]
APT_PUBLIC bool checkArchitecture(std::string const &Arch)
Are we interested in the given Architecture?
APT_PUBLIC std::vector< std::string > const getLanguages(bool const &All=false, bool const &Cached=true, char const **const Locale=0)
Returns a vector of Language Codes.
APT_PUBLIC std::vector< std::string > const getBuildProfiles()
std::string getUname(std::string const &packageName)
Definition: algorithms.cc:1464
pkgCache - Structure definitions for the cache file
bool Depends(CommandLine &CmdL)
APT::StringView Str
Definition: deblistparser.h:32
int isspace_ascii(int const c) APT_PURE APT_COLD
Definition: strutl.cc:1517
static int tolower_ascii_inline(int const c)
Definition: strutl.h:137
static int tolower_ascii_unsafe(int const c)
Definition: strutl.h:132