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