]> git.saurik.com Git - apt.git/blob - apt-pkg/deb/debmetaindex.cc
1f725ba0506aec4ce294455468171935b18cd829
[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/indexrecords.h>
12 #include <apt-pkg/sourcelist.h>
13 #include <apt-pkg/hashes.h>
14 #include <apt-pkg/metaindex.h>
15 #include <apt-pkg/pkgcachegen.h>
16 #include <apt-pkg/tagfile.h>
17 #include <apt-pkg/gpgv.h>
18 #include <apt-pkg/macros.h>
19
20 #include <map>
21 #include <string>
22 #include <utility>
23 #include <vector>
24 #include <set>
25 #include <algorithm>
26
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <unistd.h>
30 #include <string.h>
31
32 #include <apti18n.h>
33
34 class APT_HIDDEN debReleaseIndexPrivate /*{{{*/
35 {
36 public:
37 struct APT_HIDDEN debSectionEntry
38 {
39 std::string Name;
40 std::vector<std::string> Targets;
41 std::vector<std::string> Architectures;
42 std::vector<std::string> Languages;
43 };
44
45 std::vector<debSectionEntry> DebEntries;
46 std::vector<debSectionEntry> DebSrcEntries;
47
48 debReleaseIndex::TriState Trusted;
49
50 debReleaseIndexPrivate() : Trusted(debReleaseIndex::TRI_UNSET) {}
51 debReleaseIndexPrivate(bool const pTrusted) : Trusted(pTrusted ? debReleaseIndex::TRI_YES : debReleaseIndex::TRI_NO) {}
52 };
53 /*}}}*/
54 // ReleaseIndex::MetaIndex* - display helpers /*{{{*/
55 std::string debReleaseIndex::MetaIndexInfo(const char *Type) const
56 {
57 std::string Info = ::URI::ArchiveOnly(URI) + ' ';
58 if (Dist[Dist.size() - 1] == '/')
59 {
60 if (Dist != "/")
61 Info += Dist;
62 }
63 else
64 Info += Dist;
65 Info += " ";
66 Info += Type;
67 return Info;
68 }
69 std::string debReleaseIndex::Describe() const
70 {
71 return MetaIndexInfo("Release");
72 }
73
74 std::string debReleaseIndex::MetaIndexFile(const char *Type) const
75 {
76 return _config->FindDir("Dir::State::lists") +
77 URItoFileName(MetaIndexURI(Type));
78 }
79
80 std::string debReleaseIndex::MetaIndexURI(const char *Type) const
81 {
82 std::string Res;
83
84 if (Dist == "/")
85 Res = URI;
86 else if (Dist[Dist.size()-1] == '/')
87 Res = URI + Dist;
88 else
89 Res = URI + "dists/" + Dist + "/";
90
91 Res += Type;
92 return Res;
93 }
94 /*}}}*/
95 std::string debReleaseIndex::LocalFileName() const /*{{{*/
96 {
97 // see if we have a InRelease file
98 std::string PathInRelease = MetaIndexFile("InRelease");
99 if (FileExists(PathInRelease))
100 return PathInRelease;
101
102 // and if not return the normal one
103 if (FileExists(PathInRelease))
104 return MetaIndexFile("Release");
105
106 return "";
107 }
108 /*}}}*/
109 // ReleaseIndex Con- and Destructors /*{{{*/
110 debReleaseIndex::debReleaseIndex(std::string const &URI, std::string const &Dist) :
111 metaIndex(URI, Dist, "deb"), d(new debReleaseIndexPrivate())
112 {}
113 debReleaseIndex::debReleaseIndex(std::string const &URI, std::string const &Dist, bool const Trusted) :
114 metaIndex(URI, Dist, "deb"), d(new debReleaseIndexPrivate(Trusted))
115 {}
116 debReleaseIndex::~debReleaseIndex() {
117 if (d != NULL)
118 delete d;
119 }
120 /*}}}*/
121 // ReleaseIndex::GetIndexTargets /*{{{*/
122 static void GetIndexTargetsFor(char const * const Type, std::string const &URI, std::string const &Dist,
123 std::vector<debReleaseIndexPrivate::debSectionEntry> const &entries,
124 std::vector<IndexTarget> &IndexTargets)
125 {
126 bool const flatArchive = (Dist[Dist.length() - 1] == '/');
127 std::string baseURI = URI;
128 if (flatArchive)
129 {
130 if (Dist != "/")
131 baseURI += Dist;
132 }
133 else
134 baseURI += "dists/" + Dist + "/";
135 std::string const Release = (Dist == "/") ? "" : Dist;
136 std::string const Site = ::URI::ArchiveOnly(URI);
137
138 for (std::vector<debReleaseIndexPrivate::debSectionEntry>::const_iterator E = entries.begin(); E != entries.end(); ++E)
139 {
140 for (std::vector<std::string>::const_iterator T = E->Targets.begin(); T != E->Targets.end(); ++T)
141 {
142 #define APT_T_CONFIG(X) _config->Find(std::string("APT::Acquire::Targets::") + Type + "::" + *T + "::" + (X))
143 std::string const tplMetaKey = APT_T_CONFIG(flatArchive ? "flatMetaKey" : "MetaKey");
144 std::string const tplShortDesc = APT_T_CONFIG("ShortDescription");
145 std::string const tplLongDesc = APT_T_CONFIG(flatArchive ? "flatDescription" : "Description");
146 bool const IsOptional = _config->FindB(std::string("APT::Acquire::Targets::deb-src::") + *T + "::Optional", true);
147 #undef APT_T_CONFIG
148 if (tplMetaKey.empty())
149 continue;
150
151 for (std::vector<std::string>::const_iterator L = E->Languages.begin(); L != E->Languages.end(); ++L)
152 {
153 if (*L == "none" && tplMetaKey.find("$(LANGUAGE)") != std::string::npos)
154 continue;
155
156 for (std::vector<std::string>::const_iterator A = E->Architectures.begin(); A != E->Architectures.end(); ++A)
157 {
158
159 std::map<std::string, std::string> Options;
160 Options.insert(std::make_pair("SITE", Site));
161 Options.insert(std::make_pair("RELEASE", Release));
162 if (tplMetaKey.find("$(COMPONENT)") != std::string::npos)
163 Options.insert(std::make_pair("COMPONENT", E->Name));
164 if (tplMetaKey.find("$(LANGUAGE)") != std::string::npos)
165 Options.insert(std::make_pair("LANGUAGE", *L));
166 if (tplMetaKey.find("$(ARCHITECTURE)") != std::string::npos)
167 Options.insert(std::make_pair("ARCHITECTURE", *A));
168 Options.insert(std::make_pair("BASE_URI", baseURI));
169 Options.insert(std::make_pair("REPO_URI", URI));
170 Options.insert(std::make_pair("TARGET_OF", "deb-src"));
171 Options.insert(std::make_pair("CREATED_BY", *T));
172
173 std::string MetaKey = tplMetaKey;
174 std::string ShortDesc = tplShortDesc;
175 std::string LongDesc = tplLongDesc;
176 for (std::map<std::string, std::string>::const_iterator O = Options.begin(); O != Options.end(); ++O)
177 {
178 MetaKey = SubstVar(MetaKey, std::string("$(") + O->first + ")", O->second);
179 ShortDesc = SubstVar(ShortDesc, std::string("$(") + O->first + ")", O->second);
180 LongDesc = SubstVar(LongDesc, std::string("$(") + O->first + ")", O->second);
181 }
182 IndexTarget Target(
183 MetaKey,
184 ShortDesc,
185 LongDesc,
186 Options.find("BASE_URI")->second + MetaKey,
187 IsOptional,
188 Options
189 );
190 IndexTargets.push_back(Target);
191
192 if (tplMetaKey.find("$(ARCHITECTURE)") == std::string::npos)
193 break;
194
195 }
196
197 if (tplMetaKey.find("$(LANGUAGE)") == std::string::npos)
198 break;
199
200 }
201
202 }
203 }
204 }
205 std::vector<IndexTarget> debReleaseIndex::GetIndexTargets() const
206 {
207 std::vector<IndexTarget> IndexTargets;
208 GetIndexTargetsFor("deb-src", URI, Dist, d->DebSrcEntries, IndexTargets);
209 GetIndexTargetsFor("deb", URI, Dist, d->DebEntries, IndexTargets);
210 return IndexTargets;
211 }
212 /*}}}*/
213 void debReleaseIndex::AddComponent(bool const isSrc, std::string const &Name,/*{{{*/
214 std::vector<std::string> const &Targets,
215 std::vector<std::string> const &Architectures,
216 std::vector<std::string> Languages)
217 {
218 if (Languages.empty() == true)
219 Languages.push_back("none");
220 debReleaseIndexPrivate::debSectionEntry const entry = {
221 Name, Targets, Architectures, Languages
222 };
223 if (isSrc)
224 d->DebSrcEntries.push_back(entry);
225 else
226 d->DebEntries.push_back(entry);
227 }
228 /*}}}*/
229
230
231 bool debReleaseIndex::GetIndexes(pkgAcquire *Owner, bool const &GetAll) const/*{{{*/
232 {
233 indexRecords * const iR = new indexRecords(Dist);
234 if (d->Trusted == TRI_YES)
235 iR->SetTrusted(true);
236 else if (d->Trusted == TRI_NO)
237 iR->SetTrusted(false);
238
239 // special case for --print-uris
240 std::vector<IndexTarget> const targets = GetIndexTargets();
241 #define APT_TARGET(X) IndexTarget("", X, MetaIndexInfo(X), MetaIndexURI(X), false, std::map<std::string,std::string>())
242 pkgAcqMetaClearSig * const TransactionManager = new pkgAcqMetaClearSig(Owner,
243 APT_TARGET("InRelease"), APT_TARGET("Release"), APT_TARGET("Release.gpg"),
244 targets, iR);
245 #undef APT_TARGET
246 if (GetAll)
247 {
248 for (std::vector<IndexTarget>::const_iterator Target = targets.begin(); Target != targets.end(); ++Target)
249 new pkgAcqIndex(Owner, TransactionManager, *Target);
250 }
251
252 return true;
253 }
254 /*}}}*/
255 // ReleaseIndex::IsTrusted /*{{{*/
256 bool debReleaseIndex::SetTrusted(TriState const Trusted)
257 {
258 if (d->Trusted == TRI_UNSET)
259 d->Trusted = Trusted;
260 else if (d->Trusted != Trusted)
261 // TRANSLATOR: The first is an option name from sources.list manpage, the other two URI and Suite
262 return _error->Error(_("Conflicting values set for option %s concerning source %s %s"), "Trusted", URI.c_str(), Dist.c_str());
263 return true;
264 }
265 bool debReleaseIndex::IsTrusted() const
266 {
267 if (d->Trusted == TRI_YES)
268 return true;
269 else if (d->Trusted == TRI_NO)
270 return false;
271
272
273 if(_config->FindB("APT::Authentication::TrustCDROM", false))
274 if(URI.substr(0,strlen("cdrom:")) == "cdrom:")
275 return true;
276
277 if (FileExists(MetaIndexFile("Release.gpg")))
278 return true;
279
280 return FileExists(MetaIndexFile("InRelease"));
281 }
282 /*}}}*/
283 std::vector <pkgIndexFile *> *debReleaseIndex::GetIndexFiles() /*{{{*/
284 {
285 if (Indexes != NULL)
286 return Indexes;
287
288 Indexes = new std::vector<pkgIndexFile*>();
289 std::vector<IndexTarget> const Targets = GetIndexTargets();
290 bool const istrusted = IsTrusted();
291 for (std::vector<IndexTarget>::const_iterator T = Targets.begin(); T != Targets.end(); ++T)
292 {
293 std::string const TargetName = T->Option(IndexTarget::CREATED_BY);
294 if (TargetName == "Packages")
295 Indexes->push_back(new debPackagesIndex(*T, istrusted));
296 else if (TargetName == "Sources")
297 Indexes->push_back(new debSourcesIndex(*T, istrusted));
298 else if (TargetName == "Translations")
299 Indexes->push_back(new debTranslationsIndex(*T));
300 }
301 return Indexes;
302 }
303 /*}}}*/
304
305 static bool ReleaseFileName(debReleaseIndex const * const That, std::string &ReleaseFile)/*{{{*/
306 {
307 ReleaseFile = That->MetaIndexFile("InRelease");
308 bool releaseExists = false;
309 if (FileExists(ReleaseFile) == true)
310 releaseExists = true;
311 else
312 {
313 ReleaseFile = That->MetaIndexFile("Release");
314 if (FileExists(ReleaseFile))
315 releaseExists = true;
316 }
317 return releaseExists;
318 }
319 /*}}}*/
320 bool debReleaseIndex::Merge(pkgCacheGenerator &Gen,OpProgress * /*Prog*/) const/*{{{*/
321 {
322 std::string ReleaseFile;
323 bool const releaseExists = ReleaseFileName(this, ReleaseFile);
324
325 ::URI Tmp(URI);
326 if (Gen.SelectReleaseFile(ReleaseFile, Tmp.Host) == false)
327 return _error->Error("Problem with SelectReleaseFile %s", ReleaseFile.c_str());
328
329 if (releaseExists == false)
330 return true;
331
332 FileFd Rel;
333 // Beware: The 'Release' file might be clearsigned in case the
334 // signature for an 'InRelease' file couldn't be checked
335 if (OpenMaybeClearSignedFile(ReleaseFile, Rel) == false)
336 return false;
337 if (_error->PendingError() == true)
338 return false;
339
340 // Store the IMS information
341 pkgCache::RlsFileIterator File = Gen.GetCurRlsFile();
342 pkgCacheGenerator::Dynamic<pkgCache::RlsFileIterator> DynFile(File);
343 // Rel can't be used as this is potentially a temporary file
344 struct stat Buf;
345 if (stat(ReleaseFile.c_str(), &Buf) != 0)
346 return _error->Errno("fstat", "Unable to stat file %s", ReleaseFile.c_str());
347 File->Size = Buf.st_size;
348 File->mtime = Buf.st_mtime;
349
350 pkgTagFile TagFile(&Rel, Rel.Size());
351 pkgTagSection Section;
352 if (_error->PendingError() == true || TagFile.Step(Section) == false)
353 return false;
354
355 std::string data;
356 #define APT_INRELEASE(TYPE, TAG, STORE) \
357 data = Section.FindS(TAG); \
358 if (data.empty() == false) \
359 { \
360 map_stringitem_t const storage = Gen.StoreString(pkgCacheGenerator::TYPE, data); \
361 STORE = storage; \
362 }
363 APT_INRELEASE(MIXED, "Suite", File->Archive)
364 APT_INRELEASE(VERSIONNUMBER, "Version", File->Version)
365 APT_INRELEASE(MIXED, "Origin", File->Origin)
366 APT_INRELEASE(MIXED, "Codename", File->Codename)
367 APT_INRELEASE(MIXED, "Label", File->Label)
368 #undef APT_INRELEASE
369 Section.FindFlag("NotAutomatic", File->Flags, pkgCache::Flag::NotAutomatic);
370 Section.FindFlag("ButAutomaticUpgrades", File->Flags, pkgCache::Flag::ButAutomaticUpgrades);
371
372 return !_error->PendingError();
373 }
374 /*}}}*/
375 // ReleaseIndex::FindInCache - Find this index /*{{{*/
376 pkgCache::RlsFileIterator debReleaseIndex::FindInCache(pkgCache &Cache, bool const ModifyCheck) const
377 {
378 std::string ReleaseFile;
379 bool const releaseExists = ReleaseFileName(this, ReleaseFile);
380
381 pkgCache::RlsFileIterator File = Cache.RlsFileBegin();
382 for (; File.end() == false; ++File)
383 {
384 if (File->FileName == 0 || ReleaseFile != File.FileName())
385 continue;
386
387 // empty means the file does not exist by "design"
388 if (ModifyCheck == false || (releaseExists == false && File->Size == 0))
389 return File;
390
391 struct stat St;
392 if (stat(File.FileName(),&St) != 0)
393 {
394 if (_config->FindB("Debug::pkgCacheGen", false))
395 std::clog << "ReleaseIndex::FindInCache - stat failed on " << File.FileName() << std::endl;
396 return pkgCache::RlsFileIterator(Cache);
397 }
398 if ((unsigned)St.st_size != File->Size || St.st_mtime != File->mtime)
399 {
400 if (_config->FindB("Debug::pkgCacheGen", false))
401 std::clog << "ReleaseIndex::FindInCache - size (" << St.st_size << " <> " << File->Size
402 << ") or mtime (" << St.st_mtime << " <> " << File->mtime
403 << ") doesn't match for " << File.FileName() << std::endl;
404 return pkgCache::RlsFileIterator(Cache);
405 }
406 return File;
407 }
408
409 return File;
410 }
411 /*}}}*/
412
413 static std::vector<std::string> parsePlusMinusOptions(std::string const &Name, /*{{{*/
414 std::map<std::string, std::string> const &Options, std::vector<std::string> const &defaultValues)
415 {
416 std::map<std::string, std::string>::const_iterator val = Options.find(Name);
417 std::vector<std::string> Values;
418 if (val != Options.end())
419 Values = VectorizeString(val->second, ',');
420 else
421 Values = defaultValues;
422
423 if ((val = Options.find(Name + "+")) != Options.end())
424 {
425 std::vector<std::string> const plusArch = VectorizeString(val->second, ',');
426 for (std::vector<std::string>::const_iterator plus = plusArch.begin(); plus != plusArch.end(); ++plus)
427 if (std::find(Values.begin(), Values.end(), *plus) == Values.end())
428 Values.push_back(*plus);
429 }
430 if ((val = Options.find(Name + "-")) != Options.end())
431 {
432 std::vector<std::string> const minusArch = VectorizeString(val->second, ',');
433 for (std::vector<std::string>::const_iterator minus = minusArch.begin(); minus != minusArch.end(); ++minus)
434 {
435 std::vector<std::string>::iterator kill = std::find(Values.begin(), Values.end(), *minus);
436 if (kill != Values.end())
437 Values.erase(kill);
438 }
439 }
440 return Values;
441 }
442 /*}}}*/
443 class APT_HIDDEN debSLTypeDebian : public pkgSourceList::Type /*{{{*/
444 {
445 protected:
446
447 bool CreateItemInternal(std::vector<metaIndex *> &List, std::string const &URI,
448 std::string const &Dist, std::string const &Section,
449 bool const &IsSrc, std::map<std::string, std::string> const &Options) const
450 {
451 debReleaseIndex *Deb = NULL;
452 for (std::vector<metaIndex *>::const_iterator I = List.begin();
453 I != List.end(); ++I)
454 {
455 // We only worry about debian entries here
456 if (strcmp((*I)->GetType(), "deb") != 0)
457 continue;
458
459 /* This check insures that there will be only one Release file
460 queued for all the Packages files and Sources files it
461 corresponds to. */
462 if ((*I)->GetURI() == URI && (*I)->GetDist() == Dist)
463 {
464 Deb = dynamic_cast<debReleaseIndex*>(*I);
465 if (Deb != NULL)
466 break;
467 }
468 }
469
470 // No currently created Release file indexes this entry, so we create a new one.
471 if (Deb == NULL)
472 {
473 Deb = new debReleaseIndex(URI, Dist);
474 List.push_back(Deb);
475 }
476
477 Deb->AddComponent(
478 IsSrc,
479 Section,
480 parsePlusMinusOptions("target", Options, _config->FindVector(std::string("APT::Acquire::Targets::") + Name, "", true)),
481 parsePlusMinusOptions("arch", Options, APT::Configuration::getArchitectures()),
482 parsePlusMinusOptions("lang", Options, APT::Configuration::getLanguages(true))
483 );
484
485 std::map<std::string, std::string>::const_iterator const trusted = Options.find("trusted");
486 if (trusted != Options.end())
487 {
488 if (Deb->SetTrusted(StringToBool(trusted->second, false) ? debReleaseIndex::TRI_YES : debReleaseIndex::TRI_NO) == false)
489 return false;
490 }
491 else if (Deb->SetTrusted(debReleaseIndex::TRI_DONTCARE) == false)
492 return false;
493
494 return true;
495 }
496
497 debSLTypeDebian(char const * const Name, char const * const Label) : Type(Name, Label)
498 {
499 }
500 };
501 /*}}}*/
502 class APT_HIDDEN debSLTypeDeb : public debSLTypeDebian /*{{{*/
503 {
504 public:
505
506 bool CreateItem(std::vector<metaIndex *> &List, std::string const &URI,
507 std::string const &Dist, std::string const &Section,
508 std::map<std::string, std::string> const &Options) const
509 {
510 return CreateItemInternal(List, URI, Dist, Section, false, Options);
511 }
512
513 debSLTypeDeb() : debSLTypeDebian("deb", "Debian binary tree")
514 {
515 }
516 };
517 /*}}}*/
518 class APT_HIDDEN debSLTypeDebSrc : public debSLTypeDebian /*{{{*/
519 {
520 public:
521
522 bool CreateItem(std::vector<metaIndex *> &List, std::string const &URI,
523 std::string const &Dist, std::string const &Section,
524 std::map<std::string, std::string> const &Options) const
525 {
526 return CreateItemInternal(List, URI, Dist, Section, true, Options);
527 }
528
529 debSLTypeDebSrc() : debSLTypeDebian("deb-src", "Debian source tree")
530 {
531 }
532 };
533 /*}}}*/
534
535 debDebFileMetaIndex::debDebFileMetaIndex(std::string const &DebFile) /*{{{*/
536 : metaIndex(DebFile, "local-uri", "deb-dist"), d(NULL), DebFile(DebFile)
537 {
538 DebIndex = new debDebPkgFileIndex(DebFile);
539 Indexes = new std::vector<pkgIndexFile *>();
540 Indexes->push_back(DebIndex);
541 }
542 debDebFileMetaIndex::~debDebFileMetaIndex() {}
543 /*}}}*/
544 class APT_HIDDEN debSLTypeDebFile : public pkgSourceList::Type /*{{{*/
545 {
546 public:
547
548 bool CreateItem(std::vector<metaIndex *> &List, std::string const &URI,
549 std::string const &/*Dist*/, std::string const &/*Section*/,
550 std::map<std::string, std::string> const &/*Options*/) const
551 {
552 metaIndex *mi = new debDebFileMetaIndex(URI);
553 List.push_back(mi);
554 return true;
555 }
556
557 debSLTypeDebFile() : Type("deb-file", "Debian local deb file")
558 {
559 }
560 };
561 /*}}}*/
562
563 APT_HIDDEN debSLTypeDeb _apt_DebType;
564 APT_HIDDEN debSLTypeDebSrc _apt_DebSrcType;
565 APT_HIDDEN debSLTypeDebFile _apt_DebFileType;