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