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