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