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