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