]> git.saurik.com Git - apt.git/blob - apt-pkg/deb/deblistparser.cc
12c6ab4c9ee7f697abdf5b9474439665029866f4
[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/macros.h>
25
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 string const static myArch = _config->Find("APT::Architecture");
247 // Possible values are: "all", "native", "installed" and "none"
248 // The "installed" mode is handled by ParseStatus(), See #544481 and friends.
249 string const static essential = _config->Find("pkgCacheGen::Essential", "all");
250 if (essential == "all" ||
251 (essential == "native" && Pkg->Arch != 0 && myArch == Pkg.Arch()))
252 if (Section.FindFlag("Essential",Pkg->Flags,pkgCache::Flag::Essential) == false)
253 return false;
254 if (Section.FindFlag("Important",Pkg->Flags,pkgCache::Flag::Important) == false)
255 return false;
256
257 if (strcmp(Pkg.Name(),"apt") == 0)
258 {
259 if ((essential == "native" && Pkg->Arch != 0 && myArch == Pkg.Arch()) ||
260 essential == "all")
261 Pkg->Flags |= pkgCache::Flag::Essential | pkgCache::Flag::Important;
262 else
263 Pkg->Flags |= pkgCache::Flag::Important;
264 }
265
266 if (ParseStatus(Pkg,Ver) == false)
267 return false;
268 return true;
269 }
270 /*}}}*/
271 // ListParser::VersionHash - Compute a unique hash for this version /*{{{*/
272 // ---------------------------------------------------------------------
273 /* */
274 unsigned short debListParser::VersionHash()
275 {
276 const char *Sections[] ={"Installed-Size",
277 "Depends",
278 "Pre-Depends",
279 // "Suggests",
280 // "Recommends",
281 "Conflicts",
282 "Breaks",
283 "Replaces",0};
284 unsigned long Result = INIT_FCS;
285 char S[1024];
286 for (const char **I = Sections; *I != 0; I++)
287 {
288 const char *Start;
289 const char *End;
290 if (Section.Find(*I,Start,End) == false || End - Start >= (signed)sizeof(S))
291 continue;
292
293 /* Strip out any spaces from the text, this undoes dpkgs reformatting
294 of certain fields. dpkg also has the rather interesting notion of
295 reformatting depends operators < -> <= */
296 char *J = S;
297 for (; Start != End; Start++)
298 {
299 if (isspace(*Start) == 0)
300 *J++ = tolower_ascii(*Start);
301 if (*Start == '<' && Start[1] != '<' && Start[1] != '=')
302 *J++ = '=';
303 if (*Start == '>' && Start[1] != '>' && Start[1] != '=')
304 *J++ = '=';
305 }
306
307 Result = AddCRC16(Result,S,J - S);
308 }
309
310 return Result;
311 }
312 /*}}}*/
313 // ListParser::ParseStatus - Parse the status field /*{{{*/
314 // ---------------------------------------------------------------------
315 /* Status lines are of the form,
316 Status: want flag status
317 want = unknown, install, hold, deinstall, purge
318 flag = ok, reinstreq, hold, hold-reinstreq
319 status = not-installed, unpacked, half-configured,
320 half-installed, config-files, post-inst-failed,
321 removal-failed, installed
322
323 Some of the above are obsolete (I think?) flag = hold-* and
324 status = post-inst-failed, removal-failed at least.
325 */
326 bool debListParser::ParseStatus(pkgCache::PkgIterator &Pkg,
327 pkgCache::VerIterator &Ver)
328 {
329 const char *Start;
330 const char *Stop;
331 if (Section.Find("Status",Start,Stop) == false)
332 return true;
333
334 // UsePackage() is responsible for setting the flag in the default case
335 bool const static essential = _config->Find("pkgCacheGen::Essential", "") == "installed";
336 if (essential == true &&
337 Section.FindFlag("Essential",Pkg->Flags,pkgCache::Flag::Essential) == false)
338 return false;
339
340 // Isolate the first word
341 const char *I = Start;
342 for(; I < Stop && *I != ' '; I++);
343 if (I >= Stop || *I != ' ')
344 return _error->Error("Malformed Status line");
345
346 // Process the want field
347 WordList WantList[] = {{"unknown",pkgCache::State::Unknown},
348 {"install",pkgCache::State::Install},
349 {"hold",pkgCache::State::Hold},
350 {"deinstall",pkgCache::State::DeInstall},
351 {"purge",pkgCache::State::Purge},
352 {}};
353 if (GrabWord(string(Start,I-Start),WantList,Pkg->SelectedState) == false)
354 return _error->Error("Malformed 1st word in the Status line");
355
356 // Isloate the next word
357 I++;
358 Start = I;
359 for(; I < Stop && *I != ' '; I++);
360 if (I >= Stop || *I != ' ')
361 return _error->Error("Malformed status line, no 2nd word");
362
363 // Process the flag field
364 WordList FlagList[] = {{"ok",pkgCache::State::Ok},
365 {"reinstreq",pkgCache::State::ReInstReq},
366 {"hold",pkgCache::State::HoldInst},
367 {"hold-reinstreq",pkgCache::State::HoldReInstReq},
368 {}};
369 if (GrabWord(string(Start,I-Start),FlagList,Pkg->InstState) == false)
370 return _error->Error("Malformed 2nd word in the Status line");
371
372 // Isloate the last word
373 I++;
374 Start = I;
375 for(; I < Stop && *I != ' '; I++);
376 if (I != Stop)
377 return _error->Error("Malformed Status line, no 3rd word");
378
379 // Process the flag field
380 WordList StatusList[] = {{"not-installed",pkgCache::State::NotInstalled},
381 {"unpacked",pkgCache::State::UnPacked},
382 {"half-configured",pkgCache::State::HalfConfigured},
383 {"installed",pkgCache::State::Installed},
384 {"half-installed",pkgCache::State::HalfInstalled},
385 {"config-files",pkgCache::State::ConfigFiles},
386 {"triggers-awaited",pkgCache::State::TriggersAwaited},
387 {"triggers-pending",pkgCache::State::TriggersPending},
388 {"post-inst-failed",pkgCache::State::HalfConfigured},
389 {"removal-failed",pkgCache::State::HalfInstalled},
390 {}};
391 if (GrabWord(string(Start,I-Start),StatusList,Pkg->CurrentState) == false)
392 return _error->Error("Malformed 3rd word in the Status line");
393
394 /* A Status line marks the package as indicating the current
395 version as well. Only if it is actually installed.. Otherwise
396 the interesting dpkg handling of the status file creates bogus
397 entries. */
398 if (!(Pkg->CurrentState == pkgCache::State::NotInstalled ||
399 Pkg->CurrentState == pkgCache::State::ConfigFiles))
400 {
401 if (Ver.end() == true)
402 _error->Warning("Encountered status field in a non-version description");
403 else
404 Pkg->CurrentVer = Ver.Index();
405 }
406
407 return true;
408 }
409
410 const char *debListParser::ConvertRelation(const char *I,unsigned int &Op)
411 {
412 // Determine the operator
413 switch (*I)
414 {
415 case '<':
416 I++;
417 if (*I == '=')
418 {
419 I++;
420 Op = pkgCache::Dep::LessEq;
421 break;
422 }
423
424 if (*I == '<')
425 {
426 I++;
427 Op = pkgCache::Dep::Less;
428 break;
429 }
430
431 // < is the same as <= and << is really Cs < for some reason
432 Op = pkgCache::Dep::LessEq;
433 break;
434
435 case '>':
436 I++;
437 if (*I == '=')
438 {
439 I++;
440 Op = pkgCache::Dep::GreaterEq;
441 break;
442 }
443
444 if (*I == '>')
445 {
446 I++;
447 Op = pkgCache::Dep::Greater;
448 break;
449 }
450
451 // > is the same as >= and >> is really Cs > for some reason
452 Op = pkgCache::Dep::GreaterEq;
453 break;
454
455 case '=':
456 Op = pkgCache::Dep::Equals;
457 I++;
458 break;
459
460 // HACK around bad package definitions
461 default:
462 Op = pkgCache::Dep::Equals;
463 break;
464 }
465 return I;
466 }
467 /*}}}*/
468 // ListParser::ParseDepends - Parse a dependency element /*{{{*/
469 // ---------------------------------------------------------------------
470 /* This parses the dependency elements out of a standard string in place,
471 bit by bit. */
472 const char *debListParser::ParseDepends(const char *Start,const char *Stop,
473 string &Package,string &Ver,
474 unsigned int &Op, bool const &ParseArchFlags,
475 bool const &StripMultiArch)
476 {
477 // Strip off leading space
478 for (;Start != Stop && isspace(*Start) != 0; Start++);
479
480 // Parse off the package name
481 const char *I = Start;
482 for (;I != Stop && isspace(*I) == 0 && *I != '(' && *I != ')' &&
483 *I != ',' && *I != '|' && *I != '[' && *I != ']'; I++);
484
485 // Malformed, no '('
486 if (I != Stop && *I == ')')
487 return 0;
488
489 if (I == Start)
490 return 0;
491
492 // Stash the package name
493 Package.assign(Start,I - Start);
494
495 // We don't want to confuse library users which can't handle MultiArch
496 string const arch = _config->Find("APT::Architecture");
497 if (StripMultiArch == true) {
498 size_t const found = Package.rfind(':');
499 if (found != string::npos &&
500 (strcmp(Package.c_str() + found, ":any") == 0 ||
501 strcmp(Package.c_str() + found, ":native") == 0 ||
502 strcmp(Package.c_str() + found + 1, arch.c_str()) == 0))
503 Package = Package.substr(0,found);
504 }
505
506 // Skip white space to the '('
507 for (;I != Stop && isspace(*I) != 0 ; I++);
508
509 // Parse a version
510 if (I != Stop && *I == '(')
511 {
512 // Skip the '('
513 for (I++; I != Stop && isspace(*I) != 0 ; I++);
514 if (I + 3 >= Stop)
515 return 0;
516 I = ConvertRelation(I,Op);
517
518 // Skip whitespace
519 for (;I != Stop && isspace(*I) != 0; I++);
520 Start = I;
521 I = (const char*) memchr(I, ')', Stop - I);
522 if (I == NULL || Start == I)
523 return 0;
524
525 // Skip trailing whitespace
526 const char *End = I;
527 for (; End > Start && isspace(End[-1]); End--);
528
529 Ver.assign(Start,End-Start);
530 I++;
531 }
532 else
533 {
534 Ver.clear();
535 Op = pkgCache::Dep::NoOp;
536 }
537
538 // Skip whitespace
539 for (;I != Stop && isspace(*I) != 0; I++);
540
541 if (ParseArchFlags == true)
542 {
543 APT::CacheFilter::PackageArchitectureMatchesSpecification matchesArch(arch, false);
544
545 // Parse an architecture
546 if (I != Stop && *I == '[')
547 {
548 ++I;
549 // malformed
550 if (unlikely(I == Stop))
551 return 0;
552
553 const char *End = I;
554 bool Found = false;
555 bool NegArch = false;
556 while (I != Stop)
557 {
558 // look for whitespace or ending ']'
559 for (;End != Stop && !isspace(*End) && *End != ']'; ++End);
560
561 if (unlikely(End == Stop))
562 return 0;
563
564 if (*I == '!')
565 {
566 NegArch = true;
567 ++I;
568 }
569
570 std::string arch(I, End);
571 if (arch.empty() == false && matchesArch(arch.c_str()) == true)
572 {
573 Found = true;
574 if (I[-1] != '!')
575 NegArch = false;
576 // we found a match, so fast-forward to the end of the wildcards
577 for (; End != Stop && *End != ']'; ++End);
578 }
579
580 if (*End++ == ']') {
581 I = End;
582 break;
583 }
584
585 I = End;
586 for (;I != Stop && isspace(*I) != 0; I++);
587 }
588
589 if (NegArch == true)
590 Found = !Found;
591
592 if (Found == false)
593 Package = ""; /* not for this arch */
594 }
595
596 // Skip whitespace
597 for (;I != Stop && isspace(*I) != 0; I++);
598 }
599
600 if (I != Stop && *I == '|')
601 Op |= pkgCache::Dep::Or;
602
603 if (I == Stop || *I == ',' || *I == '|')
604 {
605 if (I != Stop)
606 for (I++; I != Stop && isspace(*I) != 0; I++);
607 return I;
608 }
609
610 return 0;
611 }
612 /*}}}*/
613 // ListParser::ParseDepends - Parse a dependency list /*{{{*/
614 // ---------------------------------------------------------------------
615 /* This is the higher level depends parser. It takes a tag and generates
616 a complete depends tree for the given version. */
617 bool debListParser::ParseDepends(pkgCache::VerIterator &Ver,
618 const char *Tag,unsigned int Type)
619 {
620 const char *Start;
621 const char *Stop;
622 if (Section.Find(Tag,Start,Stop) == false)
623 return true;
624
625 string const pkgArch = Ver.Arch();
626
627 while (1)
628 {
629 string Package;
630 string Version;
631 unsigned int Op;
632
633 Start = ParseDepends(Start,Stop,Package,Version,Op,false,!MultiArchEnabled);
634 if (Start == 0)
635 return _error->Error("Problem parsing dependency %s",Tag);
636 size_t const found = Package.rfind(':');
637
638 // If negative is unspecific it needs to apply on all architectures
639 if (MultiArchEnabled == true && found == string::npos &&
640 (Type == pkgCache::Dep::Conflicts ||
641 Type == pkgCache::Dep::DpkgBreaks ||
642 Type == pkgCache::Dep::Replaces))
643 {
644 for (std::vector<std::string>::const_iterator a = Architectures.begin();
645 a != Architectures.end(); ++a)
646 if (NewDepends(Ver,Package,*a,Version,Op,Type) == false)
647 return false;
648 }
649 else if (MultiArchEnabled == true && found != string::npos &&
650 strcmp(Package.c_str() + found, ":any") != 0)
651 {
652 string Arch = Package.substr(found+1, string::npos);
653 Package = Package.substr(0, found);
654 // Such dependencies are not supposed to be accepted …
655 // … but this is probably the best thing to do.
656 if (Arch == "native")
657 Arch = _config->Find("APT::Architecture");
658 if (NewDepends(Ver,Package,Arch,Version,Op,Type) == false)
659 return false;
660 }
661 else if (NewDepends(Ver,Package,pkgArch,Version,Op,Type) == false)
662 return false;
663 if (Start == Stop)
664 break;
665 }
666 return true;
667 }
668 /*}}}*/
669 // ListParser::ParseProvides - Parse the provides list /*{{{*/
670 // ---------------------------------------------------------------------
671 /* */
672 bool debListParser::ParseProvides(pkgCache::VerIterator &Ver)
673 {
674 const char *Start;
675 const char *Stop;
676 if (Section.Find("Provides",Start,Stop) == true)
677 {
678 string Package;
679 string Version;
680 string const Arch = Ver.Arch();
681 unsigned int Op;
682
683 while (1)
684 {
685 Start = ParseDepends(Start,Stop,Package,Version,Op);
686 if (Start == 0)
687 return _error->Error("Problem parsing Provides line");
688 if (Op != pkgCache::Dep::NoOp) {
689 _error->Warning("Ignoring Provides line with DepCompareOp for package %s", Package.c_str());
690 } else if ((Ver->MultiArch & pkgCache::Version::Foreign) == pkgCache::Version::Foreign) {
691 if (NewProvidesAllArch(Ver, Package, Version) == false)
692 return false;
693 } else {
694 if (NewProvides(Ver, Package, Arch, Version) == false)
695 return false;
696 }
697
698 if (Start == Stop)
699 break;
700 }
701 }
702
703 if (MultiArchEnabled == false)
704 return true;
705 else if ((Ver->MultiArch & pkgCache::Version::Allowed) == pkgCache::Version::Allowed)
706 {
707 string const Package = string(Ver.ParentPkg().Name()).append(":").append("any");
708 return NewProvidesAllArch(Ver, Package, Ver.VerStr());
709 }
710 else if ((Ver->MultiArch & pkgCache::Version::Foreign) == pkgCache::Version::Foreign)
711 return NewProvidesAllArch(Ver, Ver.ParentPkg().Name(), Ver.VerStr());
712
713 return true;
714 }
715 /*}}}*/
716 // ListParser::NewProvides - add provides for all architectures /*{{{*/
717 bool debListParser::NewProvidesAllArch(pkgCache::VerIterator &Ver, string const &Package,
718 string const &Version) {
719 for (std::vector<string>::const_iterator a = Architectures.begin();
720 a != Architectures.end(); ++a)
721 {
722 if (NewProvides(Ver, Package, *a, Version) == false)
723 return false;
724 }
725 return true;
726 }
727 /*}}}*/
728 // ListParser::GrabWord - Matches a word and returns /*{{{*/
729 // ---------------------------------------------------------------------
730 /* Looks for a word in a list of words - for ParseStatus */
731 bool debListParser::GrabWord(string Word,WordList *List,unsigned char &Out)
732 {
733 for (unsigned int C = 0; List[C].Str != 0; C++)
734 {
735 if (strcasecmp(Word.c_str(),List[C].Str) == 0)
736 {
737 Out = List[C].Val;
738 return true;
739 }
740 }
741 return false;
742 }
743 /*}}}*/
744 // ListParser::Step - Move to the next section in the file /*{{{*/
745 // ---------------------------------------------------------------------
746 /* This has to be carefull to only process the correct architecture */
747 bool debListParser::Step()
748 {
749 iOffset = Tags.Offset();
750 while (Tags.Step(Section) == true)
751 {
752 /* See if this is the correct Architecture, if it isn't then we
753 drop the whole section. A missing arch tag only happens (in theory)
754 inside the Status file, so that is a positive return */
755 string const Architecture = Section.FindS("Architecture");
756 if (Architecture.empty() == true)
757 return true;
758
759 if (Arch.empty() == true || Arch == "any" || MultiArchEnabled == false)
760 {
761 if (APT::Configuration::checkArchitecture(Architecture) == true)
762 return true;
763 }
764 else
765 {
766 if (Architecture == Arch)
767 return true;
768
769 if (Architecture == "all" && Arch == _config->Find("APT::Architecture"))
770 return true;
771 }
772
773 iOffset = Tags.Offset();
774 }
775 return false;
776 }
777 /*}}}*/
778 // ListParser::LoadReleaseInfo - Load the release information /*{{{*/
779 // ---------------------------------------------------------------------
780 /* */
781 bool debListParser::LoadReleaseInfo(pkgCache::PkgFileIterator &FileI,
782 FileFd &File, string component)
783 {
784 // apt-secure does no longer download individual (per-section) Release
785 // file. to provide Component pinning we use the section name now
786 map_ptrloc const storage = WriteUniqString(component);
787 FileI->Component = storage;
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 map_ptrloc const storage = WriteUniqString(data);
875 switch (writeTo) {
876 case Suite: FileI->Archive = storage; break;
877 case Component: FileI->Component = storage; break;
878 case Version: FileI->Version = storage; break;
879 case Origin: FileI->Origin = storage; break;
880 case Codename: FileI->Codename = storage; break;
881 case Label: FileI->Label = storage; break;
882 case None: break;
883 }
884 }
885 }
886 fclose(release);
887
888 return !_error->PendingError();
889 }
890 /*}}}*/
891 // ListParser::GetPrio - Convert the priority from a string /*{{{*/
892 // ---------------------------------------------------------------------
893 /* */
894 unsigned char debListParser::GetPrio(string Str)
895 {
896 unsigned char Out;
897 if (GrabWord(Str,PrioList,Out) == false)
898 Out = pkgCache::State::Extra;
899
900 return Out;
901 }
902 /*}}}*/