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