]> git.saurik.com Git - apt.git/blob - apt-pkg/deb/debmetaindex.cc
don't hardcode /var/lib/dpkg/status as dir::state::status
[apt.git] / apt-pkg / deb / debmetaindex.cc
1 #include <config.h>
2
3 #include <apt-pkg/error.h>
4 #include <apt-pkg/debmetaindex.h>
5 #include <apt-pkg/debindexfile.h>
6 #include <apt-pkg/strutl.h>
7 #include <apt-pkg/fileutl.h>
8 #include <apt-pkg/acquire-item.h>
9 #include <apt-pkg/configuration.h>
10 #include <apt-pkg/aptconfiguration.h>
11 #include <apt-pkg/sourcelist.h>
12 #include <apt-pkg/hashes.h>
13 #include <apt-pkg/metaindex.h>
14 #include <apt-pkg/pkgcachegen.h>
15 #include <apt-pkg/tagfile.h>
16 #include <apt-pkg/gpgv.h>
17 #include <apt-pkg/macros.h>
18
19 #include <map>
20 #include <string>
21 #include <utility>
22 #include <vector>
23 #include <algorithm>
24 #include <sstream>
25
26 #include <sys/stat.h>
27 #include <string.h>
28
29 #include <apti18n.h>
30
31 class APT_HIDDEN debReleaseIndexPrivate /*{{{*/
32 {
33 public:
34 struct APT_HIDDEN debSectionEntry
35 {
36 std::string const sourcesEntry;
37 std::string const Name;
38 std::vector<std::string> const Targets;
39 std::vector<std::string> const Architectures;
40 std::vector<std::string> const Languages;
41 bool const UsePDiffs;
42 std::string const UseByHash;
43 };
44
45 std::vector<debSectionEntry> DebEntries;
46 std::vector<debSectionEntry> DebSrcEntries;
47
48 metaIndex::TriState CheckValidUntil;
49 time_t ValidUntilMin;
50 time_t ValidUntilMax;
51
52 std::vector<std::string> Architectures;
53 std::vector<std::string> NoSupportForAll;
54 std::map<std::string, std::string> const ReleaseOptions;
55
56 debReleaseIndexPrivate(std::map<std::string, std::string> const &Options) : CheckValidUntil(metaIndex::TRI_UNSET), ValidUntilMin(0), ValidUntilMax(0), ReleaseOptions(Options) {}
57 };
58 /*}}}*/
59 // ReleaseIndex::MetaIndex* - display helpers /*{{{*/
60 std::string debReleaseIndex::MetaIndexInfo(const char *Type) const
61 {
62 std::string Info = ::URI::ArchiveOnly(URI) + ' ';
63 if (Dist[Dist.size() - 1] == '/')
64 {
65 if (Dist != "/")
66 Info += Dist;
67 }
68 else
69 Info += Dist;
70 Info += " ";
71 Info += Type;
72 return Info;
73 }
74 std::string debReleaseIndex::Describe() const
75 {
76 return MetaIndexInfo("Release");
77 }
78
79 std::string debReleaseIndex::MetaIndexFile(const char *Type) const
80 {
81 return _config->FindDir("Dir::State::lists") +
82 URItoFileName(MetaIndexURI(Type));
83 }
84 static std::string constructMetaIndexURI(std::string URI, std::string const &Dist, char const * const Type)
85 {
86 if (Dist == "/")
87 ;
88 else if (Dist[Dist.size()-1] == '/')
89 URI += Dist;
90 else
91 URI += "dists/" + Dist + "/";
92 return URI + Type;
93 }
94 std::string debReleaseIndex::MetaIndexURI(const char *Type) const
95 {
96 return constructMetaIndexURI(URI, Dist, Type);
97 }
98 /*}}}*/
99 // ReleaseIndex Con- and Destructors /*{{{*/
100 debReleaseIndex::debReleaseIndex(std::string const &URI, std::string const &Dist, std::map<std::string, std::string> const &Options) :
101 metaIndex(URI, Dist, "deb"), d(new debReleaseIndexPrivate(Options))
102 {}
103 debReleaseIndex::debReleaseIndex(std::string const &URI, std::string const &Dist, bool const pTrusted, std::map<std::string, std::string> const &Options) :
104 metaIndex(URI, Dist, "deb"), d(new debReleaseIndexPrivate(Options))
105 {
106 Trusted = pTrusted ? TRI_YES : TRI_NO;
107 }
108 debReleaseIndex::~debReleaseIndex() {
109 if (d != NULL)
110 delete d;
111 }
112 /*}}}*/
113 // ReleaseIndex::GetIndexTargets /*{{{*/
114 static void GetIndexTargetsFor(char const * const Type, std::string const &URI, std::string const &Dist,
115 std::vector<debReleaseIndexPrivate::debSectionEntry> const &entries,
116 std::vector<IndexTarget> &IndexTargets, std::map<std::string, std::string> const &ReleaseOptions)
117 {
118 bool const flatArchive = (Dist[Dist.length() - 1] == '/');
119 std::string const baseURI = constructMetaIndexURI(URI, Dist, "");
120 std::string const Release = (Dist == "/") ? "" : Dist;
121 std::string const Site = ::URI::ArchiveOnly(URI);
122
123 std::string DefCompressionTypes;
124 {
125 std::vector<std::string> types = APT::Configuration::getCompressionTypes();
126 if (types.empty() == false)
127 {
128 std::ostringstream os;
129 std::copy(types.begin(), types.end()-1, std::ostream_iterator<std::string>(os, " "));
130 os << *types.rbegin();
131 DefCompressionTypes = os.str();
132 }
133 }
134 std::string DefKeepCompressedAs;
135 {
136 std::vector<APT::Configuration::Compressor> comps = APT::Configuration::getCompressors();
137 if (comps.empty() == false)
138 {
139 std::sort(comps.begin(), comps.end(),
140 [](APT::Configuration::Compressor const &a, APT::Configuration::Compressor const &b) { return a.Cost < b.Cost; });
141 std::ostringstream os;
142 for (auto const &c : comps)
143 if (c.Cost != 0)
144 os << c.Extension.substr(1) << ' ';
145 DefKeepCompressedAs = os.str();
146 }
147 DefKeepCompressedAs += "uncompressed";
148 }
149
150 std::vector<std::string> const NativeArchs = { _config->Find("APT::Architecture"), "all" };
151 bool const GzipIndex = _config->FindB("Acquire::GzipIndexes", false);
152 for (std::vector<debReleaseIndexPrivate::debSectionEntry>::const_iterator E = entries.begin(); E != entries.end(); ++E)
153 {
154 for (std::vector<std::string>::const_iterator T = E->Targets.begin(); T != E->Targets.end(); ++T)
155 {
156 #define APT_T_CONFIG_STR(X, Y) _config->Find(std::string("Acquire::IndexTargets::") + Type + "::" + *T + "::" + (X), (Y))
157 #define APT_T_CONFIG_BOOL(X, Y) _config->FindB(std::string("Acquire::IndexTargets::") + Type + "::" + *T + "::" + (X), (Y))
158 std::string const tplMetaKey = APT_T_CONFIG_STR(flatArchive ? "flatMetaKey" : "MetaKey", "");
159 std::string const tplShortDesc = APT_T_CONFIG_STR("ShortDescription", "");
160 std::string const tplLongDesc = "$(SITE) " + APT_T_CONFIG_STR(flatArchive ? "flatDescription" : "Description", "");
161 std::string const tplIdentifier = APT_T_CONFIG_STR("Identifier", *T);
162 bool const IsOptional = APT_T_CONFIG_BOOL("Optional", true);
163 bool const KeepCompressed = APT_T_CONFIG_BOOL("KeepCompressed", GzipIndex);
164 bool const DefaultEnabled = APT_T_CONFIG_BOOL("DefaultEnabled", true);
165 bool const UsePDiffs = APT_T_CONFIG_BOOL("PDiffs", E->UsePDiffs);
166 std::string const UseByHash = APT_T_CONFIG_STR("By-Hash", E->UseByHash);
167 std::string const CompressionTypes = APT_T_CONFIG_STR("CompressionTypes", DefCompressionTypes);
168 std::string KeepCompressedAs = APT_T_CONFIG_STR("KeepCompressedAs", "");
169 std::string const FallbackOf = APT_T_CONFIG_STR("Fallback-Of", "");
170 #undef APT_T_CONFIG_BOOL
171 #undef APT_T_CONFIG_STR
172 if (tplMetaKey.empty())
173 continue;
174
175 if (KeepCompressedAs.empty())
176 KeepCompressedAs = DefKeepCompressedAs;
177 else
178 {
179 std::vector<std::string> const defKeep = VectorizeString(DefKeepCompressedAs, ' ');
180 std::vector<std::string> const valKeep = VectorizeString(KeepCompressedAs, ' ');
181 std::vector<std::string> keep;
182 for (auto const &val : valKeep)
183 {
184 if (val.empty())
185 continue;
186 if (std::find(defKeep.begin(), defKeep.end(), val) == defKeep.end())
187 continue;
188 keep.push_back(val);
189 }
190 if (std::find(keep.begin(), keep.end(), "uncompressed") == keep.end())
191 keep.push_back("uncompressed");
192 std::ostringstream os;
193 std::copy(keep.begin(), keep.end()-1, std::ostream_iterator<std::string>(os, " "));
194 os << *keep.rbegin();
195 KeepCompressedAs = os.str();
196 }
197
198 for (std::vector<std::string>::const_iterator L = E->Languages.begin(); L != E->Languages.end(); ++L)
199 {
200 if (*L == "none" && tplMetaKey.find("$(LANGUAGE)") != std::string::npos)
201 continue;
202
203 for (std::vector<std::string>::const_iterator A = E->Architectures.begin(); A != E->Architectures.end(); ++A)
204 {
205 for (auto const &NativeArch: NativeArchs)
206 {
207 constexpr static auto BreakPoint = "$(NATIVE_ARCHITECTURE)";
208 // available in templates
209 std::map<std::string, std::string> Options;
210 Options.insert(std::make_pair("SITE", Site));
211 Options.insert(std::make_pair("RELEASE", Release));
212 if (tplMetaKey.find("$(COMPONENT)") != std::string::npos)
213 Options.insert(std::make_pair("COMPONENT", E->Name));
214 if (tplMetaKey.find("$(LANGUAGE)") != std::string::npos)
215 Options.insert(std::make_pair("LANGUAGE", *L));
216 if (tplMetaKey.find("$(ARCHITECTURE)") != std::string::npos)
217 Options.insert(std::make_pair("ARCHITECTURE", *A));
218 else if (tplMetaKey.find("$(NATIVE_ARCHITECTURE)") != std::string::npos)
219 Options.insert(std::make_pair("ARCHITECTURE", NativeArch));
220 if (tplMetaKey.find("$(NATIVE_ARCHITECTURE)") != std::string::npos)
221 Options.insert(std::make_pair("NATIVE_ARCHITECTURE", NativeArch));
222
223 std::string MetaKey = tplMetaKey;
224 std::string ShortDesc = tplShortDesc;
225 std::string LongDesc = tplLongDesc;
226 std::string Identifier = tplIdentifier;
227 for (std::map<std::string, std::string>::const_iterator O = Options.begin(); O != Options.end(); ++O)
228 {
229 std::string const varname = "$(" + O->first + ")";
230 MetaKey = SubstVar(MetaKey, varname, O->second);
231 ShortDesc = SubstVar(ShortDesc, varname, O->second);
232 LongDesc = SubstVar(LongDesc, varname, O->second);
233 Identifier = SubstVar(Identifier, varname, O->second);
234 }
235
236 {
237 auto const dup = std::find_if(IndexTargets.begin(), IndexTargets.end(), [&](IndexTarget const &IT) {
238 return MetaKey == IT.MetaKey && baseURI == IT.Option(IndexTarget::BASE_URI) &&
239 E->sourcesEntry == IT.Option(IndexTarget::SOURCESENTRY) && *T == IT.Option(IndexTarget::CREATED_BY);
240 });
241 if (dup != IndexTargets.end())
242 {
243 if (tplMetaKey.find(BreakPoint) == std::string::npos)
244 break;
245 continue;
246 }
247 }
248
249 {
250 auto const dup = std::find_if(IndexTargets.begin(), IndexTargets.end(), [&](IndexTarget const &IT) {
251 return MetaKey == IT.MetaKey && baseURI == IT.Option(IndexTarget::BASE_URI) &&
252 E->sourcesEntry == IT.Option(IndexTarget::SOURCESENTRY) && *T != IT.Option(IndexTarget::CREATED_BY);
253 });
254 if (dup != IndexTargets.end())
255 {
256 std::string const dupT = dup->Option(IndexTarget::CREATED_BY);
257 std::string const dupEntry = dup->Option(IndexTarget::SOURCESENTRY);
258 //TRANSLATOR: an identifier like Packages; Releasefile key indicating
259 // a file like main/binary-amd64/Packages; another identifier like Contents;
260 // filename and linenumber of the sources.list entry currently parsed
261 _error->Warning(_("Target %s wants to acquire the same file (%s) as %s from source %s"),
262 T->c_str(), MetaKey.c_str(), dupT.c_str(), dupEntry.c_str());
263 if (tplMetaKey.find(BreakPoint) == std::string::npos)
264 break;
265 continue;
266 }
267 }
268
269 {
270 auto const dup = std::find_if(IndexTargets.begin(), IndexTargets.end(), [&](IndexTarget const &T) {
271 return MetaKey == T.MetaKey && baseURI == T.Option(IndexTarget::BASE_URI) &&
272 E->sourcesEntry != T.Option(IndexTarget::SOURCESENTRY);
273 });
274 if (dup != IndexTargets.end())
275 {
276 std::string const dupEntry = dup->Option(IndexTarget::SOURCESENTRY);
277 //TRANSLATOR: an identifier like Packages; Releasefile key indicating
278 // a file like main/binary-amd64/Packages; filename and linenumber of
279 // two sources.list entries
280 _error->Warning(_("Target %s (%s) is configured multiple times in %s and %s"),
281 T->c_str(), MetaKey.c_str(), dupEntry.c_str(), E->sourcesEntry.c_str());
282 if (tplMetaKey.find(BreakPoint) == std::string::npos)
283 break;
284 continue;
285 }
286 }
287
288 // not available in templates, but in the indextarget
289 Options.insert(ReleaseOptions.begin(), ReleaseOptions.end());
290 Options.insert(std::make_pair("IDENTIFIER", Identifier));
291 Options.insert(std::make_pair("TARGET_OF", Type));
292 Options.insert(std::make_pair("CREATED_BY", *T));
293 Options.insert(std::make_pair("FALLBACK_OF", FallbackOf));
294 Options.insert(std::make_pair("PDIFFS", UsePDiffs ? "yes" : "no"));
295 Options.insert(std::make_pair("BY_HASH", UseByHash));
296 Options.insert(std::make_pair("DEFAULTENABLED", DefaultEnabled ? "yes" : "no"));
297 Options.insert(std::make_pair("COMPRESSIONTYPES", CompressionTypes));
298 Options.insert(std::make_pair("KEEPCOMPRESSEDAS", KeepCompressedAs));
299 Options.insert(std::make_pair("SOURCESENTRY", E->sourcesEntry));
300
301 bool IsOpt = IsOptional;
302 if (IsOpt == false)
303 {
304 auto const arch = Options.find("ARCHITECTURE");
305 if (arch != Options.end() && arch->second == "all")
306 IsOpt = true;
307 }
308
309 IndexTarget Target(
310 MetaKey,
311 ShortDesc,
312 LongDesc,
313 baseURI + MetaKey,
314 IsOpt,
315 KeepCompressed,
316 Options
317 );
318 IndexTargets.push_back(Target);
319
320 if (tplMetaKey.find(BreakPoint) == std::string::npos)
321 break;
322 }
323
324 if (tplMetaKey.find("$(ARCHITECTURE)") == std::string::npos)
325 break;
326
327 }
328
329 if (tplMetaKey.find("$(LANGUAGE)") == std::string::npos)
330 break;
331
332 }
333
334 }
335 }
336 }
337 std::vector<IndexTarget> debReleaseIndex::GetIndexTargets() const
338 {
339 std::vector<IndexTarget> IndexTargets;
340 GetIndexTargetsFor("deb-src", URI, Dist, d->DebSrcEntries, IndexTargets, d->ReleaseOptions);
341 GetIndexTargetsFor("deb", URI, Dist, d->DebEntries, IndexTargets, d->ReleaseOptions);
342 return IndexTargets;
343 }
344 /*}}}*/
345 void debReleaseIndex::AddComponent(std::string const &sourcesEntry, /*{{{*/
346 bool const isSrc, std::string const &Name,
347 std::vector<std::string> const &Targets,
348 std::vector<std::string> const &Architectures,
349 std::vector<std::string> Languages,
350 bool const usePDiffs, std::string const &useByHash)
351 {
352 if (Languages.empty() == true)
353 Languages.push_back("none");
354 debReleaseIndexPrivate::debSectionEntry const entry = {
355 sourcesEntry, Name, Targets, Architectures, Languages, usePDiffs, useByHash
356 };
357 if (isSrc)
358 d->DebSrcEntries.push_back(entry);
359 else
360 d->DebEntries.push_back(entry);
361 }
362 /*}}}*/
363
364 bool debReleaseIndex::Load(std::string const &Filename, std::string * const ErrorText)/*{{{*/
365 {
366 LoadedSuccessfully = TRI_NO;
367 FileFd Fd;
368 if (OpenMaybeClearSignedFile(Filename, Fd) == false)
369 return false;
370
371 pkgTagFile TagFile(&Fd, Fd.Size());
372 if (Fd.IsOpen() == false || Fd.Failed())
373 {
374 if (ErrorText != NULL)
375 strprintf(*ErrorText, _("Unable to parse Release file %s"),Filename.c_str());
376 return false;
377 }
378
379 pkgTagSection Section;
380 const char *Start, *End;
381 if (TagFile.Step(Section) == false)
382 {
383 if (ErrorText != NULL)
384 strprintf(*ErrorText, _("No sections in Release file %s"), Filename.c_str());
385 return false;
386 }
387 // FIXME: find better tag name
388 SupportsAcquireByHash = Section.FindB("Acquire-By-Hash", false);
389
390 Suite = Section.FindS("Suite");
391 Codename = Section.FindS("Codename");
392 {
393 std::string const archs = Section.FindS("Architectures");
394 if (archs.empty() == false)
395 d->Architectures = VectorizeString(archs, ' ');
396 }
397 {
398 std::string const targets = Section.FindS("No-Support-for-Architecture-all");
399 if (targets.empty() == false)
400 d->NoSupportForAll = VectorizeString(targets, ' ');
401 }
402
403 bool FoundHashSum = false;
404 bool FoundStrongHashSum = false;
405 auto const SupportedHashes = HashString::SupportedHashes();
406 for (int i=0; SupportedHashes[i] != NULL; i++)
407 {
408 if (!Section.Find(SupportedHashes[i], Start, End))
409 continue;
410
411 std::string Name;
412 std::string Hash;
413 unsigned long long Size;
414 while (Start < End)
415 {
416 if (!parseSumData(Start, End, Name, Hash, Size))
417 return false;
418
419 HashString const hs(SupportedHashes[i], Hash);
420 if (Entries.find(Name) == Entries.end())
421 {
422 metaIndex::checkSum *Sum = new metaIndex::checkSum;
423 Sum->MetaKeyFilename = Name;
424 Sum->Size = Size;
425 Sum->Hashes.FileSize(Size);
426 APT_IGNORE_DEPRECATED(Sum->Hash = hs;)
427 Entries[Name] = Sum;
428 }
429 Entries[Name]->Hashes.push_back(hs);
430 FoundHashSum = true;
431 if (FoundStrongHashSum == false && hs.usable() == true)
432 FoundStrongHashSum = true;
433 }
434 }
435
436 bool AuthPossible = false;
437 if(FoundHashSum == false)
438 _error->Warning(_("No Hash entry in Release file %s"), Filename.c_str());
439 else if(FoundStrongHashSum == false)
440 _error->Warning(_("No Hash entry in Release file %s which is considered strong enough for security purposes"), Filename.c_str());
441 else
442 AuthPossible = true;
443
444 std::string const StrDate = Section.FindS("Date");
445 if (RFC1123StrToTime(StrDate.c_str(), Date) == false)
446 {
447 _error->Warning( _("Invalid '%s' entry in Release file %s"), "Date", Filename.c_str());
448 Date = 0;
449 }
450
451 bool CheckValidUntil = _config->FindB("Acquire::Check-Valid-Until", true);
452 if (d->CheckValidUntil == metaIndex::TRI_NO)
453 CheckValidUntil = false;
454 else if (d->CheckValidUntil == metaIndex::TRI_YES)
455 CheckValidUntil = true;
456
457 if (CheckValidUntil == true)
458 {
459 std::string const Label = Section.FindS("Label");
460 std::string const StrValidUntil = Section.FindS("Valid-Until");
461
462 // if we have a Valid-Until header in the Release file, use it as default
463 if (StrValidUntil.empty() == false)
464 {
465 if(RFC1123StrToTime(StrValidUntil.c_str(), ValidUntil) == false)
466 {
467 if (ErrorText != NULL)
468 strprintf(*ErrorText, _("Invalid '%s' entry in Release file %s"), "Valid-Until", Filename.c_str());
469 return false;
470 }
471 }
472 // get the user settings for this archive and use what expires earlier
473 time_t MaxAge = d->ValidUntilMax;
474 if (MaxAge == 0)
475 {
476 MaxAge = _config->FindI("Acquire::Max-ValidTime", 0);
477 if (Label.empty() == false)
478 MaxAge = _config->FindI(("Acquire::Max-ValidTime::" + Label).c_str(), MaxAge);
479 }
480 time_t MinAge = d->ValidUntilMin;
481 if (MinAge == 0)
482 {
483 MinAge = _config->FindI("Acquire::Min-ValidTime", 0);
484 if (Label.empty() == false)
485 MinAge = _config->FindI(("Acquire::Min-ValidTime::" + Label).c_str(), MinAge);
486 }
487
488 if (MinAge != 0 || ValidUntil != 0 || MaxAge != 0)
489 {
490 if (MinAge != 0 && ValidUntil != 0) {
491 time_t const min_date = Date + MinAge;
492 if (ValidUntil < min_date)
493 ValidUntil = min_date;
494 }
495 if (MaxAge != 0 && Date != 0) {
496 time_t const max_date = Date + MaxAge;
497 if (ValidUntil == 0 || ValidUntil > max_date)
498 ValidUntil = max_date;
499 }
500 }
501 }
502
503 /* as the Release file is parsed only after it was verified, the Signed-By field
504 does not effect the current, but the "next" Release file */
505 auto Sign = Section.FindS("Signed-By");
506 if (Sign.empty() == false)
507 {
508 std::transform(Sign.begin(), Sign.end(), Sign.begin(), [&](char const c) {
509 return (isspace(c) == 0) ? c : ',';
510 });
511 auto fingers = VectorizeString(Sign, ',');
512 std::transform(fingers.begin(), fingers.end(), fingers.begin(), [&](std::string finger) {
513 std::transform(finger.begin(), finger.end(), finger.begin(), ::toupper);
514 if (finger.length() != 40 || finger.find_first_not_of("0123456789ABCDEF") != std::string::npos)
515 {
516 if (ErrorText != NULL)
517 strprintf(*ErrorText, _("Invalid '%s' entry in Release file %s"), "Signed-By", Filename.c_str());
518 return std::string();
519 }
520 return finger;
521 });
522 if (fingers.empty() == false && std::find(fingers.begin(), fingers.end(), "") == fingers.end())
523 {
524 std::stringstream os;
525 std::copy(fingers.begin(), fingers.end(), std::ostream_iterator<std::string>(os, ","));
526 SignedBy = os.str();
527 }
528 }
529
530 if (AuthPossible)
531 LoadedSuccessfully = TRI_YES;
532 return AuthPossible;
533 }
534 /*}}}*/
535 metaIndex * debReleaseIndex::UnloadedClone() const /*{{{*/
536 {
537 if (Trusted == TRI_NO)
538 return new debReleaseIndex(URI, Dist, false, d->ReleaseOptions);
539 else if (Trusted == TRI_YES)
540 return new debReleaseIndex(URI, Dist, true, d->ReleaseOptions);
541 else
542 return new debReleaseIndex(URI, Dist, d->ReleaseOptions);
543 }
544 /*}}}*/
545 bool debReleaseIndex::parseSumData(const char *&Start, const char *End, /*{{{*/
546 std::string &Name, std::string &Hash, unsigned long long &Size)
547 {
548 Name = "";
549 Hash = "";
550 Size = 0;
551 /* Skip over the first blank */
552 while ((*Start == '\t' || *Start == ' ' || *Start == '\n' || *Start == '\r')
553 && Start < End)
554 Start++;
555 if (Start >= End)
556 return false;
557
558 /* Move EntryEnd to the end of the first entry (the hash) */
559 const char *EntryEnd = Start;
560 while ((*EntryEnd != '\t' && *EntryEnd != ' ')
561 && EntryEnd < End)
562 EntryEnd++;
563 if (EntryEnd == End)
564 return false;
565
566 Hash.append(Start, EntryEnd-Start);
567
568 /* Skip over intermediate blanks */
569 Start = EntryEnd;
570 while (*Start == '\t' || *Start == ' ')
571 Start++;
572 if (Start >= End)
573 return false;
574
575 EntryEnd = Start;
576 /* Find the end of the second entry (the size) */
577 while ((*EntryEnd != '\t' && *EntryEnd != ' ' )
578 && EntryEnd < End)
579 EntryEnd++;
580 if (EntryEnd == End)
581 return false;
582
583 Size = strtoull (Start, NULL, 10);
584
585 /* Skip over intermediate blanks */
586 Start = EntryEnd;
587 while (*Start == '\t' || *Start == ' ')
588 Start++;
589 if (Start >= End)
590 return false;
591
592 EntryEnd = Start;
593 /* Find the end of the third entry (the filename) */
594 while ((*EntryEnd != '\t' && *EntryEnd != ' ' &&
595 *EntryEnd != '\n' && *EntryEnd != '\r')
596 && EntryEnd < End)
597 EntryEnd++;
598
599 Name.append(Start, EntryEnd-Start);
600 Start = EntryEnd; //prepare for the next round
601 return true;
602 }
603 /*}}}*/
604
605 bool debReleaseIndex::GetIndexes(pkgAcquire *Owner, bool const &GetAll)/*{{{*/
606 {
607 #define APT_TARGET(X) IndexTarget("", X, MetaIndexInfo(X), MetaIndexURI(X), false, false, d->ReleaseOptions)
608 pkgAcqMetaClearSig * const TransactionManager = new pkgAcqMetaClearSig(Owner,
609 APT_TARGET("InRelease"), APT_TARGET("Release"), APT_TARGET("Release.gpg"), this);
610 #undef APT_TARGET
611 // special case for --print-uris
612 if (GetAll)
613 for (auto const &Target: GetIndexTargets())
614 if (Target.Option(IndexTarget::FALLBACK_OF).empty())
615 new pkgAcqIndex(Owner, TransactionManager, Target);
616
617 return true;
618 }
619 /*}}}*/
620 // ReleaseIndex::Set* TriState options /*{{{*/
621 bool debReleaseIndex::SetTrusted(TriState const pTrusted)
622 {
623 if (Trusted == TRI_UNSET)
624 Trusted = pTrusted;
625 else if (Trusted != pTrusted)
626 // TRANSLATOR: The first is an option name from sources.list manpage, the other two URI and Suite
627 return _error->Error(_("Conflicting values set for option %s regarding source %s %s"), "Trusted", URI.c_str(), Dist.c_str());
628 return true;
629 }
630 bool debReleaseIndex::SetCheckValidUntil(TriState const pCheckValidUntil)
631 {
632 if (d->CheckValidUntil == TRI_UNSET)
633 d->CheckValidUntil = pCheckValidUntil;
634 else if (d->CheckValidUntil != pCheckValidUntil)
635 return _error->Error(_("Conflicting values set for option %s regarding source %s %s"), "Check-Valid-Until", URI.c_str(), Dist.c_str());
636 return true;
637 }
638 bool debReleaseIndex::SetValidUntilMin(time_t const Valid)
639 {
640 if (d->ValidUntilMin == 0)
641 d->ValidUntilMin = Valid;
642 else if (d->ValidUntilMin != Valid)
643 return _error->Error(_("Conflicting values set for option %s regarding source %s %s"), "Min-ValidTime", URI.c_str(), Dist.c_str());
644 return true;
645 }
646 bool debReleaseIndex::SetValidUntilMax(time_t const Valid)
647 {
648 if (d->ValidUntilMax == 0)
649 d->ValidUntilMax = Valid;
650 else if (d->ValidUntilMax != Valid)
651 return _error->Error(_("Conflicting values set for option %s regarding source %s %s"), "Max-ValidTime", URI.c_str(), Dist.c_str());
652 return true;
653 }
654 bool debReleaseIndex::SetSignedBy(std::string const &pSignedBy)
655 {
656 if (SignedBy.empty() == true && pSignedBy.empty() == false)
657 {
658 if (pSignedBy[0] == '/') // no check for existence as we could be chrooting later or such things
659 SignedBy = pSignedBy; // absolute path to a keyring file
660 else
661 {
662 // we could go all fancy and allow short/long/string matches as gpgv/apt-key does,
663 // but fingerprints are harder to fake than the others and this option is set once,
664 // not interactively all the time so easy to type is not really a concern.
665 auto fingers = VectorizeString(pSignedBy, ',');
666 std::transform(fingers.begin(), fingers.end(), fingers.begin(), [&](std::string finger) {
667 std::transform(finger.begin(), finger.end(), finger.begin(), ::toupper);
668 if (finger.length() != 40 || finger.find_first_not_of("0123456789ABCDEF") != std::string::npos)
669 {
670 _error->Error(_("Invalid value set for option %s regarding source %s %s (%s)"), "Signed-By", URI.c_str(), Dist.c_str(), "not a fingerprint");
671 return std::string();
672 }
673 return finger;
674 });
675 std::stringstream os;
676 std::copy(fingers.begin(), fingers.end(), std::ostream_iterator<std::string>(os, ","));
677 SignedBy = os.str();
678 }
679 // Normalize the string: Remove trailing commas
680 while (SignedBy[SignedBy.size() - 1] == ',')
681 SignedBy.resize(SignedBy.size() - 1);
682 }
683 else {
684 // Only compare normalized strings
685 auto pSignedByView = APT::StringView(pSignedBy);
686 while (pSignedByView[pSignedByView.size() - 1] == ',')
687 pSignedByView = pSignedByView.substr(0, pSignedByView.size() - 1);
688 if (pSignedByView != SignedBy)
689 return _error->Error(_("Conflicting values set for option %s regarding source %s %s: %s != %s"), "Signed-By", URI.c_str(), Dist.c_str(), SignedBy.c_str(), pSignedByView.to_string().c_str());
690 }
691 return true;
692 }
693 /*}}}*/
694 // ReleaseIndex::IsTrusted /*{{{*/
695 bool debReleaseIndex::IsTrusted() const
696 {
697 if (Trusted == TRI_YES)
698 return true;
699 else if (Trusted == TRI_NO)
700 return false;
701
702
703 if(_config->FindB("APT::Authentication::TrustCDROM", false))
704 if(URI.substr(0,strlen("cdrom:")) == "cdrom:")
705 return true;
706
707 if (FileExists(MetaIndexFile("Release.gpg")))
708 return true;
709
710 return FileExists(MetaIndexFile("InRelease"));
711 }
712 /*}}}*/
713 bool debReleaseIndex::IsArchitectureSupported(std::string const &arch) const/*{{{*/
714 {
715 if (d->Architectures.empty())
716 return true;
717 return std::find(d->Architectures.begin(), d->Architectures.end(), arch) != d->Architectures.end();
718 }
719 /*}}}*/
720 bool debReleaseIndex::IsArchitectureAllSupportedFor(IndexTarget const &target) const/*{{{*/
721 {
722 if (d->NoSupportForAll.empty())
723 return true;
724 return std::find(d->NoSupportForAll.begin(), d->NoSupportForAll.end(), target.Option(IndexTarget::CREATED_BY)) == d->NoSupportForAll.end();
725 }
726 /*}}}*/
727 std::vector <pkgIndexFile *> *debReleaseIndex::GetIndexFiles() /*{{{*/
728 {
729 if (Indexes != NULL)
730 return Indexes;
731
732 Indexes = new std::vector<pkgIndexFile*>();
733 bool const istrusted = IsTrusted();
734 for (auto const &T: GetIndexTargets())
735 {
736 std::string const TargetName = T.Option(IndexTarget::CREATED_BY);
737 if (TargetName == "Packages")
738 Indexes->push_back(new debPackagesIndex(T, istrusted));
739 else if (TargetName == "Sources")
740 Indexes->push_back(new debSourcesIndex(T, istrusted));
741 else if (TargetName == "Translations")
742 Indexes->push_back(new debTranslationsIndex(T));
743 }
744 return Indexes;
745 }
746 /*}}}*/
747 std::map<std::string, std::string> debReleaseIndex::GetReleaseOptions()
748 {
749 return d->ReleaseOptions;
750 }
751
752 static bool ReleaseFileName(debReleaseIndex const * const That, std::string &ReleaseFile)/*{{{*/
753 {
754 ReleaseFile = That->MetaIndexFile("InRelease");
755 bool releaseExists = false;
756 if (FileExists(ReleaseFile) == true)
757 releaseExists = true;
758 else
759 {
760 ReleaseFile = That->MetaIndexFile("Release");
761 if (FileExists(ReleaseFile))
762 releaseExists = true;
763 }
764 return releaseExists;
765 }
766 /*}}}*/
767 bool debReleaseIndex::Merge(pkgCacheGenerator &Gen,OpProgress * /*Prog*/) const/*{{{*/
768 {
769 std::string ReleaseFile;
770 bool const releaseExists = ReleaseFileName(this, ReleaseFile);
771
772 ::URI Tmp(URI);
773 if (Gen.SelectReleaseFile(ReleaseFile, Tmp.Host) == false)
774 return _error->Error("Problem with SelectReleaseFile %s", ReleaseFile.c_str());
775
776 if (releaseExists == false)
777 return true;
778
779 FileFd Rel;
780 // Beware: The 'Release' file might be clearsigned in case the
781 // signature for an 'InRelease' file couldn't be checked
782 if (OpenMaybeClearSignedFile(ReleaseFile, Rel) == false)
783 return false;
784
785 // Store the IMS information
786 pkgCache::RlsFileIterator File = Gen.GetCurRlsFile();
787 pkgCacheGenerator::Dynamic<pkgCache::RlsFileIterator> DynFile(File);
788 // Rel can't be used as this is potentially a temporary file
789 struct stat Buf;
790 if (stat(ReleaseFile.c_str(), &Buf) != 0)
791 return _error->Errno("fstat", "Unable to stat file %s", ReleaseFile.c_str());
792 File->Size = Buf.st_size;
793 File->mtime = Buf.st_mtime;
794
795 pkgTagFile TagFile(&Rel, Rel.Size());
796 pkgTagSection Section;
797 if (Rel.IsOpen() == false || Rel.Failed() || TagFile.Step(Section) == false)
798 return false;
799
800 std::string data;
801 #define APT_INRELEASE(TYPE, TAG, STORE) \
802 data = Section.FindS(TAG); \
803 if (data.empty() == false) \
804 { \
805 map_stringitem_t const storage = Gen.StoreString(pkgCacheGenerator::TYPE, data); \
806 if (storage == 0) return false; \
807 STORE = storage; \
808 }
809 APT_INRELEASE(MIXED, "Suite", File->Archive)
810 APT_INRELEASE(VERSIONNUMBER, "Version", File->Version)
811 APT_INRELEASE(MIXED, "Origin", File->Origin)
812 APT_INRELEASE(MIXED, "Codename", File->Codename)
813 APT_INRELEASE(MIXED, "Label", File->Label)
814 #undef APT_INRELEASE
815 Section.FindFlag("NotAutomatic", File->Flags, pkgCache::Flag::NotAutomatic);
816 Section.FindFlag("ButAutomaticUpgrades", File->Flags, pkgCache::Flag::ButAutomaticUpgrades);
817
818 return true;
819 }
820 /*}}}*/
821 // ReleaseIndex::FindInCache - Find this index /*{{{*/
822 pkgCache::RlsFileIterator debReleaseIndex::FindInCache(pkgCache &Cache, bool const ModifyCheck) const
823 {
824 std::string ReleaseFile;
825 bool const releaseExists = ReleaseFileName(this, ReleaseFile);
826
827 pkgCache::RlsFileIterator File = Cache.RlsFileBegin();
828 for (; File.end() == false; ++File)
829 {
830 if (File->FileName == 0 || ReleaseFile != File.FileName())
831 continue;
832
833 // empty means the file does not exist by "design"
834 if (ModifyCheck == false || (releaseExists == false && File->Size == 0))
835 return File;
836
837 struct stat St;
838 if (stat(File.FileName(),&St) != 0)
839 {
840 if (_config->FindB("Debug::pkgCacheGen", false))
841 std::clog << "ReleaseIndex::FindInCache - stat failed on " << File.FileName() << std::endl;
842 return pkgCache::RlsFileIterator(Cache);
843 }
844 if ((unsigned)St.st_size != File->Size || St.st_mtime != File->mtime)
845 {
846 if (_config->FindB("Debug::pkgCacheGen", false))
847 std::clog << "ReleaseIndex::FindInCache - size (" << St.st_size << " <> " << File->Size
848 << ") or mtime (" << St.st_mtime << " <> " << File->mtime
849 << ") doesn't match for " << File.FileName() << std::endl;
850 return pkgCache::RlsFileIterator(Cache);
851 }
852 return File;
853 }
854
855 return File;
856 }
857 /*}}}*/
858
859 static std::vector<std::string> parsePlusMinusOptions(std::string const &Name, /*{{{*/
860 std::map<std::string, std::string> const &Options, std::vector<std::string> const &defaultValues)
861 {
862 std::map<std::string, std::string>::const_iterator val = Options.find(Name);
863 std::vector<std::string> Values;
864 if (val != Options.end())
865 Values = VectorizeString(val->second, ',');
866 else
867 Values = defaultValues;
868
869 // all is a very special architecture users shouldn't be concerned with explicitly
870 if (Name == "arch" && std::find(Values.begin(), Values.end(), "all") == Values.end())
871 Values.push_back("all");
872
873 if ((val = Options.find(Name + "+")) != Options.end())
874 {
875 std::vector<std::string> const plus = VectorizeString(val->second, ',');
876 std::copy_if(plus.begin(), plus.end(), std::back_inserter(Values), [&Values](std::string const &v) {
877 return std::find(Values.begin(), Values.end(), v) == Values.end();
878 });
879 }
880 if ((val = Options.find(Name + "-")) != Options.end())
881 {
882 std::vector<std::string> const minus = VectorizeString(val->second, ',');
883 Values.erase(std::remove_if(Values.begin(), Values.end(), [&minus](std::string const &v) {
884 return std::find(minus.begin(), minus.end(), v) != minus.end();
885 }), Values.end());
886 }
887 return Values;
888 }
889 /*}}}*/
890 class APT_HIDDEN debSLTypeDebian : public pkgSourceList::Type /*{{{*/
891 {
892 metaIndex::TriState GetTriStateOption(std::map<std::string, std::string>const &Options, char const * const name) const
893 {
894 std::map<std::string, std::string>::const_iterator const opt = Options.find(name);
895 if (opt != Options.end())
896 return StringToBool(opt->second, false) ? metaIndex::TRI_YES : metaIndex::TRI_NO;
897 return metaIndex::TRI_DONTCARE;
898 }
899
900 static time_t GetTimeOption(std::map<std::string, std::string>const &Options, char const * const name)
901 {
902 std::map<std::string, std::string>::const_iterator const opt = Options.find(name);
903 if (opt == Options.end())
904 return 0;
905 return strtoull(opt->second.c_str(), NULL, 10);
906 }
907
908 static bool GetBoolOption(std::map<std::string, std::string> const &Options, char const * const name, bool const defVal)
909 {
910 std::map<std::string, std::string>::const_iterator const opt = Options.find(name);
911 if (opt == Options.end())
912 return defVal;
913 return StringToBool(opt->second, defVal);
914 }
915
916 static std::vector<std::string> GetMapKeys(std::map<std::string, std::string> const &Options)
917 {
918 std::vector<std::string> ret;
919 ret.reserve(Options.size());
920 for (auto &&O: Options)
921 ret.emplace_back(O.first);
922 std::sort(ret.begin(), ret.end());
923 return ret;
924 }
925
926 static bool MapsAreEqual(std::map<std::string, std::string> const &OptionsA,
927 std::map<std::string, std::string> const &OptionsB,
928 std::string const &URI, std::string const &Dist)
929 {
930 auto const KeysA = GetMapKeys(OptionsA);
931 auto const KeysB = GetMapKeys(OptionsB);
932 auto const m = std::mismatch(KeysA.begin(), KeysA.end(), KeysB.begin());
933 if (m.first != KeysA.end())
934 {
935 if (std::find(KeysB.begin(), KeysB.end(), *m.first) == KeysB.end())
936 return _error->Error(_("Conflicting values set for option %s regarding source %s %s"), m.first->c_str(), "<set>", "<unset>");
937 else
938 return _error->Error(_("Conflicting values set for option %s regarding source %s %s"), m.second->c_str(), "<set>", "<unset>");
939 }
940 if (m.second != KeysB.end())
941 {
942 if (std::find(KeysA.begin(), KeysA.end(), *m.second) == KeysA.end())
943 return _error->Error(_("Conflicting values set for option %s regarding source %s %s"), m.first->c_str(), "<set>", "<unset>");
944 else
945 return _error->Error(_("Conflicting values set for option %s regarding source %s %s"), m.second->c_str(), "<set>", "<unset>");
946 }
947 for (auto&& key: KeysA)
948 {
949 if (key == "BASE_URI" || key == "REPO_URI")
950 continue;
951 auto const a = OptionsA.find(key);
952 auto const b = OptionsB.find(key);
953 if (unlikely(a == OptionsA.end() || b == OptionsB.end()) || a->second != b->second)
954 return _error->Error(_("Conflicting values set for option %s regarding source %s %s"), key.c_str(), URI.c_str(), Dist.c_str());
955 }
956 return true;
957 }
958
959 protected:
960
961 bool CreateItemInternal(std::vector<metaIndex *> &List, std::string const &URI,
962 std::string const &Dist, std::string const &Section,
963 bool const &IsSrc, std::map<std::string, std::string> const &Options) const
964 {
965 std::map<std::string,std::string> ReleaseOptions = {{
966 { "BASE_URI", constructMetaIndexURI(URI, Dist, "") },
967 { "REPO_URI", URI },
968 }};
969 if (GetBoolOption(Options, "allow-insecure", _config->FindB("Acquire::AllowInsecureRepositories")))
970 ReleaseOptions.emplace("ALLOW_INSECURE", "true");
971 if (GetBoolOption(Options, "allow-weak", _config->FindB("Acquire::AllowWeakRepositories")))
972 ReleaseOptions.emplace("ALLOW_WEAK", "true");
973 if (GetBoolOption(Options, "allow-downgrade-to-insecure", _config->FindB("Acquire::AllowDowngradeToInsecureRepositories")))
974 ReleaseOptions.emplace("ALLOW_DOWNGRADE_TO_INSECURE", "true");
975
976 debReleaseIndex * Deb = nullptr;
977 std::string const FileName = URItoFileName(constructMetaIndexURI(URI, Dist, "Release"));
978 for (auto const &I: List)
979 {
980 // We only worry about debian entries here
981 if (strcmp(I->GetType(), "deb") != 0)
982 continue;
983
984 auto const D = dynamic_cast<debReleaseIndex*>(I);
985 if (unlikely(D == nullptr))
986 continue;
987
988 /* This check ensures that there will be only one Release file
989 queued for all the Packages files and Sources files it
990 corresponds to. */
991 if (URItoFileName(D->MetaIndexURI("Release")) == FileName)
992 {
993 if (MapsAreEqual(ReleaseOptions, D->GetReleaseOptions(), URI, Dist) == false)
994 return false;
995 Deb = D;
996 break;
997 }
998 }
999
1000 // No currently created Release file indexes this entry, so we create a new one.
1001 if (Deb == nullptr)
1002 {
1003 Deb = new debReleaseIndex(URI, Dist, ReleaseOptions);
1004 List.push_back(Deb);
1005 }
1006
1007 std::vector<std::string> const alltargets = _config->FindVector(std::string("Acquire::IndexTargets::") + Name, "", true);
1008 std::vector<std::string> deftargets;
1009 deftargets.reserve(alltargets.size());
1010 std::copy_if(alltargets.begin(), alltargets.end(), std::back_inserter(deftargets), [&](std::string const &t) {
1011 std::string c = "Acquire::IndexTargets::";
1012 c.append(Name).append("::").append(t).append("::DefaultEnabled");
1013 return _config->FindB(c, true);
1014 });
1015 std::vector<std::string> mytargets = parsePlusMinusOptions("target", Options, deftargets);
1016 for (auto const &target : alltargets)
1017 {
1018 std::map<std::string, std::string>::const_iterator const opt = Options.find(target);
1019 if (opt == Options.end())
1020 continue;
1021 auto const idMatch = [&](std::string const &t) {
1022 return target == _config->Find(std::string("Acquire::IndexTargets::") + Name + "::" + t + "::Identifier", t);
1023 };
1024 if (StringToBool(opt->second))
1025 std::copy_if(alltargets.begin(), alltargets.end(), std::back_inserter(mytargets), idMatch);
1026 else
1027 mytargets.erase(std::remove_if(mytargets.begin(), mytargets.end(), idMatch), mytargets.end());
1028 }
1029 // if we can't order it in a 1000 steps we give up… probably a cycle
1030 for (auto i = 0; i < 1000; ++i)
1031 {
1032 bool Changed = false;
1033 for (auto t = mytargets.begin(); t != mytargets.end(); ++t)
1034 {
1035 std::string const fallback = _config->Find(std::string("Acquire::IndexTargets::") + Name + "::" + *t + "::Fallback-Of");
1036 if (fallback.empty())
1037 continue;
1038 auto const faller = std::find(mytargets.begin(), mytargets.end(), fallback);
1039 if (faller == mytargets.end() || faller < t)
1040 continue;
1041 Changed = true;
1042 auto const tv = *t;
1043 mytargets.erase(t);
1044 mytargets.emplace_back(tv);
1045 }
1046 if (Changed == false)
1047 break;
1048 }
1049 // remove duplicates without changing the order (in first appearance)
1050 {
1051 std::set<std::string> seenOnce;
1052 mytargets.erase(std::remove_if(mytargets.begin(), mytargets.end(), [&](std::string const &t) {
1053 return seenOnce.insert(t).second == false;
1054 }), mytargets.end());
1055 }
1056
1057 bool const UsePDiffs = GetBoolOption(Options, "pdiffs", _config->FindB("Acquire::PDiffs", true));
1058
1059 std::string UseByHash = _config->Find("APT::Acquire::By-Hash", "yes");
1060 UseByHash = _config->Find("Acquire::By-Hash", UseByHash);
1061 {
1062 std::string const host = ::URI(URI).Host;
1063 UseByHash = _config->Find("APT::Acquire::" + host + "::By-Hash", UseByHash);
1064 UseByHash = _config->Find("Acquire::" + host + "::By-Hash", UseByHash);
1065 std::map<std::string, std::string>::const_iterator const opt = Options.find("by-hash");
1066 if (opt != Options.end())
1067 UseByHash = opt->second;
1068 }
1069
1070 auto const entry = Options.find("sourceslist-entry");
1071 Deb->AddComponent(
1072 entry->second,
1073 IsSrc,
1074 Section,
1075 mytargets,
1076 parsePlusMinusOptions("arch", Options, APT::Configuration::getArchitectures()),
1077 parsePlusMinusOptions("lang", Options, APT::Configuration::getLanguages(true)),
1078 UsePDiffs,
1079 UseByHash
1080 );
1081
1082 if (Deb->SetTrusted(GetTriStateOption(Options, "trusted")) == false ||
1083 Deb->SetCheckValidUntil(GetTriStateOption(Options, "check-valid-until")) == false ||
1084 Deb->SetValidUntilMax(GetTimeOption(Options, "valid-until-max")) == false ||
1085 Deb->SetValidUntilMin(GetTimeOption(Options, "valid-until-min")) == false)
1086 return false;
1087
1088 std::map<std::string, std::string>::const_iterator const signedby = Options.find("signed-by");
1089 if (signedby == Options.end())
1090 {
1091 bool alreadySet = false;
1092 std::string filename;
1093 if (ReleaseFileName(Deb, filename))
1094 {
1095 auto OldDeb = Deb->UnloadedClone();
1096 _error->PushToStack();
1097 OldDeb->Load(filename, nullptr);
1098 bool const goodLoad = _error->PendingError() == false;
1099 _error->RevertToStack();
1100 if (goodLoad)
1101 {
1102 if (OldDeb->GetValidUntil() > 0)
1103 {
1104 time_t const invalid_since = time(NULL) - OldDeb->GetValidUntil();
1105 if (invalid_since <= 0)
1106 {
1107 Deb->SetSignedBy(OldDeb->GetSignedBy());
1108 alreadySet = true;
1109 }
1110 }
1111 }
1112 delete OldDeb;
1113 }
1114 if (alreadySet == false && Deb->SetSignedBy("") == false)
1115 return false;
1116 }
1117 else
1118 {
1119 if (Deb->SetSignedBy(signedby->second) == false)
1120 return false;
1121 }
1122
1123 return true;
1124 }
1125
1126 debSLTypeDebian(char const * const Name, char const * const Label) : Type(Name, Label)
1127 {
1128 }
1129 };
1130 /*}}}*/
1131 class APT_HIDDEN debSLTypeDeb : public debSLTypeDebian /*{{{*/
1132 {
1133 public:
1134
1135 bool CreateItem(std::vector<metaIndex *> &List, std::string const &URI,
1136 std::string const &Dist, std::string const &Section,
1137 std::map<std::string, std::string> const &Options) const APT_OVERRIDE
1138 {
1139 return CreateItemInternal(List, URI, Dist, Section, false, Options);
1140 }
1141
1142 debSLTypeDeb() : debSLTypeDebian("deb", "Debian binary tree")
1143 {
1144 }
1145 };
1146 /*}}}*/
1147 class APT_HIDDEN debSLTypeDebSrc : public debSLTypeDebian /*{{{*/
1148 {
1149 public:
1150
1151 bool CreateItem(std::vector<metaIndex *> &List, std::string const &URI,
1152 std::string const &Dist, std::string const &Section,
1153 std::map<std::string, std::string> const &Options) const APT_OVERRIDE
1154 {
1155 return CreateItemInternal(List, URI, Dist, Section, true, Options);
1156 }
1157
1158 debSLTypeDebSrc() : debSLTypeDebian("deb-src", "Debian source tree")
1159 {
1160 }
1161 };
1162 /*}}}*/
1163
1164 APT_HIDDEN debSLTypeDeb _apt_DebType;
1165 APT_HIDDEN debSLTypeDebSrc _apt_DebSrcType;