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