]> git.saurik.com Git - apt.git/blame - apt-pkg/deb/debmetaindex.cc
cache: Bump minor version to 6
[apt.git] / apt-pkg / deb / debmetaindex.cc
CommitLineData
ea542140 1#include <config.h>
7db98ffc 2
b07aeb1a 3#include <apt-pkg/error.h>
7db98ffc
MZ
4#include <apt-pkg/debmetaindex.h>
5#include <apt-pkg/debindexfile.h>
6#include <apt-pkg/strutl.h>
472ff00e 7#include <apt-pkg/fileutl.h>
7db98ffc
MZ
8#include <apt-pkg/acquire-item.h>
9#include <apt-pkg/configuration.h>
45df0ad2 10#include <apt-pkg/aptconfiguration.h>
472ff00e 11#include <apt-pkg/sourcelist.h>
453b82a3 12#include <apt-pkg/hashes.h>
453b82a3 13#include <apt-pkg/metaindex.h>
b07aeb1a
DK
14#include <apt-pkg/pkgcachegen.h>
15#include <apt-pkg/tagfile.h>
16#include <apt-pkg/gpgv.h>
17#include <apt-pkg/macros.h>
7db98ffc 18
453b82a3
DK
19#include <map>
20#include <string>
21#include <utility>
22#include <vector>
7cb28948 23#include <algorithm>
d7a51997 24#include <sstream>
5dd4c8b8 25
b07aeb1a 26#include <sys/stat.h>
b07aeb1a
DK
27#include <string.h>
28
268ffceb
DK
29#include <apti18n.h>
30
463c8d80
DK
31class APT_HIDDEN debReleaseIndexPrivate /*{{{*/
32{
33 public:
34 struct APT_HIDDEN debSectionEntry
35 {
7f2d1eef
DK
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;
463c8d80
DK
43 };
44
45 std::vector<debSectionEntry> DebEntries;
46 std::vector<debSectionEntry> DebSrcEntries;
268ffceb 47
0741daeb
DK
48 metaIndex::TriState CheckValidUntil;
49 time_t ValidUntilMin;
50 time_t ValidUntilMax;
51
1dd20368 52 std::vector<std::string> Architectures;
a628ca52 53 std::vector<std::string> NoSupportForAll;
d03b947b 54 std::map<std::string, std::string> const ReleaseOptions;
1dd20368 55
d03b947b 56 debReleaseIndexPrivate(std::map<std::string, std::string> const &Options) : CheckValidUntil(metaIndex::TRI_UNSET), ValidUntilMin(0), ValidUntilMax(0), ReleaseOptions(Options) {}
463c8d80
DK
57};
58 /*}}}*/
59// ReleaseIndex::MetaIndex* - display helpers /*{{{*/
60std::string debReleaseIndex::MetaIndexInfo(const char *Type) const
7db98ffc 61{
463c8d80 62 std::string Info = ::URI::ArchiveOnly(URI) + ' ';
7db98ffc
MZ
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}
b07aeb1a
DK
74std::string debReleaseIndex::Describe() const
75{
76 return MetaIndexInfo("Release");
77}
7db98ffc 78
463c8d80 79std::string debReleaseIndex::MetaIndexFile(const char *Type) const
7db98ffc
MZ
80{
81 return _config->FindDir("Dir::State::lists") +
82 URItoFileName(MetaIndexURI(Type));
83}
b90faf24 84static std::string constructMetaIndexURI(std::string URI, std::string const &Dist, char const * const Type)
7db98ffc 85{
7db98ffc 86 if (Dist == "/")
b90faf24 87 ;
7db98ffc 88 else if (Dist[Dist.size()-1] == '/')
b90faf24 89 URI += Dist;
7db98ffc 90 else
b90faf24
DK
91 URI += "dists/" + Dist + "/";
92 return URI + Type;
93}
94std::string debReleaseIndex::MetaIndexURI(const char *Type) const
95{
96 return constructMetaIndexURI(URI, Dist, Type);
7db98ffc 97}
463c8d80 98 /*}}}*/
463c8d80 99// ReleaseIndex Con- and Destructors /*{{{*/
d03b947b
DK
100debReleaseIndex::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))
4b42f43b 102{}
d03b947b
DK
103debReleaseIndex::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))
5ad0096a
DK
105{
106 Trusted = pTrusted ? TRI_YES : TRI_NO;
107}
5dd4c8b8 108debReleaseIndex::~debReleaseIndex() {
463c8d80
DK
109 if (d != NULL)
110 delete d;
7a9f09bd 111}
463c8d80
DK
112 /*}}}*/
113// ReleaseIndex::GetIndexTargets /*{{{*/
114static void GetIndexTargetsFor(char const * const Type, std::string const &URI, std::string const &Dist,
115 std::vector<debReleaseIndexPrivate::debSectionEntry> const &entries,
d03b947b 116 std::vector<IndexTarget> &IndexTargets, std::map<std::string, std::string> const &ReleaseOptions)
1e0f0f28 117{
1e0f0f28 118 bool const flatArchive = (Dist[Dist.length() - 1] == '/');
d03b947b 119 std::string const baseURI = constructMetaIndexURI(URI, Dist, "");
1e0f0f28 120 std::string const Release = (Dist == "/") ? "" : Dist;
1da3b7b8 121 std::string const Site = ::URI::ArchiveOnly(URI);
463c8d80 122
d7a51997
DK
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 }
0179cfa8
DK
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 }
7c1dca14
DK
149
150 std::vector<std::string> const NativeArchs = { _config->Find("APT::Architecture"), "all" };
653ef26c 151 bool const GzipIndex = _config->FindB("Acquire::GzipIndexes", false);
463c8d80 152 for (std::vector<debReleaseIndexPrivate::debSectionEntry>::const_iterator E = entries.begin(); E != entries.end(); ++E)
1e0f0f28 153 {
463c8d80 154 for (std::vector<std::string>::const_iterator T = E->Targets.begin(); T != E->Targets.end(); ++T)
1e0f0f28 155 {
d7a51997
DK
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", "");
39c724b4 161 std::string const tplIdentifier = APT_T_CONFIG_STR("Identifier", *T);
d7a51997
DK
162 bool const IsOptional = APT_T_CONFIG_BOOL("Optional", true);
163 bool const KeepCompressed = APT_T_CONFIG_BOOL("KeepCompressed", GzipIndex);
9adb9778 164 bool const DefaultEnabled = APT_T_CONFIG_BOOL("DefaultEnabled", true);
d7a51997 165 bool const UsePDiffs = APT_T_CONFIG_BOOL("PDiffs", E->UsePDiffs);
24e8f24e 166 std::string const UseByHash = APT_T_CONFIG_STR("By-Hash", E->UseByHash);
d7a51997 167 std::string const CompressionTypes = APT_T_CONFIG_STR("CompressionTypes", DefCompressionTypes);
0179cfa8 168 std::string KeepCompressedAs = APT_T_CONFIG_STR("KeepCompressedAs", "");
7f2d1eef 169 std::string const FallbackOf = APT_T_CONFIG_STR("Fallback-Of", "");
d7a51997
DK
170#undef APT_T_CONFIG_BOOL
171#undef APT_T_CONFIG_STR
463c8d80 172 if (tplMetaKey.empty())
1e0f0f28
DK
173 continue;
174
0179cfa8
DK
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
463c8d80 198 for (std::vector<std::string>::const_iterator L = E->Languages.begin(); L != E->Languages.end(); ++L)
1e0f0f28 199 {
463c8d80
DK
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)
1e0f0f28 204 {
7c1dca14 205 for (auto const &NativeArch: NativeArchs)
463c8d80 206 {
7c1dca14
DK
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));
d7a51997 222
7c1dca14
DK
223 std::string MetaKey = tplMetaKey;
224 std::string ShortDesc = tplShortDesc;
225 std::string LongDesc = tplLongDesc;
39c724b4 226 std::string Identifier = tplIdentifier;
7c1dca14 227 for (std::map<std::string, std::string>::const_iterator O = Options.begin(); O != Options.end(); ++O)
3090ae69 228 {
39c724b4
DK
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);
3090ae69 234 }
3090ae69 235
3090ae69 236 {
7c1dca14
DK
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 }
3090ae69 247 }
3090ae69 248
3090ae69 249 {
7c1dca14
DK
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 }
3090ae69 267 }
3090ae69 268
7c1dca14
DK
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 }
d7a51997 287
7c1dca14 288 // not available in templates, but in the indextarget
d03b947b 289 Options.insert(ReleaseOptions.begin(), ReleaseOptions.end());
39c724b4 290 Options.insert(std::make_pair("IDENTIFIER", Identifier));
7c1dca14
DK
291 Options.insert(std::make_pair("TARGET_OF", Type));
292 Options.insert(std::make_pair("CREATED_BY", *T));
7f2d1eef 293 Options.insert(std::make_pair("FALLBACK_OF", FallbackOf));
7c1dca14
DK
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));
1dd20368 300
7c1dca14
DK
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,
d03b947b 313 baseURI + MetaKey,
7c1dca14
DK
314 IsOpt,
315 KeepCompressed,
316 Options
317 );
318 IndexTargets.push_back(Target);
319
320 if (tplMetaKey.find(BreakPoint) == std::string::npos)
321 break;
322 }
463c8d80
DK
323
324 if (tplMetaKey.find("$(ARCHITECTURE)") == std::string::npos)
1e0f0f28 325 break;
d3a869e3 326
1e0f0f28
DK
327 }
328
463c8d80 329 if (tplMetaKey.find("$(LANGUAGE)") == std::string::npos)
1e0f0f28 330 break;
463c8d80 331
1e0f0f28
DK
332 }
333
1e0f0f28
DK
334 }
335 }
59148d96 336}
261727f0 337std::vector<IndexTarget> debReleaseIndex::GetIndexTargets() const
59148d96 338{
463c8d80 339 std::vector<IndexTarget> IndexTargets;
d03b947b
DK
340 GetIndexTargetsFor("deb-src", URI, Dist, d->DebSrcEntries, IndexTargets, d->ReleaseOptions);
341 GetIndexTargetsFor("deb", URI, Dist, d->DebEntries, IndexTargets, d->ReleaseOptions);
463c8d80 342 return IndexTargets;
7db98ffc 343}
463c8d80 344 /*}}}*/
3090ae69
DK
345void debReleaseIndex::AddComponent(std::string const &sourcesEntry, /*{{{*/
346 bool const isSrc, std::string const &Name,
463c8d80
DK
347 std::vector<std::string> const &Targets,
348 std::vector<std::string> const &Architectures,
1a3a14ac 349 std::vector<std::string> Languages,
24e8f24e 350 bool const usePDiffs, std::string const &useByHash)
463c8d80
DK
351{
352 if (Languages.empty() == true)
353 Languages.push_back("none");
354 debReleaseIndexPrivate::debSectionEntry const entry = {
24e8f24e 355 sourcesEntry, Name, Targets, Architectures, Languages, usePDiffs, useByHash
463c8d80
DK
356 };
357 if (isSrc)
358 d->DebSrcEntries.push_back(entry);
359 else
360 d->DebEntries.push_back(entry);
361}
362 /*}}}*/
59148d96 363
5ad0096a
DK
364bool 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());
95278287 372 if (Fd.IsOpen() == false || Fd.Failed())
5ad0096a
DK
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");
1dd20368
DK
392 {
393 std::string const archs = Section.FindS("Architectures");
394 if (archs.empty() == false)
395 d->Architectures = VectorizeString(archs, ' ');
396 }
a628ca52
DK
397 {
398 std::string const targets = Section.FindS("No-Support-for-Architecture-all");
399 if (targets.empty() == false)
400 d->NoSupportForAll = VectorizeString(targets, ' ');
401 }
5ad0096a
DK
402
403 bool FoundHashSum = false;
bd4a8f51
DK
404 bool FoundStrongHashSum = false;
405 auto const SupportedHashes = HashString::SupportedHashes();
406 for (int i=0; SupportedHashes[i] != NULL; i++)
5ad0096a 407 {
bd4a8f51 408 if (!Section.Find(SupportedHashes[i], Start, End))
5ad0096a
DK
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
bd4a8f51 419 HashString const hs(SupportedHashes[i], Hash);
5ad0096a
DK
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);
bd4a8f51 426 APT_IGNORE_DEPRECATED(Sum->Hash = hs;)
5ad0096a
DK
427 Entries[Name] = Sum;
428 }
bd4a8f51 429 Entries[Name]->Hashes.push_back(hs);
5ad0096a 430 FoundHashSum = true;
bd4a8f51
DK
431 if (FoundStrongHashSum == false && hs.usable() == true)
432 FoundStrongHashSum = true;
5ad0096a
DK
433 }
434 }
435
ab94dcec 436 bool AuthPossible = false;
5ad0096a 437 if(FoundHashSum == false)
ab94dcec
DK
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;
5ad0096a
DK
443
444 std::string const StrDate = Section.FindS("Date");
445 if (RFC1123StrToTime(StrDate.c_str(), Date) == false)
446 {
89901946 447 _error->Warning( _("Invalid '%s' entry in Release file %s"), "Date", Filename.c_str());
6fc2e030 448 Date = 0;
5ad0096a
DK
449 }
450
0741daeb
DK
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;
5ad0096a 456
0741daeb 457 if (CheckValidUntil == true)
5ad0096a 458 {
0741daeb
DK
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)
5ad0096a 464 {
0741daeb
DK
465 if(RFC1123StrToTime(StrValidUntil.c_str(), ValidUntil) == false)
466 {
467 if (ErrorText != NULL)
89901946 468 strprintf(*ErrorText, _("Invalid '%s' entry in Release file %s"), "Valid-Until", Filename.c_str());
0741daeb
DK
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);
5ad0096a 486 }
5ad0096a 487
6fc2e030
DK
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 }
0741daeb 500 }
5ad0096a 501 }
59148d96 502
89901946
DK
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
ab94dcec
DK
530 if (AuthPossible)
531 LoadedSuccessfully = TRI_YES;
532 return AuthPossible;
5ad0096a
DK
533}
534 /*}}}*/
535metaIndex * debReleaseIndex::UnloadedClone() const /*{{{*/
536{
537 if (Trusted == TRI_NO)
d03b947b 538 return new debReleaseIndex(URI, Dist, false, d->ReleaseOptions);
5ad0096a 539 else if (Trusted == TRI_YES)
d03b947b 540 return new debReleaseIndex(URI, Dist, true, d->ReleaseOptions);
5ad0096a 541 else
d03b947b 542 return new debReleaseIndex(URI, Dist, d->ReleaseOptions);
5ad0096a
DK
543}
544 /*}}}*/
545bool debReleaseIndex::parseSumData(const char *&Start, const char *End, /*{{{*/
546 std::string &Name, std::string &Hash, unsigned long long &Size)
7db98ffc 547{
5ad0096a
DK
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;
07cb47e7 557
5ad0096a
DK
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
605bool debReleaseIndex::GetIndexes(pkgAcquire *Owner, bool const &GetAll)/*{{{*/
606{
d03b947b 607#define APT_TARGET(X) IndexTarget("", X, MetaIndexInfo(X), MetaIndexURI(X), false, false, d->ReleaseOptions)
3d8232bf 608 pkgAcqMetaClearSig * const TransactionManager = new pkgAcqMetaClearSig(Owner,
a8f565d3 609 APT_TARGET("InRelease"), APT_TARGET("Release"), APT_TARGET("Release.gpg"), this);
448c38bd 610#undef APT_TARGET
5ad0096a 611 // special case for --print-uris
448c38bd 612 if (GetAll)
a8f565d3 613 for (auto const &Target: GetIndexTargets())
7f2d1eef
DK
614 if (Target.Option(IndexTarget::FALLBACK_OF).empty())
615 new pkgAcqIndex(Owner, TransactionManager, Target);
fe0f7911 616
55971004 617 return true;
7db98ffc 618}
463c8d80 619 /*}}}*/
0741daeb 620// ReleaseIndex::Set* TriState options /*{{{*/
5ad0096a 621bool debReleaseIndex::SetTrusted(TriState const pTrusted)
4b42f43b 622{
5ad0096a
DK
623 if (Trusted == TRI_UNSET)
624 Trusted = pTrusted;
625 else if (Trusted != pTrusted)
268ffceb 626 // TRANSLATOR: The first is an option name from sources.list manpage, the other two URI and Suite
d04e44ac 627 return _error->Error(_("Conflicting values set for option %s regarding source %s %s"), "Trusted", URI.c_str(), Dist.c_str());
268ffceb 628 return true;
4b42f43b 629}
0741daeb
DK
630bool debReleaseIndex::SetCheckValidUntil(TriState const pCheckValidUntil)
631{
632 if (d->CheckValidUntil == TRI_UNSET)
633 d->CheckValidUntil = pCheckValidUntil;
634 else if (d->CheckValidUntil != pCheckValidUntil)
d04e44ac 635 return _error->Error(_("Conflicting values set for option %s regarding source %s %s"), "Check-Valid-Until", URI.c_str(), Dist.c_str());
0741daeb
DK
636 return true;
637}
638bool debReleaseIndex::SetValidUntilMin(time_t const Valid)
639{
640 if (d->ValidUntilMin == 0)
641 d->ValidUntilMin = Valid;
642 else if (d->ValidUntilMin != Valid)
d04e44ac 643 return _error->Error(_("Conflicting values set for option %s regarding source %s %s"), "Min-ValidTime", URI.c_str(), Dist.c_str());
0741daeb
DK
644 return true;
645}
646bool debReleaseIndex::SetValidUntilMax(time_t const Valid)
647{
648 if (d->ValidUntilMax == 0)
649 d->ValidUntilMax = Valid;
650 else if (d->ValidUntilMax != Valid)
d04e44ac 651 return _error->Error(_("Conflicting values set for option %s regarding source %s %s"), "Max-ValidTime", URI.c_str(), Dist.c_str());
0741daeb 652 return true;
b0d40854
DK
653}
654bool 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
46e00c90 659 SignedBy = pSignedBy; // absolute path to a keyring file
b0d40854
DK
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.
46e00c90
DK
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();
b0d40854 678 }
71203dbf
JAK
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());
b0d40854 690 }
b0d40854 691 return true;
0741daeb
DK
692}
693 /*}}}*/
694// ReleaseIndex::IsTrusted /*{{{*/
7db98ffc
MZ
695bool debReleaseIndex::IsTrusted() const
696{
5ad0096a 697 if (Trusted == TRI_YES)
4b42f43b 698 return true;
5ad0096a 699 else if (Trusted == TRI_NO)
4b42f43b
DK
700 return false;
701
702
4e0ad446 703 if(_config->FindB("APT::Authentication::TrustCDROM", false))
e8cdc56a
MV
704 if(URI.substr(0,strlen("cdrom:")) == "cdrom:")
705 return true;
fe0f7911 706
463c8d80 707 if (FileExists(MetaIndexFile("Release.gpg")))
7db98ffc 708 return true;
fe0f7911 709
463c8d80 710 return FileExists(MetaIndexFile("InRelease"));
7db98ffc 711}
463c8d80 712 /*}}}*/
1dd20368
DK
713bool 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 /*}}}*/
a628ca52
DK
720bool 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 /*}}}*/
463c8d80 727std::vector <pkgIndexFile *> *debReleaseIndex::GetIndexFiles() /*{{{*/
59148d96 728{
e3c1cfc7
DK
729 if (Indexes != NULL)
730 return Indexes;
59148d96 731
e3c1cfc7 732 Indexes = new std::vector<pkgIndexFile*>();
e3c1cfc7 733 bool const istrusted = IsTrusted();
8dd562a8 734 for (auto const &T: GetIndexTargets())
59148d96 735 {
8dd562a8 736 std::string const TargetName = T.Option(IndexTarget::CREATED_BY);
59148d96 737 if (TargetName == "Packages")
8dd562a8 738 Indexes->push_back(new debPackagesIndex(T, istrusted));
59148d96 739 else if (TargetName == "Sources")
8dd562a8 740 Indexes->push_back(new debSourcesIndex(T, istrusted));
59148d96 741 else if (TargetName == "Translations")
8dd562a8 742 Indexes->push_back(new debTranslationsIndex(T));
59148d96 743 }
e3c1cfc7 744 return Indexes;
5dd4c8b8 745}
463c8d80 746 /*}}}*/
d03b947b
DK
747std::map<std::string, std::string> debReleaseIndex::GetReleaseOptions()
748{
749 return d->ReleaseOptions;
750}
a7a5b0d9 751
463c8d80 752static bool ReleaseFileName(debReleaseIndex const * const That, std::string &ReleaseFile)/*{{{*/
b07aeb1a
DK
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}
463c8d80 766 /*}}}*/
b07aeb1a
DK
767bool 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;
b07aeb1a
DK
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;
95278287 797 if (Rel.IsOpen() == false || Rel.Failed() || TagFile.Step(Section) == false)
b07aeb1a
DK
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); \
95278287 806 if (storage == 0) return false; \
b07aeb1a
DK
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
95278287 818 return true;
b07aeb1a
DK
819}
820 /*}}}*/
821// ReleaseIndex::FindInCache - Find this index /*{{{*/
3fd89e62 822pkgCache::RlsFileIterator debReleaseIndex::FindInCache(pkgCache &Cache, bool const ModifyCheck) const
b07aeb1a
DK
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"
3fd89e62 834 if (ModifyCheck == false || (releaseExists == false && File->Size == 0))
b07aeb1a
DK
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
463c8d80
DK
859static std::vector<std::string> parsePlusMinusOptions(std::string const &Name, /*{{{*/
860 std::map<std::string, std::string> const &Options, std::vector<std::string> const &defaultValues)
7db98ffc 861{
463c8d80
DK
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;
7db98ffc 868
1dd20368
DK
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
463c8d80 873 if ((val = Options.find(Name + "+")) != Options.end())
7db98ffc 874 {
8dd562a8
DK
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 });
463c8d80
DK
879 }
880 if ((val = Options.find(Name + "-")) != Options.end())
881 {
8dd562a8
DK
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());
463c8d80
DK
886 }
887 return Values;
888}
889 /*}}}*/
890class APT_HIDDEN debSLTypeDebian : public pkgSourceList::Type /*{{{*/
891{
0741daeb
DK
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
d03b947b 900 static time_t GetTimeOption(std::map<std::string, std::string>const &Options, char const * const name)
0741daeb
DK
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
d03b947b
DK
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
463c8d80 959 protected:
3d1be93d 960
463c8d80
DK
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 {
d03b947b
DK
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
b90faf24
DK
976 debReleaseIndex * Deb = nullptr;
977 std::string const FileName = URItoFileName(constructMetaIndexURI(URI, Dist, "Release"));
978 for (auto const &I: List)
7db98ffc 979 {
5dd4c8b8 980 // We only worry about debian entries here
b90faf24 981 if (strcmp(I->GetType(), "deb") != 0)
5dd4c8b8
DK
982 continue;
983
b90faf24
DK
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
5dd4c8b8
DK
989 queued for all the Packages files and Sources files it
990 corresponds to. */
b90faf24 991 if (URItoFileName(D->MetaIndexURI("Release")) == FileName)
7db98ffc 992 {
d03b947b
DK
993 if (MapsAreEqual(ReleaseOptions, D->GetReleaseOptions(), URI, Dist) == false)
994 return false;
b90faf24
DK
995 Deb = D;
996 break;
7db98ffc
MZ
997 }
998 }
4b42f43b 999
7db98ffc 1000 // No currently created Release file indexes this entry, so we create a new one.
b90faf24 1001 if (Deb == nullptr)
261727f0 1002 {
d03b947b 1003 Deb = new debReleaseIndex(URI, Dist, ReleaseOptions);
261727f0
DK
1004 List.push_back(Deb);
1005 }
4b42f43b 1006
e6a12ff7 1007 std::vector<std::string> const alltargets = _config->FindVector(std::string("Acquire::IndexTargets::") + Name, "", true);
9adb9778
DK
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);
8dd562a8
DK
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;
39c724b4
DK
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());
8dd562a8 1028 }
7f2d1eef
DK
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 }
39c724b4
DK
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 }
8dd562a8 1056
d03b947b 1057 bool const UsePDiffs = GetBoolOption(Options, "pdiffs", _config->FindB("Acquire::PDiffs", true));
8dd562a8 1058
24e8f24e
DK
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
3090ae69 1070 auto const entry = Options.find("sourceslist-entry");
463c8d80 1071 Deb->AddComponent(
3090ae69 1072 entry->second,
463c8d80
DK
1073 IsSrc,
1074 Section,
e6a12ff7 1075 mytargets,
463c8d80 1076 parsePlusMinusOptions("arch", Options, APT::Configuration::getArchitectures()),
1a3a14ac 1077 parsePlusMinusOptions("lang", Options, APT::Configuration::getLanguages(true)),
24e8f24e
DK
1078 UsePDiffs,
1079 UseByHash
463c8d80 1080 );
261727f0 1081
0741daeb
DK
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)
268ffceb 1086 return false;
261727f0 1087
b0d40854
DK
1088 std::map<std::string, std::string>::const_iterator const signedby = Options.find("signed-by");
1089 if (signedby == Options.end())
1090 {
89901946
DK
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)
b0d40854
DK
1115 return false;
1116 }
1117 else
1118 {
1119 if (Deb->SetSignedBy(signedby->second) == false)
1120 return false;
1121 }
1122
7db98ffc
MZ
1123 return true;
1124 }
0d29b9d4 1125
463c8d80
DK
1126 debSLTypeDebian(char const * const Name, char const * const Label) : Type(Name, Label)
1127 {
1128 }
1129};
1130 /*}}}*/
1131class APT_HIDDEN debSLTypeDeb : public debSLTypeDebian /*{{{*/
7db98ffc
MZ
1132{
1133 public:
1134
463c8d80
DK
1135 bool CreateItem(std::vector<metaIndex *> &List, std::string const &URI,
1136 std::string const &Dist, std::string const &Section,
3b302846 1137 std::map<std::string, std::string> const &Options) const APT_OVERRIDE
7db98ffc 1138 {
5dd4c8b8 1139 return CreateItemInternal(List, URI, Dist, Section, false, Options);
7db98ffc
MZ
1140 }
1141
463c8d80 1142 debSLTypeDeb() : debSLTypeDebian("deb", "Debian binary tree")
7db98ffc 1143 {
463c8d80 1144 }
7db98ffc 1145};
463c8d80
DK
1146 /*}}}*/
1147class APT_HIDDEN debSLTypeDebSrc : public debSLTypeDebian /*{{{*/
7db98ffc
MZ
1148{
1149 public:
1150
463c8d80
DK
1151 bool CreateItem(std::vector<metaIndex *> &List, std::string const &URI,
1152 std::string const &Dist, std::string const &Section,
3b302846 1153 std::map<std::string, std::string> const &Options) const APT_OVERRIDE
7db98ffc 1154 {
5dd4c8b8 1155 return CreateItemInternal(List, URI, Dist, Section, true, Options);
7db98ffc 1156 }
463c8d80
DK
1157
1158 debSLTypeDebSrc() : debSLTypeDebian("deb-src", "Debian source tree")
7db98ffc 1159 {
463c8d80 1160 }
7db98ffc 1161};
463c8d80 1162 /*}}}*/
7db98ffc 1163
dce45dbe
DK
1164APT_HIDDEN debSLTypeDeb _apt_DebType;
1165APT_HIDDEN debSLTypeDebSrc _apt_DebSrcType;