sourcelist.cc 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651
  1. // -*- mode: cpp; mode: fold -*-
  2. // Description /*{{{*/
  3. // $Id: sourcelist.cc,v 1.3 2002/08/15 20:51:37 niemeyer Exp $
  4. /* ######################################################################
  5. List of Sources
  6. ##################################################################### */
  7. /*}}}*/
  8. // Include Files /*{{{*/
  9. #include<config.h>
  10. #include <apt-pkg/sourcelist.h>
  11. #include <apt-pkg/cmndline.h>
  12. #include <apt-pkg/error.h>
  13. #include <apt-pkg/fileutl.h>
  14. #include <apt-pkg/strutl.h>
  15. #include <apt-pkg/configuration.h>
  16. #include <apt-pkg/metaindex.h>
  17. #include <apt-pkg/indexfile.h>
  18. #include <apt-pkg/tagfile.h>
  19. #include <apt-pkg/pkgcache.h>
  20. #include <apt-pkg/cacheiterators.h>
  21. #include <apt-pkg/debindexfile.h>
  22. #include <apt-pkg/debsrcrecords.h>
  23. #include <ctype.h>
  24. #include <stddef.h>
  25. #include <time.h>
  26. #include <cstring>
  27. #include <map>
  28. #include <string>
  29. #include <vector>
  30. #include <fstream>
  31. #include <algorithm>
  32. #include <apti18n.h>
  33. /*}}}*/
  34. using namespace std;
  35. // Global list of Items supported
  36. static pkgSourceList::Type *ItmList[10];
  37. pkgSourceList::Type **pkgSourceList::Type::GlobalList = ItmList;
  38. unsigned long pkgSourceList::Type::GlobalListLen = 0;
  39. // Type::Type - Constructor /*{{{*/
  40. // ---------------------------------------------------------------------
  41. /* Link this to the global list of items*/
  42. pkgSourceList::Type::Type(char const * const pName, char const * const pLabel) : Name(pName), Label(pLabel)
  43. {
  44. ItmList[GlobalListLen] = this;
  45. ++GlobalListLen;
  46. }
  47. pkgSourceList::Type::~Type() {}
  48. /*}}}*/
  49. // Type::GetType - Get a specific meta for a given type /*{{{*/
  50. // ---------------------------------------------------------------------
  51. /* */
  52. pkgSourceList::Type *pkgSourceList::Type::GetType(const char *Type)
  53. {
  54. for (unsigned I = 0; I != GlobalListLen; ++I)
  55. if (strcmp(GlobalList[I]->Name,Type) == 0)
  56. return GlobalList[I];
  57. return 0;
  58. }
  59. /*}}}*/
  60. // Type::FixupURI - Normalize the URI and check it.. /*{{{*/
  61. // ---------------------------------------------------------------------
  62. /* */
  63. bool pkgSourceList::Type::FixupURI(string &URI) const
  64. {
  65. if (URI.empty() == true)
  66. return false;
  67. if (URI.find(':') == string::npos)
  68. return false;
  69. URI = SubstVar(URI,"$(ARCH)",_config->Find("APT::Architecture"));
  70. // Make sure that the URI is / postfixed
  71. if (URI[URI.size() - 1] != '/')
  72. URI += '/';
  73. return true;
  74. }
  75. /*}}}*/
  76. bool pkgSourceList::Type::ParseStanza(vector<metaIndex *> &List, /*{{{*/
  77. pkgTagSection &Tags,
  78. unsigned int const i,
  79. FileFd &Fd)
  80. {
  81. map<string, string> Options;
  82. string Enabled = Tags.FindS("Enabled");
  83. if (Enabled.empty() == false && StringToBool(Enabled) == false)
  84. return true;
  85. std::map<char const * const, std::pair<char const * const, bool> > mapping;
  86. #define APT_PLUSMINUS(X, Y) \
  87. mapping.insert(std::make_pair(X, std::make_pair(Y, true))); \
  88. mapping.insert(std::make_pair(X "-Add", std::make_pair(Y "+", true))); \
  89. mapping.insert(std::make_pair(X "-Remove", std::make_pair(Y "-", true)))
  90. APT_PLUSMINUS("Architectures", "arch");
  91. APT_PLUSMINUS("Languages", "lang");
  92. APT_PLUSMINUS("Targets", "target");
  93. #undef APT_PLUSMINUS
  94. mapping.insert(std::make_pair("Trusted", std::make_pair("trusted", false)));
  95. mapping.insert(std::make_pair("Check-Valid-Until", std::make_pair("check-valid-until", false)));
  96. mapping.insert(std::make_pair("Valid-Until-Min", std::make_pair("valid-until-min", false)));
  97. mapping.insert(std::make_pair("Valid-Until-Max", std::make_pair("valid-until-max", false)));
  98. mapping.insert(std::make_pair("Signed-By", std::make_pair("signed-by", false)));
  99. mapping.insert(std::make_pair("PDiffs", std::make_pair("pdiffs", false)));
  100. mapping.insert(std::make_pair("By-Hash", std::make_pair("by-hash", false)));
  101. for (std::map<char const * const, std::pair<char const * const, bool> >::const_iterator m = mapping.begin(); m != mapping.end(); ++m)
  102. if (Tags.Exists(m->first))
  103. {
  104. std::string option = Tags.FindS(m->first);
  105. // for deb822 the " " is the delimiter, but the backend expects ","
  106. if (m->second.second == true)
  107. std::replace(option.begin(), option.end(), ' ', ',');
  108. Options[m->second.first] = option;
  109. }
  110. {
  111. std::string entry;
  112. strprintf(entry, "%s:%i", Fd.Name().c_str(), i);
  113. Options["sourceslist-entry"] = entry;
  114. }
  115. // now create one item per suite/section
  116. string Suite = Tags.FindS("Suites");
  117. Suite = SubstVar(Suite,"$(ARCH)",_config->Find("APT::Architecture"));
  118. string const Component = Tags.FindS("Components");
  119. string const URIS = Tags.FindS("URIs");
  120. std::vector<std::string> const list_uris = VectorizeString(URIS, ' ');
  121. std::vector<std::string> const list_suite = VectorizeString(Suite, ' ');
  122. std::vector<std::string> const list_comp = VectorizeString(Component, ' ');
  123. if (list_uris.empty())
  124. // TRANSLATOR: %u is a line number, the first %s is a filename of a file with the extension "second %s" and the third %s is a unique identifier for bugreports
  125. return _error->Error(_("Malformed entry %u in %s file %s (%s)"), i, "sources", Fd.Name().c_str(), "URI");
  126. for (std::vector<std::string>::const_iterator U = list_uris.begin();
  127. U != list_uris.end(); ++U)
  128. {
  129. std::string URI = *U;
  130. if (U->empty() || FixupURI(URI) == false)
  131. return _error->Error(_("Malformed entry %u in %s file %s (%s)"), i, "sources", Fd.Name().c_str(), "URI parse");
  132. if (list_suite.empty())
  133. return _error->Error(_("Malformed entry %u in %s file %s (%s)"), i, "sources", Fd.Name().c_str(), "Suite");
  134. for (std::vector<std::string>::const_iterator S = list_suite.begin();
  135. S != list_suite.end(); ++S)
  136. {
  137. if (S->empty() == false && (*S)[S->size() - 1] == '/')
  138. {
  139. if (list_comp.empty() == false)
  140. return _error->Error(_("Malformed entry %u in %s file %s (%s)"), i, "sources", Fd.Name().c_str(), "absolute Suite Component");
  141. if (CreateItem(List, URI, *S, "", Options) == false)
  142. return false;
  143. }
  144. else
  145. {
  146. if (list_comp.empty())
  147. return _error->Error(_("Malformed entry %u in %s file %s (%s)"), i, "sources", Fd.Name().c_str(), "Component");
  148. for (std::vector<std::string>::const_iterator C = list_comp.begin();
  149. C != list_comp.end(); ++C)
  150. {
  151. if (CreateItem(List, URI, *S, *C, Options) == false)
  152. {
  153. return false;
  154. }
  155. }
  156. }
  157. }
  158. }
  159. return true;
  160. }
  161. /*}}}*/
  162. // Type::ParseLine - Parse a single line /*{{{*/
  163. // ---------------------------------------------------------------------
  164. /* This is a generic one that is the 'usual' format for sources.list
  165. Weird types may override this. */
  166. bool pkgSourceList::Type::ParseLine(vector<metaIndex *> &List,
  167. const char *Buffer,
  168. unsigned int const CurLine,
  169. string const &File) const
  170. {
  171. for (;Buffer != 0 && isspace(*Buffer); ++Buffer); // Skip whitespaces
  172. // Parse option field if it exists
  173. // e.g.: [ option1=value1 option2=value2 ]
  174. map<string, string> Options;
  175. {
  176. std::string entry;
  177. strprintf(entry, "%s:%i", File.c_str(), CurLine);
  178. Options["sourceslist-entry"] = entry;
  179. }
  180. if (Buffer != 0 && Buffer[0] == '[')
  181. {
  182. ++Buffer; // ignore the [
  183. for (;Buffer != 0 && isspace(*Buffer); ++Buffer); // Skip whitespaces
  184. while (*Buffer != ']')
  185. {
  186. // get one option, e.g. option1=value1
  187. string option;
  188. if (ParseQuoteWord(Buffer,option) == false)
  189. return _error->Error(_("Malformed entry %u in %s file %s (%s)"), CurLine, "list", File.c_str(), "[option] unparseable");
  190. if (option.length() < 3)
  191. return _error->Error(_("Malformed entry %u in %s file %s (%s)"), CurLine, "list", File.c_str(), "[option] too short");
  192. // accept options even if the last has no space before the ]-end marker
  193. if (option.at(option.length()-1) == ']')
  194. {
  195. for (; *Buffer != ']'; --Buffer);
  196. option.resize(option.length()-1);
  197. }
  198. size_t const needle = option.find('=');
  199. if (needle == string::npos)
  200. return _error->Error(_("Malformed entry %u in %s file %s (%s)"), CurLine, "list", File.c_str(), "[option] not assignment");
  201. string const key = string(option, 0, needle);
  202. string const value = string(option, needle + 1, option.length());
  203. if (key.empty() == true)
  204. return _error->Error(_("Malformed entry %u in %s file %s (%s)"), CurLine, "list", File.c_str(), "[option] no key");
  205. if (value.empty() == true)
  206. return _error->Error(_("Malformed entry %u in %s file %s (%s)"), CurLine, "list", File.c_str(), "[option] no value");
  207. Options[key] = value;
  208. }
  209. ++Buffer; // ignore the ]
  210. for (;Buffer != 0 && isspace(*Buffer); ++Buffer); // Skip whitespaces
  211. }
  212. string URI;
  213. string Dist;
  214. string Section;
  215. if (ParseQuoteWord(Buffer,URI) == false)
  216. return _error->Error(_("Malformed entry %u in %s file %s (%s)"), CurLine, "list", File.c_str(), "URI");
  217. if (ParseQuoteWord(Buffer,Dist) == false)
  218. return _error->Error(_("Malformed entry %u in %s file %s (%s)"), CurLine, "list", File.c_str(), "Suite");
  219. if (FixupURI(URI) == false)
  220. return _error->Error(_("Malformed entry %u in %s file %s (%s)"), CurLine, "list", File.c_str(), "URI parse");
  221. // Check for an absolute dists specification.
  222. if (Dist.empty() == false && Dist[Dist.size() - 1] == '/')
  223. {
  224. if (ParseQuoteWord(Buffer,Section) == true)
  225. return _error->Error(_("Malformed entry %u in %s file %s (%s)"), CurLine, "list", File.c_str(), "absolute Suite Component");
  226. Dist = SubstVar(Dist,"$(ARCH)",_config->Find("APT::Architecture"));
  227. return CreateItem(List, URI, Dist, Section, Options);
  228. }
  229. // Grab the rest of the dists
  230. if (ParseQuoteWord(Buffer,Section) == false)
  231. return _error->Error(_("Malformed entry %u in %s file %s (%s)"), CurLine, "list", File.c_str(), "Component");
  232. do
  233. {
  234. if (CreateItem(List, URI, Dist, Section, Options) == false)
  235. return false;
  236. }
  237. while (ParseQuoteWord(Buffer,Section) == true);
  238. return true;
  239. }
  240. /*}}}*/
  241. // SourceList::pkgSourceList - Constructors /*{{{*/
  242. // ---------------------------------------------------------------------
  243. /* */
  244. pkgSourceList::pkgSourceList() : d(NULL)
  245. {
  246. }
  247. /*}}}*/
  248. // SourceList::~pkgSourceList - Destructor /*{{{*/
  249. // ---------------------------------------------------------------------
  250. /* */
  251. pkgSourceList::~pkgSourceList()
  252. {
  253. for (const_iterator I = SrcList.begin(); I != SrcList.end(); ++I)
  254. delete *I;
  255. SrcList.clear();
  256. for (auto F = VolatileFiles.begin(); F != VolatileFiles.end(); ++F)
  257. delete (*F);
  258. VolatileFiles.clear();
  259. }
  260. /*}}}*/
  261. // SourceList::ReadMainList - Read the main source list from etc /*{{{*/
  262. // ---------------------------------------------------------------------
  263. /* */
  264. bool pkgSourceList::ReadMainList()
  265. {
  266. // CNC:2003-03-03 - Multiple sources list support.
  267. bool Res = true;
  268. #if 0
  269. Res = ReadVendors();
  270. if (Res == false)
  271. return false;
  272. #endif
  273. Reset();
  274. // CNC:2003-11-28 - Entries in sources.list have priority over
  275. // entries in sources.list.d.
  276. string Main = _config->FindFile("Dir::Etc::sourcelist", "/dev/null");
  277. string Parts = _config->FindDir("Dir::Etc::sourceparts", "/dev/null");
  278. if (RealFileExists(Main) == true)
  279. Res &= ReadAppend(Main);
  280. else if (DirectoryExists(Parts) == false && APT::String::Endswith(Parts, "/dev/null") == false)
  281. // Only warn if there are no sources.list.d.
  282. _error->WarningE("DirectoryExists", _("Unable to read %s"), Parts.c_str());
  283. if (DirectoryExists(Parts) == true)
  284. Res &= ReadSourceDir(Parts);
  285. else if (Main.empty() == false && RealFileExists(Main) == false &&
  286. APT::String::Endswith(Parts, "/dev/null") == false)
  287. // Only warn if there is no sources.list file.
  288. _error->WarningE("RealFileExists", _("Unable to read %s"), Main.c_str());
  289. for (auto && file: _config->FindVector("APT::Sources::With"))
  290. Res &= AddVolatileFile(file, nullptr);
  291. return Res;
  292. }
  293. /*}}}*/
  294. // SourceList::Reset - Clear the sourcelist contents /*{{{*/
  295. // ---------------------------------------------------------------------
  296. /* */
  297. void pkgSourceList::Reset()
  298. {
  299. for (const_iterator I = SrcList.begin(); I != SrcList.end(); ++I)
  300. delete *I;
  301. SrcList.clear();
  302. }
  303. /*}}}*/
  304. // SourceList::Read - Parse the sourcelist file /*{{{*/
  305. // ---------------------------------------------------------------------
  306. /* */
  307. bool pkgSourceList::Read(string const &File)
  308. {
  309. Reset();
  310. return ReadAppend(File);
  311. }
  312. /*}}}*/
  313. // SourceList::ReadAppend - Parse a sourcelist file /*{{{*/
  314. // ---------------------------------------------------------------------
  315. /* */
  316. bool pkgSourceList::ReadAppend(string const &File)
  317. {
  318. if (flExtension(File) == "sources")
  319. return ParseFileDeb822(File);
  320. else
  321. return ParseFileOldStyle(File);
  322. }
  323. /*}}}*/
  324. // SourceList::ReadFileOldStyle - Read Traditional style sources.list /*{{{*/
  325. // ---------------------------------------------------------------------
  326. /* */
  327. bool pkgSourceList::ParseFileOldStyle(std::string const &File)
  328. {
  329. // Open the stream for reading
  330. ifstream F(File.c_str(),ios::in /*| ios::nocreate*/);
  331. if (F.fail() == true)
  332. return _error->Errno("ifstream::ifstream",_("Opening %s"),File.c_str());
  333. std::string Buffer;
  334. for (unsigned int CurLine = 1; std::getline(F, Buffer); ++CurLine)
  335. {
  336. // remove comments
  337. size_t curpos = 0;
  338. while ((curpos = Buffer.find('#', curpos)) != std::string::npos)
  339. {
  340. size_t const openbrackets = std::count(Buffer.begin(), Buffer.begin() + curpos, '[');
  341. size_t const closedbrackets = std::count(Buffer.begin(), Buffer.begin() + curpos, ']');
  342. if (openbrackets > closedbrackets)
  343. {
  344. // a # in an option, unlikely, but oh well, it was supported so stick to it
  345. ++curpos;
  346. continue;
  347. }
  348. Buffer.erase(curpos);
  349. break;
  350. }
  351. // remove spaces before/after
  352. curpos = Buffer.find_first_not_of(" \t\r");
  353. if (curpos != 0)
  354. Buffer.erase(0, curpos);
  355. curpos = Buffer.find_last_not_of(" \t\r");
  356. if (curpos != std::string::npos)
  357. Buffer.erase(curpos + 1);
  358. if (Buffer.empty())
  359. continue;
  360. // Grok it
  361. std::string const LineType = Buffer.substr(0, Buffer.find_first_of(" \t\v"));
  362. if (LineType.empty() || LineType == Buffer)
  363. return _error->Error(_("Malformed line %u in source list %s (type)"),CurLine,File.c_str());
  364. Type *Parse = Type::GetType(LineType.c_str());
  365. if (Parse == 0)
  366. return _error->Error(_("Type '%s' is not known on line %u in source list %s"),LineType.c_str(),CurLine,File.c_str());
  367. if (Parse->ParseLine(SrcList, Buffer.c_str() + LineType.length(), CurLine, File) == false)
  368. return false;
  369. }
  370. return true;
  371. }
  372. /*}}}*/
  373. // SourceList::ParseFileDeb822 - Parse deb822 style sources.list /*{{{*/
  374. // ---------------------------------------------------------------------
  375. /* Returns: the number of stanzas parsed*/
  376. bool pkgSourceList::ParseFileDeb822(string const &File)
  377. {
  378. // see if we can read the file
  379. FileFd Fd(File, FileFd::ReadOnly);
  380. pkgTagFile Sources(&Fd, pkgTagFile::SUPPORT_COMMENTS);
  381. if (Fd.IsOpen() == false || Fd.Failed())
  382. return _error->Error(_("Malformed stanza %u in source list %s (type)"),0,File.c_str());
  383. // read step by step
  384. pkgTagSection Tags;
  385. unsigned int i = 0;
  386. while (Sources.Step(Tags) == true)
  387. {
  388. ++i;
  389. if(Tags.Exists("Types") == false)
  390. return _error->Error(_("Malformed stanza %u in source list %s (type)"),i,File.c_str());
  391. string const types = Tags.FindS("Types");
  392. std::vector<std::string> const list_types = VectorizeString(types, ' ');
  393. for (std::vector<std::string>::const_iterator I = list_types.begin();
  394. I != list_types.end(); ++I)
  395. {
  396. Type *Parse = Type::GetType((*I).c_str());
  397. if (Parse == 0)
  398. {
  399. _error->Error(_("Type '%s' is not known on stanza %u in source list %s"), (*I).c_str(),i,Fd.Name().c_str());
  400. return false;
  401. }
  402. if (!Parse->ParseStanza(SrcList, Tags, i, Fd))
  403. return false;
  404. }
  405. }
  406. return true;
  407. }
  408. /*}}}*/
  409. // SourceList::FindIndex - Get the index associated with a file /*{{{*/
  410. static bool FindInIndexFileContainer(std::vector<pkgIndexFile *> const &Cont, pkgCache::PkgFileIterator const &File, pkgIndexFile *&Found)
  411. {
  412. auto const J = std::find_if(Cont.begin(), Cont.end(), [&File](pkgIndexFile const * const J) {
  413. return J->FindInCache(*File.Cache()) == File;
  414. });
  415. if (J != Cont.end())
  416. {
  417. Found = (*J);
  418. return true;
  419. }
  420. return false;
  421. }
  422. bool pkgSourceList::FindIndex(pkgCache::PkgFileIterator File,
  423. pkgIndexFile *&Found) const
  424. {
  425. for (const_iterator I = SrcList.begin(); I != SrcList.end(); ++I)
  426. if (FindInIndexFileContainer(*(*I)->GetIndexFiles(), File, Found))
  427. return true;
  428. return FindInIndexFileContainer(VolatileFiles, File, Found);
  429. }
  430. /*}}}*/
  431. // SourceList::GetIndexes - Load the index files into the downloader /*{{{*/
  432. // ---------------------------------------------------------------------
  433. /* */
  434. bool pkgSourceList::GetIndexes(pkgAcquire *Owner, bool GetAll) const
  435. {
  436. for (const_iterator I = SrcList.begin(); I != SrcList.end(); ++I)
  437. if ((*I)->GetIndexes(Owner,GetAll) == false)
  438. return false;
  439. return true;
  440. }
  441. /*}}}*/
  442. // CNC:2003-03-03 - By Anton V. Denisov <avd@altlinux.org>.
  443. // SourceList::ReadSourceDir - Read a directory with sources files
  444. // Based on ReadConfigDir() /*{{{*/
  445. // ---------------------------------------------------------------------
  446. /* */
  447. bool pkgSourceList::ReadSourceDir(string const &Dir)
  448. {
  449. std::vector<std::string> ext;
  450. ext.push_back("list");
  451. ext.push_back("sources");
  452. std::vector<std::string> const List = GetListOfFilesInDir(Dir, ext, true);
  453. // Read the files
  454. for (vector<string>::const_iterator I = List.begin(); I != List.end(); ++I)
  455. if (ReadAppend(*I) == false)
  456. return false;
  457. return true;
  458. }
  459. /*}}}*/
  460. // GetLastModified() /*{{{*/
  461. // ---------------------------------------------------------------------
  462. /* */
  463. time_t pkgSourceList::GetLastModifiedTime()
  464. {
  465. vector<string> List;
  466. string Main = _config->FindFile("Dir::Etc::sourcelist");
  467. string Parts = _config->FindDir("Dir::Etc::sourceparts");
  468. // go over the parts
  469. if (DirectoryExists(Parts) == true)
  470. List = GetListOfFilesInDir(Parts, "list", true);
  471. // calculate the time
  472. std::vector<time_t> modtimes;
  473. modtimes.reserve(1 + List.size());
  474. modtimes.push_back(GetModificationTime(Main));
  475. std::transform(List.begin(), List.end(), std::back_inserter(modtimes), GetModificationTime);
  476. auto const maxmtime = std::max_element(modtimes.begin(), modtimes.end());
  477. return *maxmtime;
  478. }
  479. /*}}}*/
  480. std::vector<pkgIndexFile*> pkgSourceList::GetVolatileFiles() const /*{{{*/
  481. {
  482. return VolatileFiles;
  483. }
  484. /*}}}*/
  485. void pkgSourceList::AddVolatileFile(pkgIndexFile * const File) /*{{{*/
  486. {
  487. if (File != nullptr)
  488. VolatileFiles.push_back(File);
  489. }
  490. /*}}}*/
  491. static bool fileNameMatches(std::string const &filename, std::string const &idxtype)/*{{{*/
  492. {
  493. for (auto && type: APT::Configuration::getCompressionTypes())
  494. {
  495. if (type == "uncompressed")
  496. {
  497. if (filename == idxtype || APT::String::Endswith(filename, '_' + idxtype))
  498. return true;
  499. }
  500. else if (filename == idxtype + '.' + type ||
  501. APT::String::Endswith(filename, '_' + idxtype + '.' + type))
  502. return true;
  503. }
  504. return false;
  505. }
  506. /*}}}*/
  507. bool pkgSourceList::AddVolatileFile(std::string const &File, std::vector<std::string> * const VolatileCmdL)/*{{{*/
  508. {
  509. // Note: FileExists matches directories and links, too!
  510. if (File.empty() || FileExists(File) == false)
  511. return false;
  512. std::string const ext = flExtension(File);
  513. // udeb is not included as installing it is usually a mistake rather than intended
  514. if (ext == "deb" || ext == "ddeb")
  515. AddVolatileFile(new debDebPkgFileIndex(File));
  516. else if (ext == "dsc")
  517. AddVolatileFile(new debDscFileIndex(File));
  518. else if (FileExists(flCombine(File, "debian/control")))
  519. AddVolatileFile(new debDscFileIndex(flCombine(File, "debian/control")));
  520. else if (ext == "changes")
  521. {
  522. debDscRecordParser changes(File, nullptr);
  523. std::vector<pkgSrcRecords::File2> fileslst;
  524. if (changes.Files2(fileslst) == false || fileslst.empty())
  525. return false;
  526. auto const basedir = flNotFile(File);
  527. for (auto && file: fileslst)
  528. {
  529. auto const name = flCombine(basedir, file.Path);
  530. AddVolatileFile(name, VolatileCmdL);
  531. if (file.Hashes.VerifyFile(name) == false)
  532. return _error->Error("The file %s does not match with the hashes in the %s file!", name.c_str(), File.c_str());
  533. }
  534. return true;
  535. }
  536. else
  537. {
  538. auto const filename = flNotDir(File);
  539. auto const Target = IndexTarget(File, filename, File, "file:" + File, false, true, {
  540. { "FILENAME", File },
  541. { "REPO_URI", "file:" + flAbsPath(flNotFile(File)) + '/' },
  542. { "COMPONENT", "volatile-packages-file" },
  543. });
  544. if (fileNameMatches(filename, "Packages"))
  545. AddVolatileFile(new debPackagesIndex(Target, true));
  546. else if (fileNameMatches(filename, "Sources"))
  547. AddVolatileFile(new debSourcesIndex(Target, true));
  548. else
  549. return false;
  550. }
  551. if (VolatileCmdL != nullptr)
  552. VolatileCmdL->push_back(File);
  553. return true;
  554. }
  555. bool pkgSourceList::AddVolatileFile(std::string const &File)
  556. {
  557. return AddVolatileFile(File, nullptr);
  558. }
  559. /*}}}*/
  560. void pkgSourceList::AddVolatileFiles(CommandLine &CmdL, std::vector<std::string> * const VolatileCmdL)/*{{{*/
  561. {
  562. std::remove_if(CmdL.FileList + 1, CmdL.FileList + 1 + CmdL.FileSize(), [&](char const * const I) {
  563. if (I != nullptr && (I[0] == '/' || (I[0] == '.' && (I[1] == '\0' || (I[1] == '.' && (I[2] == '\0' || I[2] == '/')) || I[1] == '/'))))
  564. {
  565. if (AddVolatileFile(I, VolatileCmdL))
  566. ;
  567. else
  568. _error->Error(_("Unsupported file %s given on commandline"), I);
  569. return true;
  570. }
  571. return false;
  572. });
  573. }
  574. void pkgSourceList::AddVolatileFiles(CommandLine &CmdL, std::vector<const char*> * const VolatileCmdL)
  575. {
  576. std::remove_if(CmdL.FileList + 1, CmdL.FileList + 1 + CmdL.FileSize(), [&](char const * const I) {
  577. if (I != nullptr && (I[0] == '/' || (I[0] == '.' && (I[1] == '\0' || (I[1] == '.' && (I[2] == '\0' || I[2] == '/')) || I[1] == '/'))))
  578. {
  579. if (AddVolatileFile(I))
  580. {
  581. if (VolatileCmdL != nullptr)
  582. VolatileCmdL->push_back(I);
  583. }
  584. else
  585. _error->Error(_("Unsupported file %s given on commandline"), I);
  586. return true;
  587. }
  588. return false;
  589. });
  590. }
  591. /*}}}*/