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