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