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