You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

643 lines
22 KiB

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