]> git.saurik.com Git - apt.git/blob - apt-pkg/deb/deblistparser.cc
fix test/integration/test-apt-helper
[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/fileutl.h>
22 #include <apt-pkg/crc-16.h>
23 #include <apt-pkg/md5.h>
24 #include <apt-pkg/mmap.h>
25 #include <apt-pkg/pkgcache.h>
26 #include <apt-pkg/cacheiterators.h>
27 #include <apt-pkg/tagfile.h>
28 #include <apt-pkg/macros.h>
29
30 #include <stddef.h>
31 #include <string.h>
32 #include <algorithm>
33 #include <string>
34 #include <vector>
35 #include <ctype.h>
36 /*}}}*/
37
38 using std::string;
39
40 static 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 {NULL, 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, string const &Arch) : Tags(File),
54 Arch(Arch) {
55 if (Arch == "native")
56 this->Arch = _config->Find("APT::Architecture");
57 Architectures = APT::Configuration::getArchitectures();
58 MultiArchEnabled = Architectures.size() > 1;
59 }
60 /*}}}*/
61 // ListParser::UniqFindTagWrite - Find the tag and write a unq string /*{{{*/
62 // ---------------------------------------------------------------------
63 /* */
64 unsigned long debListParser::UniqFindTagWrite(const char *Tag)
65 {
66 const char *Start;
67 const char *Stop;
68 if (Section.Find(Tag,Start,Stop) == false)
69 return 0;
70 return WriteUniqString(Start,Stop - Start);
71 }
72 /*}}}*/
73 // ListParser::Package - Return the package name /*{{{*/
74 // ---------------------------------------------------------------------
75 /* This is to return the name of the package this section describes */
76 string debListParser::Package() {
77 string const Result = Section.FindS("Package");
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 string debListParser::Architecture() {
87 return Section.FindS("Architecture");
88 }
89 /*}}}*/
90 // ListParser::ArchitectureAll /*{{{*/
91 // ---------------------------------------------------------------------
92 /* */
93 bool debListParser::ArchitectureAll() {
94 return Section.FindS("Architecture") == "all";
95 }
96 /*}}}*/
97 // ListParser::Version - Return the version string /*{{{*/
98 // ---------------------------------------------------------------------
99 /* This is to return the string describing the version in debian form,
100 epoch:upstream-release. If this returns the blank string then the
101 entry is assumed to only describe package properties */
102 string debListParser::Version()
103 {
104 return Section.FindS("Version");
105 }
106 /*}}}*/
107 unsigned char debListParser::ParseMultiArch(bool const showErrors) /*{{{*/
108 {
109 unsigned char MA;
110 string const MultiArch = Section.FindS("Multi-Arch");
111 if (MultiArch.empty() == true)
112 MA = pkgCache::Version::None;
113 else if (MultiArch == "same") {
114 if (ArchitectureAll() == true)
115 {
116 if (showErrors == true)
117 _error->Warning("Architecture: all package '%s' can't be Multi-Arch: same",
118 Section.FindS("Package").c_str());
119 MA = pkgCache::Version::None;
120 }
121 else
122 MA = pkgCache::Version::Same;
123 }
124 else if (MultiArch == "foreign")
125 MA = pkgCache::Version::Foreign;
126 else if (MultiArch == "allowed")
127 MA = pkgCache::Version::Allowed;
128 else
129 {
130 if (showErrors == true)
131 _error->Warning("Unknown Multi-Arch type '%s' for package '%s'",
132 MultiArch.c_str(), Section.FindS("Package").c_str());
133 MA = pkgCache::Version::None;
134 }
135
136 if (ArchitectureAll() == true)
137 MA |= pkgCache::Version::All;
138
139 return MA;
140 }
141 /*}}}*/
142 // ListParser::NewVersion - Fill in the version structure /*{{{*/
143 // ---------------------------------------------------------------------
144 /* */
145 bool debListParser::NewVersion(pkgCache::VerIterator &Ver)
146 {
147 // Parse the section
148 Ver->Section = UniqFindTagWrite("Section");
149 Ver->MultiArch = ParseMultiArch(true);
150 // Archive Size
151 Ver->Size = Section.FindULL("Size");
152 // Unpacked Size (in K)
153 Ver->InstalledSize = Section.FindULL("Installed-Size");
154 Ver->InstalledSize *= 1024;
155
156 // Priority
157 const char *Start;
158 const char *Stop;
159 if (Section.Find("Priority",Start,Stop) == true)
160 {
161 if (GrabWord(string(Start,Stop-Start),PrioList,Ver->Priority) == false)
162 Ver->Priority = pkgCache::State::Extra;
163 }
164
165 if (ParseDepends(Ver,"Depends",pkgCache::Dep::Depends) == false)
166 return false;
167 if (ParseDepends(Ver,"Pre-Depends",pkgCache::Dep::PreDepends) == false)
168 return false;
169 if (ParseDepends(Ver,"Suggests",pkgCache::Dep::Suggests) == false)
170 return false;
171 if (ParseDepends(Ver,"Recommends",pkgCache::Dep::Recommends) == false)
172 return false;
173 if (ParseDepends(Ver,"Conflicts",pkgCache::Dep::Conflicts) == false)
174 return false;
175 if (ParseDepends(Ver,"Breaks",pkgCache::Dep::DpkgBreaks) == false)
176 return false;
177 if (ParseDepends(Ver,"Replaces",pkgCache::Dep::Replaces) == false)
178 return false;
179 if (ParseDepends(Ver,"Enhances",pkgCache::Dep::Enhances) == false)
180 return false;
181
182 // Obsolete.
183 if (ParseDepends(Ver,"Optional",pkgCache::Dep::Suggests) == false)
184 return false;
185
186 if (ParseProvides(Ver) == false)
187 return false;
188
189 return true;
190 }
191 /*}}}*/
192 // ListParser::Description - Return the description string /*{{{*/
193 // ---------------------------------------------------------------------
194 /* This is to return the string describing the package in debian
195 form. If this returns the blank string then the entry is assumed to
196 only describe package properties */
197 string debListParser::Description()
198 {
199 string const lang = DescriptionLanguage();
200 if (lang.empty())
201 return Section.FindS("Description");
202 else
203 return Section.FindS(string("Description-").append(lang).c_str());
204 }
205 /*}}}*/
206 // ListParser::DescriptionLanguage - Return the description lang string /*{{{*/
207 // ---------------------------------------------------------------------
208 /* This is to return the string describing the language of
209 description. If this returns the blank string then the entry is
210 assumed to describe original description. */
211 string debListParser::DescriptionLanguage()
212 {
213 if (Section.FindS("Description").empty() == false)
214 return "";
215
216 std::vector<string> const lang = APT::Configuration::getLanguages(true);
217 for (std::vector<string>::const_iterator l = lang.begin();
218 l != lang.end(); ++l)
219 if (Section.FindS(string("Description-").append(*l).c_str()).empty() == false)
220 return *l;
221
222 return "";
223 }
224 /*}}}*/
225 // ListParser::Description - Return the description_md5 MD5SumValue /*{{{*/
226 // ---------------------------------------------------------------------
227 /* This is to return the md5 string to allow the check if it is the right
228 description. If no Description-md5 is found in the section it will be
229 calculated.
230 */
231 MD5SumValue debListParser::Description_md5()
232 {
233 string const value = Section.FindS("Description-md5");
234 if (value.empty() == true)
235 {
236 std::string const desc = Description() + "\n";
237 if (desc == "\n")
238 return MD5SumValue();
239
240 MD5Summation md5;
241 md5.Add(desc.c_str());
242 return md5.Result();
243 }
244 else if (likely(value.size() == 32))
245 {
246 if (likely(value.find_first_not_of("0123456789abcdefABCDEF") == string::npos))
247 return MD5SumValue(value);
248 _error->Error("Malformed Description-md5 line; includes invalid character '%s'", value.c_str());
249 return MD5SumValue();
250 }
251 _error->Error("Malformed Description-md5 line; doesn't have the required length (32 != %d) '%s'", (int)value.size(), value.c_str());
252 return MD5SumValue();
253 }
254 /*}}}*/
255 // ListParser::UsePackage - Update a package structure /*{{{*/
256 // ---------------------------------------------------------------------
257 /* This is called to update the package with any new information
258 that might be found in the section */
259 bool debListParser::UsePackage(pkgCache::PkgIterator &Pkg,
260 pkgCache::VerIterator &Ver)
261 {
262 if (Pkg->Section == 0)
263 Pkg->Section = UniqFindTagWrite("Section");
264
265 string const static myArch = _config->Find("APT::Architecture");
266 // Possible values are: "all", "native", "installed" and "none"
267 // The "installed" mode is handled by ParseStatus(), See #544481 and friends.
268 string const static essential = _config->Find("pkgCacheGen::Essential", "all");
269 if (essential == "all" ||
270 (essential == "native" && Pkg->Arch != 0 && myArch == Pkg.Arch()))
271 if (Section.FindFlag("Essential",Pkg->Flags,pkgCache::Flag::Essential) == false)
272 return false;
273 if (Section.FindFlag("Important",Pkg->Flags,pkgCache::Flag::Important) == false)
274 return false;
275
276 if (strcmp(Pkg.Name(),"apt") == 0)
277 {
278 if ((essential == "native" && Pkg->Arch != 0 && myArch == Pkg.Arch()) ||
279 essential == "all")
280 Pkg->Flags |= pkgCache::Flag::Essential | pkgCache::Flag::Important;
281 else
282 Pkg->Flags |= pkgCache::Flag::Important;
283 }
284
285 if (ParseStatus(Pkg,Ver) == false)
286 return false;
287 return true;
288 }
289 /*}}}*/
290 // ListParser::VersionHash - Compute a unique hash for this version /*{{{*/
291 // ---------------------------------------------------------------------
292 /* */
293 unsigned short debListParser::VersionHash()
294 {
295 const char *Sections[] ={"Installed-Size",
296 "Depends",
297 "Pre-Depends",
298 // "Suggests",
299 // "Recommends",
300 "Conflicts",
301 "Breaks",
302 "Replaces",0};
303 unsigned long Result = INIT_FCS;
304 char S[1024];
305 for (const char * const *I = Sections; *I != 0; ++I)
306 {
307 const char *Start;
308 const char *End;
309 if (Section.Find(*I,Start,End) == false || End - Start >= (signed)sizeof(S))
310 continue;
311
312 /* Strip out any spaces from the text, this undoes dpkgs reformatting
313 of certain fields. dpkg also has the rather interesting notion of
314 reformatting depends operators < -> <= */
315 char *J = S;
316 for (; Start != End; ++Start)
317 {
318 if (isspace(*Start) != 0)
319 continue;
320 *J++ = tolower_ascii(*Start);
321
322 if ((*Start == '<' || *Start == '>') && Start[1] != *Start && Start[1] != '=')
323 *J++ = '=';
324 }
325
326 Result = AddCRC16(Result,S,J - S);
327 }
328
329 return Result;
330 }
331 /*}}}*/
332 // ListParser::ParseStatus - Parse the status field /*{{{*/
333 // ---------------------------------------------------------------------
334 /* Status lines are of the form,
335 Status: want flag status
336 want = unknown, install, hold, deinstall, purge
337 flag = ok, reinstreq, hold, hold-reinstreq
338 status = not-installed, unpacked, half-configured,
339 half-installed, config-files, post-inst-failed,
340 removal-failed, installed
341
342 Some of the above are obsolete (I think?) flag = hold-* and
343 status = post-inst-failed, removal-failed at least.
344 */
345 bool debListParser::ParseStatus(pkgCache::PkgIterator &Pkg,
346 pkgCache::VerIterator &Ver)
347 {
348 const char *Start;
349 const char *Stop;
350 if (Section.Find("Status",Start,Stop) == false)
351 return true;
352
353 // UsePackage() is responsible for setting the flag in the default case
354 bool const static essential = _config->Find("pkgCacheGen::Essential", "") == "installed";
355 if (essential == true &&
356 Section.FindFlag("Essential",Pkg->Flags,pkgCache::Flag::Essential) == false)
357 return false;
358
359 // Isolate the first word
360 const char *I = Start;
361 for(; I < Stop && *I != ' '; I++);
362 if (I >= Stop || *I != ' ')
363 return _error->Error("Malformed Status line");
364
365 // Process the want field
366 WordList WantList[] = {{"unknown",pkgCache::State::Unknown},
367 {"install",pkgCache::State::Install},
368 {"hold",pkgCache::State::Hold},
369 {"deinstall",pkgCache::State::DeInstall},
370 {"purge",pkgCache::State::Purge},
371 {NULL, 0}};
372 if (GrabWord(string(Start,I-Start),WantList,Pkg->SelectedState) == false)
373 return _error->Error("Malformed 1st word in the Status line");
374
375 // Isloate the next word
376 I++;
377 Start = I;
378 for(; I < Stop && *I != ' '; I++);
379 if (I >= Stop || *I != ' ')
380 return _error->Error("Malformed status line, no 2nd word");
381
382 // Process the flag field
383 WordList FlagList[] = {{"ok",pkgCache::State::Ok},
384 {"reinstreq",pkgCache::State::ReInstReq},
385 {"hold",pkgCache::State::HoldInst},
386 {"hold-reinstreq",pkgCache::State::HoldReInstReq},
387 {NULL, 0}};
388 if (GrabWord(string(Start,I-Start),FlagList,Pkg->InstState) == false)
389 return _error->Error("Malformed 2nd word in the Status line");
390
391 // Isloate the last word
392 I++;
393 Start = I;
394 for(; I < Stop && *I != ' '; I++);
395 if (I != Stop)
396 return _error->Error("Malformed Status line, no 3rd word");
397
398 // Process the flag field
399 WordList StatusList[] = {{"not-installed",pkgCache::State::NotInstalled},
400 {"unpacked",pkgCache::State::UnPacked},
401 {"half-configured",pkgCache::State::HalfConfigured},
402 {"installed",pkgCache::State::Installed},
403 {"half-installed",pkgCache::State::HalfInstalled},
404 {"config-files",pkgCache::State::ConfigFiles},
405 {"triggers-awaited",pkgCache::State::TriggersAwaited},
406 {"triggers-pending",pkgCache::State::TriggersPending},
407 {"post-inst-failed",pkgCache::State::HalfConfigured},
408 {"removal-failed",pkgCache::State::HalfInstalled},
409 {NULL, 0}};
410 if (GrabWord(string(Start,I-Start),StatusList,Pkg->CurrentState) == false)
411 return _error->Error("Malformed 3rd word in the Status line");
412
413 /* A Status line marks the package as indicating the current
414 version as well. Only if it is actually installed.. Otherwise
415 the interesting dpkg handling of the status file creates bogus
416 entries. */
417 if (!(Pkg->CurrentState == pkgCache::State::NotInstalled ||
418 Pkg->CurrentState == pkgCache::State::ConfigFiles))
419 {
420 if (Ver.end() == true)
421 _error->Warning("Encountered status field in a non-version description");
422 else
423 Pkg->CurrentVer = Ver.Index();
424 }
425
426 return true;
427 }
428
429 const char *debListParser::ConvertRelation(const char *I,unsigned int &Op)
430 {
431 // Determine the operator
432 switch (*I)
433 {
434 case '<':
435 I++;
436 if (*I == '=')
437 {
438 I++;
439 Op = pkgCache::Dep::LessEq;
440 break;
441 }
442
443 if (*I == '<')
444 {
445 I++;
446 Op = pkgCache::Dep::Less;
447 break;
448 }
449
450 // < is the same as <= and << is really Cs < for some reason
451 Op = pkgCache::Dep::LessEq;
452 break;
453
454 case '>':
455 I++;
456 if (*I == '=')
457 {
458 I++;
459 Op = pkgCache::Dep::GreaterEq;
460 break;
461 }
462
463 if (*I == '>')
464 {
465 I++;
466 Op = pkgCache::Dep::Greater;
467 break;
468 }
469
470 // > is the same as >= and >> is really Cs > for some reason
471 Op = pkgCache::Dep::GreaterEq;
472 break;
473
474 case '=':
475 Op = pkgCache::Dep::Equals;
476 I++;
477 break;
478
479 // HACK around bad package definitions
480 default:
481 Op = pkgCache::Dep::Equals;
482 break;
483 }
484 return I;
485 }
486 /*}}}*/
487 // ListParser::ParseDepends - Parse a dependency element /*{{{*/
488 // ---------------------------------------------------------------------
489 /* This parses the dependency elements out of a standard string in place,
490 bit by bit. */
491 const char *debListParser::ParseDepends(const char *Start,const char *Stop,
492 std::string &Package,std::string &Ver,unsigned int &Op)
493 { return ParseDepends(Start, Stop, Package, Ver, Op, false, true, false); }
494 const char *debListParser::ParseDepends(const char *Start,const char *Stop,
495 std::string &Package,std::string &Ver,unsigned int &Op,
496 bool const &ParseArchFlags)
497 { return ParseDepends(Start, Stop, Package, Ver, Op, ParseArchFlags, true, false); }
498 const char *debListParser::ParseDepends(const char *Start,const char *Stop,
499 std::string &Package,std::string &Ver,unsigned int &Op,
500 bool const &ParseArchFlags, bool const &StripMultiArch)
501 { return ParseDepends(Start, Stop, Package, Ver, Op, ParseArchFlags, StripMultiArch, false); }
502 const char *debListParser::ParseDepends(const char *Start,const char *Stop,
503 string &Package,string &Ver,
504 unsigned int &Op, bool const &ParseArchFlags,
505 bool const &StripMultiArch,
506 bool const &ParseRestrictionsList)
507 {
508 // Strip off leading space
509 for (;Start != Stop && isspace(*Start) != 0; ++Start);
510
511 // Parse off the package name
512 const char *I = Start;
513 for (;I != Stop && isspace(*I) == 0 && *I != '(' && *I != ')' &&
514 *I != ',' && *I != '|' && *I != '[' && *I != ']' &&
515 *I != '<' && *I != '>'; ++I);
516
517 // Malformed, no '('
518 if (I != Stop && *I == ')')
519 return 0;
520
521 if (I == Start)
522 return 0;
523
524 // Stash the package name
525 Package.assign(Start,I - Start);
526
527 // We don't want to confuse library users which can't handle MultiArch
528 string const arch = _config->Find("APT::Architecture");
529 if (StripMultiArch == true) {
530 size_t const found = Package.rfind(':');
531 if (found != string::npos &&
532 (strcmp(Package.c_str() + found, ":any") == 0 ||
533 strcmp(Package.c_str() + found, ":native") == 0 ||
534 strcmp(Package.c_str() + found + 1, arch.c_str()) == 0))
535 Package = Package.substr(0,found);
536 }
537
538 // Skip white space to the '('
539 for (;I != Stop && isspace(*I) != 0 ; I++);
540
541 // Parse a version
542 if (I != Stop && *I == '(')
543 {
544 // Skip the '('
545 for (I++; I != Stop && isspace(*I) != 0 ; I++);
546 if (I + 3 >= Stop)
547 return 0;
548 I = ConvertRelation(I,Op);
549
550 // Skip whitespace
551 for (;I != Stop && isspace(*I) != 0; I++);
552 Start = I;
553 I = (const char*) memchr(I, ')', Stop - I);
554 if (I == NULL || Start == I)
555 return 0;
556
557 // Skip trailing whitespace
558 const char *End = I;
559 for (; End > Start && isspace(End[-1]); End--);
560
561 Ver.assign(Start,End-Start);
562 I++;
563 }
564 else
565 {
566 Ver.clear();
567 Op = pkgCache::Dep::NoOp;
568 }
569
570 // Skip whitespace
571 for (;I != Stop && isspace(*I) != 0; I++);
572
573 if (ParseArchFlags == true)
574 {
575 APT::CacheFilter::PackageArchitectureMatchesSpecification matchesArch(arch, false);
576
577 // Parse an architecture
578 if (I != Stop && *I == '[')
579 {
580 ++I;
581 // malformed
582 if (unlikely(I == Stop))
583 return 0;
584
585 const char *End = I;
586 bool Found = false;
587 bool NegArch = false;
588 while (I != Stop)
589 {
590 // look for whitespace or ending ']'
591 for (;End != Stop && !isspace(*End) && *End != ']'; ++End);
592
593 if (unlikely(End == Stop))
594 return 0;
595
596 if (*I == '!')
597 {
598 NegArch = true;
599 ++I;
600 }
601
602 std::string arch(I, End);
603 if (arch.empty() == false && matchesArch(arch.c_str()) == true)
604 {
605 Found = true;
606 if (I[-1] != '!')
607 NegArch = false;
608 // we found a match, so fast-forward to the end of the wildcards
609 for (; End != Stop && *End != ']'; ++End);
610 }
611
612 if (*End++ == ']') {
613 I = End;
614 break;
615 }
616
617 I = End;
618 for (;I != Stop && isspace(*I) != 0; I++);
619 }
620
621 if (NegArch == true)
622 Found = !Found;
623
624 if (Found == false)
625 Package = ""; /* not for this arch */
626 }
627
628 // Skip whitespace
629 for (;I != Stop && isspace(*I) != 0; I++);
630 }
631
632 if (ParseRestrictionsList == true)
633 {
634 // Parse a restrictions list
635 if (I != Stop && *I == '<')
636 {
637 ++I;
638 // malformed
639 if (unlikely(I == Stop))
640 return 0;
641
642 std::vector<string> const profiles = APT::Configuration::getBuildProfiles();
643
644 const char *End = I;
645 bool Found = false;
646 bool NegRestriction = false;
647 while (I != Stop)
648 {
649 // look for whitespace or ending '>'
650 for (;End != Stop && !isspace(*End) && *End != '>'; ++End);
651
652 if (unlikely(End == Stop))
653 return 0;
654
655 if (*I == '!')
656 {
657 NegRestriction = true;
658 ++I;
659 }
660
661 std::string restriction(I, End);
662
663 std::string prefix = "profile.";
664 // only support for "profile" prefix, ignore others
665 if (restriction.size() > prefix.size() &&
666 restriction.substr(0, prefix.size()) == prefix)
667 {
668 // get the name of the profile
669 restriction = restriction.substr(prefix.size());
670
671 if (restriction.empty() == false && profiles.empty() == false &&
672 std::find(profiles.begin(), profiles.end(), restriction) != profiles.end())
673 {
674 Found = true;
675 if (I[-1] != '!')
676 NegRestriction = false;
677 // we found a match, so fast-forward to the end of the wildcards
678 for (; End != Stop && *End != '>'; ++End);
679 }
680 }
681
682 if (*End++ == '>') {
683 I = End;
684 break;
685 }
686
687 I = End;
688 for (;I != Stop && isspace(*I) != 0; I++);
689 }
690
691 if (NegRestriction == true)
692 Found = !Found;
693
694 if (Found == false)
695 Package = ""; /* not for this restriction */
696 }
697
698 // Skip whitespace
699 for (;I != Stop && isspace(*I) != 0; I++);
700 }
701
702 if (I != Stop && *I == '|')
703 Op |= pkgCache::Dep::Or;
704
705 if (I == Stop || *I == ',' || *I == '|')
706 {
707 if (I != Stop)
708 for (I++; I != Stop && isspace(*I) != 0; I++);
709 return I;
710 }
711
712 return 0;
713 }
714 /*}}}*/
715 // ListParser::ParseDepends - Parse a dependency list /*{{{*/
716 // ---------------------------------------------------------------------
717 /* This is the higher level depends parser. It takes a tag and generates
718 a complete depends tree for the given version. */
719 bool debListParser::ParseDepends(pkgCache::VerIterator &Ver,
720 const char *Tag,unsigned int Type)
721 {
722 const char *Start;
723 const char *Stop;
724 if (Section.Find(Tag,Start,Stop) == false)
725 return true;
726
727 string const pkgArch = Ver.Arch();
728
729 while (1)
730 {
731 string Package;
732 string Version;
733 unsigned int Op;
734
735 Start = ParseDepends(Start, Stop, Package, Version, Op, false, false, false);
736 if (Start == 0)
737 return _error->Error("Problem parsing dependency %s",Tag);
738 size_t const found = Package.rfind(':');
739
740 // If negative is unspecific it needs to apply on all architectures
741 if (MultiArchEnabled == true && found == string::npos &&
742 (Type == pkgCache::Dep::Conflicts ||
743 Type == pkgCache::Dep::DpkgBreaks ||
744 Type == pkgCache::Dep::Replaces))
745 {
746 for (std::vector<std::string>::const_iterator a = Architectures.begin();
747 a != Architectures.end(); ++a)
748 if (NewDepends(Ver,Package,*a,Version,Op,Type) == false)
749 return false;
750 if (NewDepends(Ver,Package,"none",Version,Op,Type) == false)
751 return false;
752 }
753 else if (MultiArchEnabled == true && found != string::npos &&
754 strcmp(Package.c_str() + found, ":any") != 0)
755 {
756 string Arch = Package.substr(found+1, string::npos);
757 Package = Package.substr(0, found);
758 // Such dependencies are not supposed to be accepted …
759 // … but this is probably the best thing to do.
760 if (Arch == "native")
761 Arch = _config->Find("APT::Architecture");
762 if (NewDepends(Ver,Package,Arch,Version,Op,Type) == false)
763 return false;
764 }
765 else
766 {
767 if (NewDepends(Ver,Package,pkgArch,Version,Op,Type) == false)
768 return false;
769 if ((Type == pkgCache::Dep::Conflicts ||
770 Type == pkgCache::Dep::DpkgBreaks ||
771 Type == pkgCache::Dep::Replaces) &&
772 NewDepends(Ver, Package,
773 (pkgArch != "none") ? "none" : _config->Find("APT::Architecture"),
774 Version,Op,Type) == false)
775 return false;
776 }
777 if (Start == Stop)
778 break;
779 }
780 return true;
781 }
782 /*}}}*/
783 // ListParser::ParseProvides - Parse the provides list /*{{{*/
784 // ---------------------------------------------------------------------
785 /* */
786 bool debListParser::ParseProvides(pkgCache::VerIterator &Ver)
787 {
788 const char *Start;
789 const char *Stop;
790 if (Section.Find("Provides",Start,Stop) == true)
791 {
792 string Package;
793 string Version;
794 string const Arch = Ver.Arch();
795 unsigned int Op;
796
797 while (1)
798 {
799 Start = ParseDepends(Start,Stop,Package,Version,Op);
800 if (Start == 0)
801 return _error->Error("Problem parsing Provides line");
802 if (Op != pkgCache::Dep::NoOp) {
803 _error->Warning("Ignoring Provides line with DepCompareOp for package %s", Package.c_str());
804 } else if ((Ver->MultiArch & pkgCache::Version::Foreign) == pkgCache::Version::Foreign) {
805 if (NewProvidesAllArch(Ver, Package, Version) == false)
806 return false;
807 } else {
808 if (NewProvides(Ver, Package, Arch, Version) == false)
809 return false;
810 }
811
812 if (Start == Stop)
813 break;
814 }
815 }
816
817 if ((Ver->MultiArch & pkgCache::Version::Allowed) == pkgCache::Version::Allowed)
818 {
819 string const Package = string(Ver.ParentPkg().Name()).append(":").append("any");
820 return NewProvidesAllArch(Ver, Package, Ver.VerStr());
821 }
822 else if ((Ver->MultiArch & pkgCache::Version::Foreign) == pkgCache::Version::Foreign)
823 return NewProvidesAllArch(Ver, Ver.ParentPkg().Name(), Ver.VerStr());
824
825 return true;
826 }
827 /*}}}*/
828 // ListParser::NewProvides - add provides for all architectures /*{{{*/
829 bool debListParser::NewProvidesAllArch(pkgCache::VerIterator &Ver, string const &Package,
830 string const &Version) {
831 for (std::vector<string>::const_iterator a = Architectures.begin();
832 a != Architectures.end(); ++a)
833 {
834 if (NewProvides(Ver, Package, *a, Version) == false)
835 return false;
836 }
837 return true;
838 }
839 /*}}}*/
840 // ListParser::GrabWord - Matches a word and returns /*{{{*/
841 // ---------------------------------------------------------------------
842 /* Looks for a word in a list of words - for ParseStatus */
843 bool debListParser::GrabWord(string Word,WordList *List,unsigned char &Out)
844 {
845 for (unsigned int C = 0; List[C].Str != 0; C++)
846 {
847 if (strcasecmp(Word.c_str(),List[C].Str) == 0)
848 {
849 Out = List[C].Val;
850 return true;
851 }
852 }
853 return false;
854 }
855 /*}}}*/
856 // ListParser::Step - Move to the next section in the file /*{{{*/
857 // ---------------------------------------------------------------------
858 /* This has to be careful to only process the correct architecture */
859 bool debListParser::Step()
860 {
861 iOffset = Tags.Offset();
862 while (Tags.Step(Section) == true)
863 {
864 /* See if this is the correct Architecture, if it isn't then we
865 drop the whole section. A missing arch tag only happens (in theory)
866 inside the Status file, so that is a positive return */
867 string const Architecture = Section.FindS("Architecture");
868
869 if (Arch.empty() == true || Arch == "any" || MultiArchEnabled == false)
870 {
871 if (APT::Configuration::checkArchitecture(Architecture) == true)
872 return true;
873 /* parse version stanzas without an architecture only in the status file
874 (and as misfortune bycatch flat-archives) */
875 if ((Arch.empty() == true || Arch == "any") && Architecture.empty() == true)
876 return true;
877 }
878 else
879 {
880 if (Architecture == Arch)
881 return true;
882
883 if (Architecture == "all" && Arch == _config->Find("APT::Architecture"))
884 return true;
885 }
886
887 iOffset = Tags.Offset();
888 }
889 return false;
890 }
891 /*}}}*/
892 // ListParser::LoadReleaseInfo - Load the release information /*{{{*/
893 // ---------------------------------------------------------------------
894 /* */
895 bool debListParser::LoadReleaseInfo(pkgCache::PkgFileIterator &FileI,
896 FileFd &File, string component)
897 {
898 // apt-secure does no longer download individual (per-section) Release
899 // file. to provide Component pinning we use the section name now
900 map_ptrloc const storage = WriteUniqString(component);
901 FileI->Component = storage;
902
903 pkgTagFile TagFile(&File, File.Size());
904 pkgTagSection Section;
905 if (_error->PendingError() == true || TagFile.Step(Section) == false)
906 return false;
907
908 std::string data;
909 #define APT_INRELEASE(TAG, STORE) \
910 data = Section.FindS(TAG); \
911 if (data.empty() == false) \
912 { \
913 map_ptrloc const storage = WriteUniqString(data); \
914 STORE = storage; \
915 }
916 APT_INRELEASE("Suite", FileI->Archive)
917 APT_INRELEASE("Component", FileI->Component)
918 APT_INRELEASE("Version", FileI->Version)
919 APT_INRELEASE("Origin", FileI->Origin)
920 APT_INRELEASE("Codename", FileI->Codename)
921 APT_INRELEASE("Label", FileI->Label)
922 #undef APT_INRELEASE
923 Section.FindFlag("NotAutomatic", FileI->Flags, pkgCache::Flag::NotAutomatic);
924 Section.FindFlag("ButAutomaticUpgrades", FileI->Flags, pkgCache::Flag::ButAutomaticUpgrades);
925
926 return !_error->PendingError();
927 }
928 /*}}}*/
929 // ListParser::GetPrio - Convert the priority from a string /*{{{*/
930 // ---------------------------------------------------------------------
931 /* */
932 unsigned char debListParser::GetPrio(string Str)
933 {
934 unsigned char Out;
935 if (GrabWord(Str,PrioList,Out) == false)
936 Out = pkgCache::State::Extra;
937
938 return Out;
939 }
940 /*}}}*/
941 #if (APT_PKG_MAJOR >= 4 && APT_PKG_MINOR >= 13)
942 bool debListParser::SameVersion(unsigned short const Hash, /*{{{*/
943 pkgCache::VerIterator const &Ver)
944 {
945 if (pkgCacheGenerator::ListParser::SameVersion(Hash, Ver) == false)
946 return false;
947 // status file has no (Download)Size, but all others are fair game
948 // status file is parsed last, so the first version we encounter is
949 // probably also the version we have downloaded
950 unsigned long long const Size = Section.FindULL("Size");
951 if (Size != 0 && Size != Ver->Size)
952 return false;
953 // available everywhere, but easier to check here than to include in VersionHash
954 unsigned char MultiArch = ParseMultiArch(false);
955 if (MultiArch != Ver->MultiArch)
956 return false;
957 // for all practical proposes (we can check): same version
958 return true;
959 }
960 /*}}}*/
961 #endif