* apt-pkg/deb/deblistparser.cc:
[ntk/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 value = Section.FindS("Description-md5");
219
220 if (value.empty())
221 {
222 MD5Summation md5;
223 md5.Add((Description() + "\n").c_str());
224 return md5.Result();
225 } else
226 return MD5SumValue(value);
227 }
228 /*}}}*/
229 // ListParser::UsePackage - Update a package structure /*{{{*/
230 // ---------------------------------------------------------------------
231 /* This is called to update the package with any new information
232 that might be found in the section */
233 bool debListParser::UsePackage(pkgCache::PkgIterator &Pkg,
234 pkgCache::VerIterator &Ver)
235 {
236 if (Pkg->Section == 0)
237 Pkg->Section = UniqFindTagWrite("Section");
238
239 // Packages which are not from the "native" arch doesn't get the essential flag
240 // in the default "native" mode - it is also possible to mark "all" or "none".
241 // The "installed" mode is handled by ParseStatus(), See #544481 and friends.
242 string const static myArch = _config->Find("APT::Architecture");
243 string const static essential = _config->Find("pkgCacheGen::Essential", "native");
244 if ((essential == "native" && Pkg->Arch != 0 && myArch == Pkg.Arch()) ||
245 essential == "all")
246 if (Section.FindFlag("Essential",Pkg->Flags,pkgCache::Flag::Essential) == false)
247 return false;
248 if (Section.FindFlag("Important",Pkg->Flags,pkgCache::Flag::Important) == false)
249 return false;
250
251 if (strcmp(Pkg.Name(),"apt") == 0)
252 {
253 if ((essential == "native" && Pkg->Arch != 0 && myArch == Pkg.Arch()) ||
254 essential == "all")
255 Pkg->Flags |= pkgCache::Flag::Essential | pkgCache::Flag::Important;
256 else
257 Pkg->Flags |= pkgCache::Flag::Important;
258 }
259
260 if (ParseStatus(Pkg,Ver) == false)
261 return false;
262 return true;
263 }
264 /*}}}*/
265 // ListParser::VersionHash - Compute a unique hash for this version /*{{{*/
266 // ---------------------------------------------------------------------
267 /* */
268 unsigned short debListParser::VersionHash()
269 {
270 const char *Sections[] ={"Installed-Size",
271 "Depends",
272 "Pre-Depends",
273 // "Suggests",
274 // "Recommends",
275 "Conflicts",
276 "Breaks",
277 "Replaces",0};
278 unsigned long Result = INIT_FCS;
279 char S[1024];
280 for (const char **I = Sections; *I != 0; I++)
281 {
282 const char *Start;
283 const char *End;
284 if (Section.Find(*I,Start,End) == false || End - Start >= (signed)sizeof(S))
285 continue;
286
287 /* Strip out any spaces from the text, this undoes dpkgs reformatting
288 of certain fields. dpkg also has the rather interesting notion of
289 reformatting depends operators < -> <= */
290 char *J = S;
291 for (; Start != End; Start++)
292 {
293 if (isspace(*Start) == 0)
294 *J++ = tolower_ascii(*Start);
295 if (*Start == '<' && Start[1] != '<' && Start[1] != '=')
296 *J++ = '=';
297 if (*Start == '>' && Start[1] != '>' && Start[1] != '=')
298 *J++ = '=';
299 }
300
301 Result = AddCRC16(Result,S,J - S);
302 }
303
304 return Result;
305 }
306 /*}}}*/
307 // ListParser::ParseStatus - Parse the status field /*{{{*/
308 // ---------------------------------------------------------------------
309 /* Status lines are of the form,
310 Status: want flag status
311 want = unknown, install, hold, deinstall, purge
312 flag = ok, reinstreq, hold, hold-reinstreq
313 status = not-installed, unpacked, half-configured,
314 half-installed, config-files, post-inst-failed,
315 removal-failed, installed
316
317 Some of the above are obsolete (I think?) flag = hold-* and
318 status = post-inst-failed, removal-failed at least.
319 */
320 bool debListParser::ParseStatus(pkgCache::PkgIterator &Pkg,
321 pkgCache::VerIterator &Ver)
322 {
323 const char *Start;
324 const char *Stop;
325 if (Section.Find("Status",Start,Stop) == false)
326 return true;
327
328 // UsePackage() is responsible for setting the flag in the default case
329 bool const static essential = _config->Find("pkgCacheGen::Essential", "") == "installed";
330 if (essential == true &&
331 Section.FindFlag("Essential",Pkg->Flags,pkgCache::Flag::Essential) == false)
332 return false;
333
334 // Isolate the first word
335 const char *I = Start;
336 for(; I < Stop && *I != ' '; I++);
337 if (I >= Stop || *I != ' ')
338 return _error->Error("Malformed Status line");
339
340 // Process the want field
341 WordList WantList[] = {{"unknown",pkgCache::State::Unknown},
342 {"install",pkgCache::State::Install},
343 {"hold",pkgCache::State::Hold},
344 {"deinstall",pkgCache::State::DeInstall},
345 {"purge",pkgCache::State::Purge},
346 {}};
347 if (GrabWord(string(Start,I-Start),WantList,Pkg->SelectedState) == false)
348 return _error->Error("Malformed 1st word in the Status line");
349
350 // Isloate the next word
351 I++;
352 Start = I;
353 for(; I < Stop && *I != ' '; I++);
354 if (I >= Stop || *I != ' ')
355 return _error->Error("Malformed status line, no 2nd word");
356
357 // Process the flag field
358 WordList FlagList[] = {{"ok",pkgCache::State::Ok},
359 {"reinstreq",pkgCache::State::ReInstReq},
360 {"hold",pkgCache::State::HoldInst},
361 {"hold-reinstreq",pkgCache::State::HoldReInstReq},
362 {}};
363 if (GrabWord(string(Start,I-Start),FlagList,Pkg->InstState) == false)
364 return _error->Error("Malformed 2nd word in the Status line");
365
366 // Isloate the last word
367 I++;
368 Start = I;
369 for(; I < Stop && *I != ' '; I++);
370 if (I != Stop)
371 return _error->Error("Malformed Status line, no 3rd word");
372
373 // Process the flag field
374 WordList StatusList[] = {{"not-installed",pkgCache::State::NotInstalled},
375 {"unpacked",pkgCache::State::UnPacked},
376 {"half-configured",pkgCache::State::HalfConfigured},
377 {"installed",pkgCache::State::Installed},
378 {"half-installed",pkgCache::State::HalfInstalled},
379 {"config-files",pkgCache::State::ConfigFiles},
380 {"triggers-awaited",pkgCache::State::TriggersAwaited},
381 {"triggers-pending",pkgCache::State::TriggersPending},
382 {"post-inst-failed",pkgCache::State::HalfConfigured},
383 {"removal-failed",pkgCache::State::HalfInstalled},
384 {}};
385 if (GrabWord(string(Start,I-Start),StatusList,Pkg->CurrentState) == false)
386 return _error->Error("Malformed 3rd word in the Status line");
387
388 /* A Status line marks the package as indicating the current
389 version as well. Only if it is actually installed.. Otherwise
390 the interesting dpkg handling of the status file creates bogus
391 entries. */
392 if (!(Pkg->CurrentState == pkgCache::State::NotInstalled ||
393 Pkg->CurrentState == pkgCache::State::ConfigFiles))
394 {
395 if (Ver.end() == true)
396 _error->Warning("Encountered status field in a non-version description");
397 else
398 Pkg->CurrentVer = Ver.Index();
399 }
400
401 return true;
402 }
403
404 const char *debListParser::ConvertRelation(const char *I,unsigned int &Op)
405 {
406 // Determine the operator
407 switch (*I)
408 {
409 case '<':
410 I++;
411 if (*I == '=')
412 {
413 I++;
414 Op = pkgCache::Dep::LessEq;
415 break;
416 }
417
418 if (*I == '<')
419 {
420 I++;
421 Op = pkgCache::Dep::Less;
422 break;
423 }
424
425 // < is the same as <= and << is really Cs < for some reason
426 Op = pkgCache::Dep::LessEq;
427 break;
428
429 case '>':
430 I++;
431 if (*I == '=')
432 {
433 I++;
434 Op = pkgCache::Dep::GreaterEq;
435 break;
436 }
437
438 if (*I == '>')
439 {
440 I++;
441 Op = pkgCache::Dep::Greater;
442 break;
443 }
444
445 // > is the same as >= and >> is really Cs > for some reason
446 Op = pkgCache::Dep::GreaterEq;
447 break;
448
449 case '=':
450 Op = pkgCache::Dep::Equals;
451 I++;
452 break;
453
454 // HACK around bad package definitions
455 default:
456 Op = pkgCache::Dep::Equals;
457 break;
458 }
459 return I;
460 }
461
462 /*
463 * CompleteArch:
464 *
465 * The complete architecture, consisting of <kernel>-<cpu>.
466 */
467 static string CompleteArch(std::string const &arch) {
468 if (arch == "armel") return "linux-arm";
469 if (arch == "armhf") return "linux-arm";
470 if (arch == "lpia") return "linux-i386";
471 if (arch == "powerpcspe") return "linux-powerpc";
472 if (arch == "uclibc-linux-armel") return "linux-arm";
473 if (arch == "uclinux-armel") return "uclinux-arm";
474
475 return (arch.find("-") != string::npos) ? arch : "linux-" + arch;
476 }
477 /*}}}*/
478 // ListParser::ParseDepends - Parse a dependency element /*{{{*/
479 // ---------------------------------------------------------------------
480 /* This parses the dependency elements out of a standard string in place,
481 bit by bit. */
482 const char *debListParser::ParseDepends(const char *Start,const char *Stop,
483 string &Package,string &Ver,
484 unsigned int &Op, bool const &ParseArchFlags,
485 bool const &StripMultiArch)
486 {
487 // Strip off leading space
488 for (;Start != Stop && isspace(*Start) != 0; Start++);
489
490 // Parse off the package name
491 const char *I = Start;
492 for (;I != Stop && isspace(*I) == 0 && *I != '(' && *I != ')' &&
493 *I != ',' && *I != '|' && *I != '[' && *I != ']'; I++);
494
495 // Malformed, no '('
496 if (I != Stop && *I == ')')
497 return 0;
498
499 if (I == Start)
500 return 0;
501
502 // Stash the package name
503 Package.assign(Start,I - Start);
504
505 // We don't want to confuse library users which can't handle MultiArch
506 string const arch = _config->Find("APT::Architecture");
507 if (StripMultiArch == true) {
508 size_t const found = Package.rfind(':');
509 if (found != string::npos &&
510 (strcmp(Package.c_str() + found, ":any") == 0 ||
511 strcmp(Package.c_str() + found, ":native") == 0 ||
512 strcmp(Package.c_str() + found + 1, arch.c_str()) == 0))
513 Package = Package.substr(0,found);
514 }
515
516 // Skip white space to the '('
517 for (;I != Stop && isspace(*I) != 0 ; I++);
518
519 // Parse a version
520 if (I != Stop && *I == '(')
521 {
522 // Skip the '('
523 for (I++; I != Stop && isspace(*I) != 0 ; I++);
524 if (I + 3 >= Stop)
525 return 0;
526 I = ConvertRelation(I,Op);
527
528 // Skip whitespace
529 for (;I != Stop && isspace(*I) != 0; I++);
530 Start = I;
531 I = (const char*) memchr(I, ')', Stop - I);
532 if (I == NULL || Start == I)
533 return 0;
534
535 // Skip trailing whitespace
536 const char *End = I;
537 for (; End > Start && isspace(End[-1]); End--);
538
539 Ver.assign(Start,End-Start);
540 I++;
541 }
542 else
543 {
544 Ver.clear();
545 Op = pkgCache::Dep::NoOp;
546 }
547
548 // Skip whitespace
549 for (;I != Stop && isspace(*I) != 0; I++);
550
551 if (ParseArchFlags == true)
552 {
553 string completeArch = CompleteArch(arch);
554
555 // Parse an architecture
556 if (I != Stop && *I == '[')
557 {
558 // malformed
559 I++;
560 if (I == Stop)
561 return 0;
562
563 const char *End = I;
564 bool Found = false;
565 bool NegArch = false;
566 while (I != Stop)
567 {
568 // look for whitespace or ending ']'
569 while (End != Stop && !isspace(*End) && *End != ']')
570 End++;
571
572 if (End == Stop)
573 return 0;
574
575 if (*I == '!')
576 {
577 NegArch = true;
578 I++;
579 }
580
581 if (stringcmp(arch,I,End) == 0) {
582 Found = true;
583 } else {
584 std::string wildcard = SubstVar(string(I, End), "any", "*");
585 if (fnmatch(wildcard.c_str(), completeArch.c_str(), 0) == 0)
586 Found = true;
587 }
588
589 if (*End++ == ']') {
590 I = End;
591 break;
592 }
593
594 I = End;
595 for (;I != Stop && isspace(*I) != 0; I++);
596 }
597
598 if (NegArch)
599 Found = !Found;
600
601 if (Found == false)
602 Package = ""; /* not for this arch */
603 }
604
605 // Skip whitespace
606 for (;I != Stop && isspace(*I) != 0; I++);
607 }
608
609 if (I != Stop && *I == '|')
610 Op |= pkgCache::Dep::Or;
611
612 if (I == Stop || *I == ',' || *I == '|')
613 {
614 if (I != Stop)
615 for (I++; I != Stop && isspace(*I) != 0; I++);
616 return I;
617 }
618
619 return 0;
620 }
621 /*}}}*/
622 // ListParser::ParseDepends - Parse a dependency list /*{{{*/
623 // ---------------------------------------------------------------------
624 /* This is the higher level depends parser. It takes a tag and generates
625 a complete depends tree for the given version. */
626 bool debListParser::ParseDepends(pkgCache::VerIterator &Ver,
627 const char *Tag,unsigned int Type)
628 {
629 const char *Start;
630 const char *Stop;
631 if (Section.Find(Tag,Start,Stop) == false)
632 return true;
633
634 string Package;
635 string const pkgArch = Ver.Arch();
636 string Version;
637 unsigned int Op;
638
639 while (1)
640 {
641 Start = ParseDepends(Start,Stop,Package,Version,Op,false,!MultiArchEnabled);
642 if (Start == 0)
643 return _error->Error("Problem parsing dependency %s",Tag);
644
645 if (MultiArchEnabled == true &&
646 (Type == pkgCache::Dep::Conflicts ||
647 Type == pkgCache::Dep::DpkgBreaks ||
648 Type == pkgCache::Dep::Replaces))
649 {
650 for (std::vector<std::string>::const_iterator a = Architectures.begin();
651 a != Architectures.end(); ++a)
652 if (NewDepends(Ver,Package,*a,Version,Op,Type) == false)
653 return false;
654 }
655 else if (NewDepends(Ver,Package,pkgArch,Version,Op,Type) == false)
656 return false;
657 if (Start == Stop)
658 break;
659 }
660 return true;
661 }
662 /*}}}*/
663 // ListParser::ParseProvides - Parse the provides list /*{{{*/
664 // ---------------------------------------------------------------------
665 /* */
666 bool debListParser::ParseProvides(pkgCache::VerIterator &Ver)
667 {
668 const char *Start;
669 const char *Stop;
670 if (Section.Find("Provides",Start,Stop) == true)
671 {
672 string Package;
673 string Version;
674 string const Arch = Ver.Arch();
675 unsigned int Op;
676
677 while (1)
678 {
679 Start = ParseDepends(Start,Stop,Package,Version,Op);
680 if (Start == 0)
681 return _error->Error("Problem parsing Provides line");
682 if (Op != pkgCache::Dep::NoOp) {
683 _error->Warning("Ignoring Provides line with DepCompareOp for package %s", Package.c_str());
684 } else if ((Ver->MultiArch & pkgCache::Version::Foreign) == pkgCache::Version::Foreign) {
685 if (NewProvidesAllArch(Ver, Package, Version) == false)
686 return false;
687 } else {
688 if (NewProvides(Ver, Package, Arch, Version) == false)
689 return false;
690 }
691
692 if (Start == Stop)
693 break;
694 }
695 }
696
697 if (MultiArchEnabled == false)
698 return true;
699 else if ((Ver->MultiArch & pkgCache::Version::Allowed) == pkgCache::Version::Allowed)
700 {
701 string const Package = string(Ver.ParentPkg().Name()).append(":").append("any");
702 return NewProvidesAllArch(Ver, Package, Ver.VerStr());
703 }
704 else if ((Ver->MultiArch & pkgCache::Version::Foreign) == pkgCache::Version::Foreign)
705 return NewProvidesAllArch(Ver, Ver.ParentPkg().Name(), Ver.VerStr());
706
707 return true;
708 }
709 /*}}}*/
710 // ListParser::NewProvides - add provides for all architectures /*{{{*/
711 bool debListParser::NewProvidesAllArch(pkgCache::VerIterator &Ver, string const &Package,
712 string const &Version) {
713 for (std::vector<string>::const_iterator a = Architectures.begin();
714 a != Architectures.end(); ++a)
715 {
716 if (NewProvides(Ver, Package, *a, Version) == false)
717 return false;
718 }
719 return true;
720 }
721 /*}}}*/
722 // ListParser::GrabWord - Matches a word and returns /*{{{*/
723 // ---------------------------------------------------------------------
724 /* Looks for a word in a list of words - for ParseStatus */
725 bool debListParser::GrabWord(string Word,WordList *List,unsigned char &Out)
726 {
727 for (unsigned int C = 0; List[C].Str != 0; C++)
728 {
729 if (strcasecmp(Word.c_str(),List[C].Str) == 0)
730 {
731 Out = List[C].Val;
732 return true;
733 }
734 }
735 return false;
736 }
737 /*}}}*/
738 // ListParser::Step - Move to the next section in the file /*{{{*/
739 // ---------------------------------------------------------------------
740 /* This has to be carefull to only process the correct architecture */
741 bool debListParser::Step()
742 {
743 iOffset = Tags.Offset();
744 while (Tags.Step(Section) == true)
745 {
746 /* See if this is the correct Architecture, if it isn't then we
747 drop the whole section. A missing arch tag only happens (in theory)
748 inside the Status file, so that is a positive return */
749 string const Architecture = Section.FindS("Architecture");
750 if (Architecture.empty() == true)
751 return true;
752
753 if (Arch.empty() == true || Arch == "any" || MultiArchEnabled == false)
754 {
755 if (APT::Configuration::checkArchitecture(Architecture) == true)
756 return true;
757 }
758 else
759 {
760 if (Architecture == Arch)
761 return true;
762
763 if (Architecture == "all" && Arch == _config->Find("APT::Architecture"))
764 return true;
765 }
766
767 iOffset = Tags.Offset();
768 }
769 return false;
770 }
771 /*}}}*/
772 // ListParser::LoadReleaseInfo - Load the release information /*{{{*/
773 // ---------------------------------------------------------------------
774 /* */
775 bool debListParser::LoadReleaseInfo(pkgCache::PkgFileIterator &FileI,
776 FileFd &File, string component)
777 {
778 // apt-secure does no longer download individual (per-section) Release
779 // file. to provide Component pinning we use the section name now
780 FileI->Component = WriteUniqString(component);
781
782 // FIXME: Code depends on the fact that Release files aren't compressed
783 FILE* release = fdopen(dup(File.Fd()), "r");
784 if (release == NULL)
785 return false;
786
787 char buffer[101];
788 bool gpgClose = false;
789 while (fgets(buffer, sizeof(buffer), release) != NULL)
790 {
791 size_t len = 0;
792
793 // Skip empty lines
794 for (; buffer[len] == '\r' && buffer[len] == '\n'; ++len)
795 /* nothing */
796 ;
797 if (buffer[len] == '\0')
798 continue;
799
800 // only evalute the first GPG section
801 if (strncmp("-----", buffer, 5) == 0)
802 {
803 if (gpgClose == true)
804 break;
805 gpgClose = true;
806 continue;
807 }
808
809 // seperate the tag from the data
810 const char* dataStart = strchr(buffer + len, ':');
811 if (dataStart == NULL)
812 continue;
813 len = dataStart - buffer;
814 for (++dataStart; *dataStart == ' '; ++dataStart)
815 /* nothing */
816 ;
817 const char* dataEnd = (const char*)rawmemchr(dataStart, '\0');
818 // The last char should be a newline, but we can never be sure: #633350
819 const char* lineEnd = dataEnd;
820 for (--lineEnd; *lineEnd == '\r' || *lineEnd == '\n'; --lineEnd)
821 /* nothing */
822 ;
823 ++lineEnd;
824
825 // which datastorage need to be updated
826 enum { Suite, Component, Version, Origin, Codename, Label, None } writeTo = None;
827 if (buffer[0] == ' ')
828 ;
829 #define APT_PARSER_WRITETO(X) else if (strncmp(#X, buffer, len) == 0) writeTo = X;
830 APT_PARSER_WRITETO(Suite)
831 APT_PARSER_WRITETO(Component)
832 APT_PARSER_WRITETO(Version)
833 APT_PARSER_WRITETO(Origin)
834 APT_PARSER_WRITETO(Codename)
835 APT_PARSER_WRITETO(Label)
836 #undef APT_PARSER_WRITETO
837 #define APT_PARSER_FLAGIT(X) else if (strncmp(#X, buffer, len) == 0) \
838 pkgTagSection::FindFlag(FileI->Flags, pkgCache::Flag:: X, dataStart, lineEnd);
839 APT_PARSER_FLAGIT(NotAutomatic)
840 APT_PARSER_FLAGIT(ButAutomaticUpgrades)
841 #undef APT_PARSER_FLAGIT
842
843 // load all data from the line and save it
844 string data;
845 if (writeTo != None)
846 data.append(dataStart, dataEnd);
847 if (sizeof(buffer) - 1 == (dataEnd - buffer))
848 {
849 while (fgets(buffer, sizeof(buffer), release) != NULL)
850 {
851 if (writeTo != None)
852 data.append(buffer);
853 if (strlen(buffer) != sizeof(buffer) - 1)
854 break;
855 }
856 }
857 if (writeTo != None)
858 {
859 // remove spaces and stuff from the end of the data line
860 for (std::string::reverse_iterator s = data.rbegin();
861 s != data.rend(); ++s)
862 {
863 if (*s != '\r' && *s != '\n' && *s != ' ')
864 break;
865 *s = '\0';
866 }
867 switch (writeTo) {
868 case Suite: FileI->Archive = WriteUniqString(data); break;
869 case Component: FileI->Component = WriteUniqString(data); break;
870 case Version: FileI->Version = WriteUniqString(data); break;
871 case Origin: FileI->Origin = WriteUniqString(data); break;
872 case Codename: FileI->Codename = WriteUniqString(data); break;
873 case Label: FileI->Label = WriteUniqString(data); break;
874 case None: break;
875 }
876 }
877 }
878 fclose(release);
879
880 return !_error->PendingError();
881 }
882 /*}}}*/
883 // ListParser::GetPrio - Convert the priority from a string /*{{{*/
884 // ---------------------------------------------------------------------
885 /* */
886 unsigned char debListParser::GetPrio(string Str)
887 {
888 unsigned char Out;
889 if (GrabWord(Str,PrioList,Out) == false)
890 Out = pkgCache::State::Extra;
891
892 return Out;
893 }
894 /*}}}*/