debmetaindex.cc 37 KB

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