]> git.saurik.com Git - apt.git/blob - apt-pkg/deb/deblistparser.cc
Avoid wedging the entire system if recoverable :/.
[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 if (Section.Find("Name",Start,Stop) == true)
152 {
153 Ver->Display = WriteString(Start, Stop - Start);
154 }
155 else if (Section.Find("Maemo-Display-Name",Start,Stop) == true)
156 {
157 Ver->Display = WriteString(Start, Stop - Start);
158 }
159
160 // Parse the section
161 if (Section.Find(pkgTagSection::Key::Section,Start,Stop) == true)
162 {
163 map_stringitem_t const idx = StoreString(pkgCacheGenerator::SECTION, Start, Stop - Start);
164 Ver->Section = idx;
165 }
166 // Parse the source package name
167 pkgCache::GrpIterator G = Ver.ParentPkg().Group();
168 Ver->SourcePkgName = G->Name;
169 Ver->SourceVerStr = Ver->VerStr;
170 if (Section.Find(pkgTagSection::Key::Source,Start,Stop) == true)
171 {
172 const char * const Space = (const char * const) memchr(Start, ' ', Stop - Start);
173 pkgCache::VerIterator V;
174
175 if (Space != NULL)
176 {
177 const char * const Open = (const char * const) memchr(Space, '(', Stop - Space);
178 if (likely(Open != NULL))
179 {
180 const char * const Close = (const char * const) memchr(Open, ')', Stop - Open);
181 if (likely(Close != NULL))
182 {
183 APT::StringView const version(Open + 1, (Close - Open) - 1);
184 if (version != Ver.VerStr())
185 {
186 map_stringitem_t const idx = StoreString(pkgCacheGenerator::VERSIONNUMBER, version);
187 G = Ver.ParentPkg().Group();
188 Ver->SourceVerStr = idx;
189 }
190 }
191 }
192 Stop = Space;
193 }
194
195 APT::StringView const pkgname(Start, Stop - Start);
196 if (pkgname != G.Name())
197 {
198 for (pkgCache::PkgIterator P = G.PackageList(); P.end() == false; P = G.NextPkg(P))
199 {
200 for (V = P.VersionList(); V.end() == false; ++V)
201 {
202 if (pkgname == V.SourcePkgName())
203 {
204 Ver->SourcePkgName = V->SourcePkgName;
205 break;
206 }
207 }
208 if (V.end() == false)
209 break;
210 }
211 if (V.end() == true)
212 {
213 map_stringitem_t const idx = StoreString(pkgCacheGenerator::PKGNAME, pkgname);
214 G = Ver.ParentPkg().Group();
215 Ver->SourcePkgName = idx;
216 }
217 }
218 }
219
220 Ver->MultiArch = ParseMultiArch(true);
221 // Archive Size
222 Ver->Size = Section.FindULL(pkgTagSection::Key::Size);
223 // Unpacked Size (in K)
224 Ver->InstalledSize = Section.FindULL(pkgTagSection::Key::Installed_Size);
225 Ver->InstalledSize *= 1024;
226
227 // Priority
228 if (Section.Find(pkgTagSection::Key::Priority,Start,Stop) == true)
229 {
230 if (GrabWord(StringView(Start,Stop-Start),PrioList,Ver->Priority) == false)
231 Ver->Priority = pkgCache::State::Extra;
232 }
233
234 if (ParseDepends(Ver,pkgTagSection::Key::Pre_Depends,pkgCache::Dep::PreDepends) == false)
235 return false;
236 if (ParseDepends(Ver,pkgTagSection::Key::Depends,pkgCache::Dep::Depends) == false)
237 return false;
238 if (ParseDepends(Ver,pkgTagSection::Key::Conflicts,pkgCache::Dep::Conflicts) == false)
239 return false;
240 if (ParseDepends(Ver,pkgTagSection::Key::Breaks,pkgCache::Dep::DpkgBreaks) == false)
241 return false;
242 if (ParseDepends(Ver,pkgTagSection::Key::Recommends,pkgCache::Dep::Recommends) == false)
243 return false;
244 if (ParseDepends(Ver,pkgTagSection::Key::Suggests,pkgCache::Dep::Suggests) == false)
245 return false;
246 if (ParseDepends(Ver,pkgTagSection::Key::Replaces,pkgCache::Dep::Replaces) == false)
247 return false;
248 if (ParseDepends(Ver,pkgTagSection::Key::Enhances,pkgCache::Dep::Enhances) == false)
249 return false;
250 // Obsolete.
251 if (ParseDepends(Ver,pkgTagSection::Key::Optional,pkgCache::Dep::Suggests) == false)
252 return false;
253
254 if (ParseProvides(Ver) == false)
255 return false;
256 if (ParseTag(Ver) == false)
257 return false;
258
259 return true;
260 }
261 /*}}}*/
262 // ListParser::AvailableDescriptionLanguages /*{{{*/
263 std::vector<std::string> debListParser::AvailableDescriptionLanguages()
264 {
265 std::vector<std::string> const understood = APT::Configuration::getLanguages();
266 std::vector<std::string> avail;
267 static constexpr int prefixLen = 12;
268 char buf[32] = "Description-";
269 if (Section.Exists("Description") == true)
270 avail.push_back("");
271 for (std::vector<std::string>::const_iterator lang = understood.begin(); lang != understood.end(); ++lang)
272 {
273 if (unlikely(lang->size() > sizeof(buf) - prefixLen)) {
274 _error->Warning("Ignoring translated description %s", lang->c_str());
275 continue;
276 }
277 memcpy(buf + prefixLen, lang->c_str(), lang->size());
278 if (Section.Exists(StringView(buf, prefixLen + lang->size())) == true)
279 avail.push_back(*lang);
280 }
281 return avail;
282 }
283 /*}}}*/
284 // ListParser::Description_md5 - Return the description_md5 MD5SumValue /*{{{*/
285 // ---------------------------------------------------------------------
286 /* This is to return the md5 string to allow the check if it is the right
287 description. If no Description-md5 is found in the section it will be
288 calculated.
289 */
290 APT::StringView debListParser::Description_md5()
291 {
292 StringView const value = Section.Find(pkgTagSection::Key::Description_md5);
293 if (unlikely(value.empty() == true))
294 {
295 StringView const desc = Section.Find(pkgTagSection::Key::Description);
296 if (desc == "\n")
297 return StringView();
298
299 MD5Summation md5;
300 md5.Add(desc.data(), desc.size());
301 md5.Add("\n");
302 MD5Buffer = md5.Result();
303 return StringView(MD5Buffer);
304 }
305 else if (likely(value.size() == 32))
306 {
307 return value;
308 }
309 _error->Error("Malformed Description-md5 line; doesn't have the required length (32 != %d) '%.*s'", (int)value.size(), (int)value.length(), value.data());
310 return StringView();
311 }
312 /*}}}*/
313 // ListParser::UsePackage - Update a package structure /*{{{*/
314 // ---------------------------------------------------------------------
315 /* This is called to update the package with any new information
316 that might be found in the section */
317 bool debListParser::UsePackage(pkgCache::PkgIterator &Pkg,
318 pkgCache::VerIterator &Ver)
319 {
320 string const static myArch = _config->Find("APT::Architecture");
321 // Possible values are: "all", "native", "installed" and "none"
322 // The "installed" mode is handled by ParseStatus(), See #544481 and friends.
323 string const static essential = _config->Find("pkgCacheGen::Essential", "all");
324 if (essential == "all" ||
325 (essential == "native" && Pkg->Arch != 0 && myArch == Pkg.Arch()))
326 if (Section.FindFlag(pkgTagSection::Key::Essential,Pkg->Flags,pkgCache::Flag::Essential) == false)
327 return false;
328 if (Section.FindFlag(pkgTagSection::Key::Important,Pkg->Flags,pkgCache::Flag::Important) == false)
329 return false;
330
331 if (std::find(forceEssential.begin(), forceEssential.end(), Pkg.Name()) != forceEssential.end())
332 {
333 if ((essential == "native" && Pkg->Arch != 0 && myArch == Pkg.Arch()) ||
334 essential == "all")
335 Pkg->Flags |= pkgCache::Flag::Essential | pkgCache::Flag::Important;
336 else
337 Pkg->Flags |= pkgCache::Flag::Important;
338 }
339 else if (std::find(forceImportant.begin(), forceImportant.end(), Pkg.Name()) != forceImportant.end())
340 Pkg->Flags |= pkgCache::Flag::Important;
341
342 if (ParseStatus(Pkg,Ver) == false)
343 return false;
344 return true;
345 }
346 /*}}}*/
347 // ListParser::VersionHash - Compute a unique hash for this version /*{{{*/
348 // ---------------------------------------------------------------------
349 /* */
350 unsigned short debListParser::VersionHash()
351 {
352 static constexpr pkgTagSection::Key Sections[] ={
353 pkgTagSection::Key::Installed_Size,
354 pkgTagSection::Key::Depends,
355 pkgTagSection::Key::Pre_Depends,
356 // pkgTagSection::Key::Suggests,
357 // pkgTagSection::Key::Recommends",
358 pkgTagSection::Key::Conflicts,
359 pkgTagSection::Key::Breaks,
360 pkgTagSection::Key::Replaces};
361 unsigned long Result = INIT_FCS;
362 for (auto I : Sections)
363 {
364 const char *Start;
365 const char *End;
366 if (Section.Find(I,Start,End) == false)
367 continue;
368
369 /* Strip out any spaces from the text, this undoes dpkgs reformatting
370 of certain fields. dpkg also has the rather interesting notion of
371 reformatting depends operators < -> <=, so we drop all = from the
372 string to make that not matter. */
373 for (; Start != End; ++Start)
374 {
375 if (isspace_ascii(*Start) != 0 || *Start == '=')
376 continue;
377 Result = AddCRC16Byte(Result, tolower_ascii_unsafe(*Start));
378 }
379
380
381 }
382
383 return Result;
384 }
385 /*}}}*/
386 // StatusListParser::ParseStatus - Parse the status field /*{{{*/
387 // ---------------------------------------------------------------------
388 /* Status lines are of the form,
389 Status: want flag status
390 want = unknown, install, hold, deinstall, purge
391 flag = ok, reinstreq
392 status = not-installed, config-files, half-installed, unpacked,
393 half-configured, triggers-awaited, triggers-pending, installed
394 */
395 bool debListParser::ParseStatus(pkgCache::PkgIterator &,
396 pkgCache::VerIterator &)
397 {
398 return true;
399 }
400 bool debStatusListParser::ParseStatus(pkgCache::PkgIterator &Pkg,
401 pkgCache::VerIterator &Ver)
402 {
403 const char *Start;
404 const char *Stop;
405 if (Section.Find(pkgTagSection::Key::Status,Start,Stop) == false)
406 return true;
407
408 // UsePackage() is responsible for setting the flag in the default case
409 bool const static essential = _config->Find("pkgCacheGen::Essential", "") == "installed";
410 if (essential == true &&
411 Section.FindFlag(pkgTagSection::Key::Essential,Pkg->Flags,pkgCache::Flag::Essential) == false)
412 return false;
413
414 // Isolate the first word
415 const char *I = Start;
416 for(; I < Stop && *I != ' '; I++);
417 if (I >= Stop || *I != ' ')
418 return _error->Error("Malformed Status line");
419
420 // Process the want field
421 WordList WantList[] = {{"unknown",pkgCache::State::Unknown},
422 {"install",pkgCache::State::Install},
423 {"hold",pkgCache::State::Hold},
424 {"deinstall",pkgCache::State::DeInstall},
425 {"purge",pkgCache::State::Purge},
426 {"", 0}};
427 if (GrabWord(StringView(Start,I-Start),WantList,Pkg->SelectedState) == false)
428 return _error->Error("Malformed 1st word in the Status line");
429
430 // Isloate the next word
431 I++;
432 Start = I;
433 for(; I < Stop && *I != ' '; I++);
434 if (I >= Stop || *I != ' ')
435 return _error->Error("Malformed status line, no 2nd word");
436
437 // Process the flag field
438 WordList FlagList[] = {{"ok",pkgCache::State::Ok},
439 {"reinstreq",pkgCache::State::ReInstReq},
440 {"hold",pkgCache::State::HoldInst},
441 {"hold-reinstreq",pkgCache::State::HoldReInstReq},
442 {"", 0}};
443 if (GrabWord(StringView(Start,I-Start),FlagList,Pkg->InstState) == false)
444 return _error->Error("Malformed 2nd word in the Status line");
445
446 // Isloate the last word
447 I++;
448 Start = I;
449 for(; I < Stop && *I != ' '; I++);
450 if (I != Stop)
451 return _error->Error("Malformed Status line, no 3rd word");
452
453 // Process the flag field
454 WordList StatusList[] = {{"not-installed",pkgCache::State::NotInstalled},
455 {"config-files",pkgCache::State::ConfigFiles},
456 {"half-installed",pkgCache::State::HalfInstalled},
457 {"unpacked",pkgCache::State::UnPacked},
458 {"half-configured",pkgCache::State::HalfConfigured},
459 {"triggers-awaited",pkgCache::State::TriggersAwaited},
460 {"triggers-pending",pkgCache::State::TriggersPending},
461 {"installed",pkgCache::State::Installed},
462 {"", 0}};
463 if (GrabWord(StringView(Start,I-Start),StatusList,Pkg->CurrentState) == false)
464 return _error->Error("Malformed 3rd word in the Status line");
465
466 /* A Status line marks the package as indicating the current
467 version as well. Only if it is actually installed.. Otherwise
468 the interesting dpkg handling of the status file creates bogus
469 entries. */
470 if (!(Pkg->CurrentState == pkgCache::State::NotInstalled ||
471 Pkg->CurrentState == pkgCache::State::ConfigFiles))
472 {
473 if (Ver.end() == true)
474 _error->Warning("Encountered status field in a non-version description");
475 else
476 Pkg->CurrentVer = Ver.Index();
477 }
478
479 return true;
480 }
481
482 const char *debListParser::ConvertRelation(const char *I,unsigned int &Op)
483 {
484 // Determine the operator
485 switch (*I)
486 {
487 case '<':
488 I++;
489 if (*I == '=')
490 {
491 I++;
492 Op = pkgCache::Dep::LessEq;
493 break;
494 }
495
496 if (*I == '<')
497 {
498 I++;
499 Op = pkgCache::Dep::Less;
500 break;
501 }
502
503 // < is the same as <= and << is really Cs < for some reason
504 Op = pkgCache::Dep::LessEq;
505 break;
506
507 case '>':
508 I++;
509 if (*I == '=')
510 {
511 I++;
512 Op = pkgCache::Dep::GreaterEq;
513 break;
514 }
515
516 if (*I == '>')
517 {
518 I++;
519 Op = pkgCache::Dep::Greater;
520 break;
521 }
522
523 // > is the same as >= and >> is really Cs > for some reason
524 Op = pkgCache::Dep::GreaterEq;
525 break;
526
527 case '=':
528 Op = pkgCache::Dep::Equals;
529 I++;
530 break;
531
532 // HACK around bad package definitions
533 default:
534 Op = pkgCache::Dep::Equals;
535 break;
536 }
537 return I;
538 }
539 /*}}}*/
540 // ListParser::ParseDepends - Parse a dependency element /*{{{*/
541 // ---------------------------------------------------------------------
542 /* This parses the dependency elements out of a standard string in place,
543 bit by bit. */
544 const char *debListParser::ParseDepends(const char *Start,const char *Stop,
545 std::string &Package,std::string &Ver,unsigned int &Op)
546 { return ParseDepends(Start, Stop, Package, Ver, Op, false, true, false); }
547 const char *debListParser::ParseDepends(const char *Start,const char *Stop,
548 std::string &Package,std::string &Ver,unsigned int &Op,
549 bool const &ParseArchFlags)
550 { return ParseDepends(Start, Stop, Package, Ver, Op, ParseArchFlags, true, false); }
551 const char *debListParser::ParseDepends(const char *Start,const char *Stop,
552 std::string &Package,std::string &Ver,unsigned int &Op,
553 bool const &ParseArchFlags, bool const &StripMultiArch)
554 { return ParseDepends(Start, Stop, Package, Ver, Op, ParseArchFlags, StripMultiArch, false); }
555 const char *debListParser::ParseDepends(const char *Start,const char *Stop,
556 string &Package,string &Ver,
557 unsigned int &Op, bool const &ParseArchFlags,
558 bool const &StripMultiArch,
559 bool const &ParseRestrictionsList)
560 {
561 StringView PackageView;
562 StringView VerView;
563
564 auto res = ParseDepends(Start, Stop, PackageView, VerView, Op, (bool)ParseArchFlags,
565 (bool) StripMultiArch, (bool) ParseRestrictionsList);
566 Package = PackageView.to_string();
567 Ver = VerView.to_string();
568
569 return res;
570 }
571 const char *debListParser::ParseDepends(const char *Start,const char *Stop,
572 StringView &Package,StringView &Ver,
573 unsigned int &Op, bool ParseArchFlags,
574 bool StripMultiArch,
575 bool ParseRestrictionsList)
576 {
577 // Strip off leading space
578 for (;Start != Stop && isspace_ascii(*Start) != 0; ++Start);
579
580 // Parse off the package name
581 const char *I = Start;
582 for (;I != Stop && isspace_ascii(*I) == 0 && *I != '(' && *I != ')' &&
583 *I != ',' && *I != '|' && *I != '[' && *I != ']' &&
584 *I != '<' && *I != '>'; ++I);
585
586 // Malformed, no '('
587 if (I != Stop && *I == ')')
588 return 0;
589
590 if (I == Start)
591 return 0;
592
593 // Stash the package name
594 Package = StringView(Start, I - Start);
595
596 // We don't want to confuse library users which can't handle MultiArch
597 if (StripMultiArch == true) {
598 string const arch = _config->Find("APT::Architecture");
599 size_t const found = Package.rfind(':');
600 if (found != StringView::npos &&
601 (Package.substr(found) == ":any" ||
602 Package.substr(found) == ":native" ||
603 Package.substr(found +1) == arch))
604 Package = Package.substr(0,found);
605 }
606
607 // Skip white space to the '('
608 for (;I != Stop && isspace_ascii(*I) != 0 ; I++);
609
610 // Parse a version
611 if (I != Stop && *I == '(')
612 {
613 // Skip the '('
614 for (I++; I != Stop && isspace_ascii(*I) != 0 ; I++);
615 if (I + 3 >= Stop)
616 return 0;
617 I = ConvertRelation(I,Op);
618
619 // Skip whitespace
620 for (;I != Stop && isspace_ascii(*I) != 0; I++);
621 Start = I;
622 I = (const char*) memchr(I, ')', Stop - I);
623 if (I == NULL || Start == I)
624 return 0;
625
626 // Skip trailing whitespace
627 const char *End = I;
628 for (; End > Start && isspace_ascii(End[-1]); End--);
629
630 Ver = StringView(Start,End-Start);
631 I++;
632 }
633 else
634 {
635 Ver = StringView();
636 Op = pkgCache::Dep::NoOp;
637 }
638
639 // Skip whitespace
640 for (;I != Stop && isspace_ascii(*I) != 0; I++);
641
642 if (unlikely(ParseArchFlags == true))
643 {
644 string const arch = _config->Find("APT::Architecture");
645 APT::CacheFilter::PackageArchitectureMatchesSpecification matchesArch(arch, false);
646
647 // Parse an architecture
648 if (I != Stop && *I == '[')
649 {
650 ++I;
651 // malformed
652 if (unlikely(I == Stop))
653 return 0;
654
655 const char *End = I;
656 bool Found = false;
657 bool NegArch = false;
658 while (I != Stop)
659 {
660 // look for whitespace or ending ']'
661 for (;End != Stop && !isspace_ascii(*End) && *End != ']'; ++End);
662
663 if (unlikely(End == Stop))
664 return 0;
665
666 if (*I == '!')
667 {
668 NegArch = true;
669 ++I;
670 }
671
672 std::string const arch(I, End);
673 if (arch.empty() == false && matchesArch(arch.c_str()) == true)
674 {
675 Found = true;
676 if (I[-1] != '!')
677 NegArch = false;
678 // we found a match, so fast-forward to the end of the wildcards
679 for (; End != Stop && *End != ']'; ++End);
680 }
681
682 if (*End++ == ']') {
683 I = End;
684 break;
685 }
686
687 I = End;
688 for (;I != Stop && isspace_ascii(*I) != 0; I++);
689 }
690
691 if (NegArch == true)
692 Found = !Found;
693
694 if (Found == false)
695 Package = ""; /* not for this arch */
696 }
697
698 // Skip whitespace
699 for (;I != Stop && isspace_ascii(*I) != 0; I++);
700 }
701
702 if (unlikely(ParseRestrictionsList == true))
703 {
704 // Parse a restrictions formula which is in disjunctive normal form:
705 // (foo AND bar) OR (blub AND bla)
706
707 std::vector<string> const profiles = APT::Configuration::getBuildProfiles();
708
709 // if the next character is a restriction list, then by default the
710 // dependency does not apply and the conditions have to be checked
711 // if the next character is not a restriction list, then by default the
712 // dependency applies
713 bool applies1 = (*I != '<');
714 while (I != Stop)
715 {
716 if (*I != '<')
717 break;
718
719 ++I;
720 // malformed
721 if (unlikely(I == Stop))
722 return 0;
723
724 const char *End = I;
725
726 // if of the prior restriction list is already fulfilled, then
727 // we can just skip to the end of the current list
728 if (applies1) {
729 for (;End != Stop && *End != '>'; ++End);
730 I = ++End;
731 // skip whitespace
732 for (;I != Stop && isspace_ascii(*I) != 0; I++);
733 } else {
734 bool applies2 = true;
735 // all the conditions inside a restriction list have to be
736 // met so once we find one that is not met, we can skip to
737 // the end of this list
738 while (I != Stop)
739 {
740 // look for whitespace or ending '>'
741 // End now points to the character after the current term
742 for (;End != Stop && !isspace_ascii(*End) && *End != '>'; ++End);
743
744 if (unlikely(End == Stop))
745 return 0;
746
747 bool NegRestriction = false;
748 if (*I == '!')
749 {
750 NegRestriction = true;
751 ++I;
752 }
753
754 std::string const restriction(I, End);
755 if (restriction.empty() == false && profiles.empty() == false &&
756 std::find(profiles.begin(), profiles.end(), restriction) != profiles.end())
757 {
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 } else {
764 if (!NegRestriction) {
765 applies2 = false;
766 // since one of the terms does not apply we don't have to check the others
767 for (; End != Stop && *End != '>'; ++End);
768 }
769 }
770
771 if (*End++ == '>') {
772 I = End;
773 // skip whitespace
774 for (;I != Stop && isspace_ascii(*I) != 0; I++);
775 break;
776 }
777
778 I = End;
779 // skip whitespace
780 for (;I != Stop && isspace_ascii(*I) != 0; I++);
781 }
782 if (applies2) {
783 applies1 = true;
784 }
785 }
786 }
787
788 if (applies1 == false) {
789 Package = ""; //not for this restriction
790 }
791 }
792
793 if (I != Stop && *I == '|')
794 Op |= pkgCache::Dep::Or;
795
796 if (I == Stop || *I == ',' || *I == '|')
797 {
798 if (I != Stop)
799 for (I++; I != Stop && isspace_ascii(*I) != 0; I++);
800 return I;
801 }
802
803 return 0;
804 }
805 /*}}}*/
806 // ListParser::ParseDepends - Parse a dependency list /*{{{*/
807 // ---------------------------------------------------------------------
808 /* This is the higher level depends parser. It takes a tag and generates
809 a complete depends tree for the given version. */
810 bool debListParser::ParseDepends(pkgCache::VerIterator &Ver,
811 pkgTagSection::Key Key,unsigned int Type)
812 {
813 const char *Start;
814 const char *Stop;
815 if (Section.Find(Key,Start,Stop) == false || Start == Stop)
816 return true;
817
818 string const pkgArch = Ver.Arch();
819
820 while (1)
821 {
822 StringView Package;
823 StringView Version;
824 unsigned int Op;
825
826 Start = ParseDepends(Start, Stop, Package, Version, Op, false, false, false);
827 if (Start == 0) {
828 _error->Warning("Problem parsing dependency %zu",static_cast<size_t>(Key)); // TODO
829 continue;
830 }
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 _error->Warning("Problem parsing Provides line");
899 continue;
900 }
901 if (unlikely(Op != pkgCache::Dep::NoOp && Op != pkgCache::Dep::Equals)) {
902 _error->Warning("Ignoring Provides line with non-equal DepCompareOp for package %s", Package.to_string().c_str());
903 } else if (archfound != string::npos) {
904 StringView spzArch = Package.substr(archfound + 1);
905 if (spzArch != "any")
906 {
907 if (NewProvides(Ver, Package.substr(0, archfound), spzArch, Version, pkgCache::Flag::MultiArchImplicit | pkgCache::Flag::ArchSpecific) == false)
908 return false;
909 }
910 if (NewProvides(Ver, Package, "any", Version, pkgCache::Flag::ArchSpecific) == false)
911 return false;
912 } else if ((Ver->MultiArch & pkgCache::Version::Foreign) == pkgCache::Version::Foreign) {
913 if (APT::Configuration::checkArchitecture(Arch))
914 {
915 if (NewProvidesAllArch(Ver, Package, Version, 0) == false)
916 return false;
917 }
918 else if (NewProvides(Ver, Package, Arch, Version, 0) == false)
919 return false;
920 } else {
921 if ((Ver->MultiArch & pkgCache::Version::Allowed) == pkgCache::Version::Allowed)
922 {
923 if (NewProvides(Ver, Package.to_string().append(":any"), "any", Version, pkgCache::Flag::MultiArchImplicit) == false)
924 return false;
925 }
926 if (NewProvides(Ver, Package, Arch, Version, 0) == false)
927 return false;
928 }
929 if (archfound == std::string::npos)
930 {
931 string spzName = Package.to_string();
932 spzName.push_back(':');
933 spzName.append(Ver.ParentPkg().Arch());
934 pkgCache::PkgIterator const spzPkg = Ver.Cache()->FindPkg(spzName, "any");
935 if (spzPkg.end() == false)
936 {
937 if (NewProvides(Ver, spzName, "any", Version, pkgCache::Flag::MultiArchImplicit | pkgCache::Flag::ArchSpecific) == false)
938 return false;
939 }
940 }
941 } while (Start != Stop);
942 }
943
944 if (APT::Configuration::checkArchitecture(Arch))
945 {
946 if ((Ver->MultiArch & pkgCache::Version::Allowed) == pkgCache::Version::Allowed)
947 {
948 string const Package = string(Ver.ParentPkg().Name()).append(":").append("any");
949 if (NewProvides(Ver, Package, "any", Ver.VerStr(), pkgCache::Flag::MultiArchImplicit) == false)
950 return false;
951 }
952 else if ((Ver->MultiArch & pkgCache::Version::Foreign) == pkgCache::Version::Foreign)
953 {
954 if (NewProvidesAllArch(Ver, Ver.ParentPkg().Name(), Ver.VerStr(), pkgCache::Flag::MultiArchImplicit) == false)
955 return false;
956 }
957 }
958
959 if (hasProvidesAlready == false)
960 {
961 pkgCache::PkgIterator const spzPkg = Ver.Cache()->FindPkg(spzName, "any");
962 if (spzPkg.end() == false)
963 {
964 if (NewProvides(Ver, spzName, "any", Ver.VerStr(), pkgCache::Flag::MultiArchImplicit | pkgCache::Flag::ArchSpecific) == false)
965 return false;
966 }
967 }
968 return true;
969 }
970 /*}}}*/
971 // ListParser::ParseTag - Parse the tag list /*{{{*/
972 // ---------------------------------------------------------------------
973 /* */
974 bool debListParser::ParseTag(pkgCache::VerIterator &Ver)
975 {
976 const char *Start;
977 const char *Stop;
978 if (Section.Find("Tag",Start,Stop) == false)
979 return true;
980
981 while (1) {
982 while (1) {
983 if (Start == Stop)
984 return true;
985 if (Stop[-1] != ' ' && Stop[-1] != '\t')
986 break;
987 --Stop;
988 }
989
990 const char *Begin = Stop - 1;
991 while (Begin != Start && Begin[-1] != ' ' && Begin[-1] != ',')
992 --Begin;
993
994 if (NewTag(Ver, Begin, Stop - Begin) == false)
995 return false;
996
997 while (1) {
998 if (Begin == Start)
999 return true;
1000 if (Begin[-1] == ',')
1001 break;
1002 --Begin;
1003 }
1004
1005 Stop = Begin - 1;
1006 }
1007
1008 return true;
1009 }
1010 /*}}}*/
1011 // ListParser::GrabWord - Matches a word and returns /*{{{*/
1012 // ---------------------------------------------------------------------
1013 /* Looks for a word in a list of words - for ParseStatus */
1014 bool debListParser::GrabWord(StringView Word, WordList const *List, unsigned char &Out)
1015 {
1016 for (unsigned int C = 0; List[C].Str.empty() == false; C++)
1017 {
1018 if (Word.length() == List[C].Str.length() &&
1019 strncasecmp(Word.data(), List[C].Str.data(), Word.length()) == 0)
1020 {
1021 Out = List[C].Val;
1022 return true;
1023 }
1024 }
1025 return false;
1026 }
1027 /*}}}*/
1028 // ListParser::Step - Move to the next section in the file /*{{{*/
1029 // ---------------------------------------------------------------------
1030 /* This has to be careful to only process the correct architecture */
1031 bool debListParser::Step()
1032 {
1033 iOffset = Tags.Offset();
1034 return Tags.Step(Section);
1035 }
1036 /*}}}*/
1037 // ListParser::GetPrio - Convert the priority from a string /*{{{*/
1038 // ---------------------------------------------------------------------
1039 /* */
1040 unsigned char debListParser::GetPrio(string Str)
1041 {
1042 unsigned char Out;
1043 if (GrabWord(Str,PrioList,Out) == false)
1044 Out = pkgCache::State::Extra;
1045
1046 return Out;
1047 }
1048 /*}}}*/
1049 bool debListParser::SameVersion(unsigned short const Hash, /*{{{*/
1050 pkgCache::VerIterator const &Ver)
1051 {
1052 if (pkgCacheListParser::SameVersion(Hash, Ver) == false)
1053 return false;
1054 // status file has no (Download)Size, but all others are fair game
1055 // status file is parsed last, so the first version we encounter is
1056 // probably also the version we have downloaded
1057 unsigned long long const Size = Section.FindULL(pkgTagSection::Key::Size);
1058 if (Size != 0 && Ver->Size != 0 && Size != Ver->Size)
1059 return false;
1060 // available everywhere, but easier to check here than to include in VersionHash
1061 unsigned char MultiArch = ParseMultiArch(false);
1062 if (MultiArch != Ver->MultiArch)
1063 return false;
1064 // for all practical proposes (we can check): same version
1065 return true;
1066 }
1067 /*}}}*/
1068
1069 debDebFileParser::debDebFileParser(FileFd *File, std::string const &DebFile)
1070 : debListParser(File), DebFile(DebFile)
1071 {
1072 }
1073
1074 bool debDebFileParser::UsePackage(pkgCache::PkgIterator &Pkg,
1075 pkgCache::VerIterator &Ver)
1076 {
1077 bool res = debListParser::UsePackage(Pkg, Ver);
1078 // we use the full file path as a provides so that the file is found
1079 // by its name
1080 if(NewProvides(Ver, DebFile, Pkg.Cache()->NativeArch(), Ver.VerStr(), 0) == false)
1081 return false;
1082 return res;
1083 }
1084
1085 debListParser::~debListParser() {}