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