sourcelist.cc 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620
  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. return Res;
  290. }
  291. /*}}}*/
  292. // SourceList::Reset - Clear the sourcelist contents /*{{{*/
  293. // ---------------------------------------------------------------------
  294. /* */
  295. void pkgSourceList::Reset()
  296. {
  297. for (const_iterator I = SrcList.begin(); I != SrcList.end(); ++I)
  298. delete *I;
  299. SrcList.clear();
  300. }
  301. /*}}}*/
  302. // SourceList::Read - Parse the sourcelist file /*{{{*/
  303. // ---------------------------------------------------------------------
  304. /* */
  305. bool pkgSourceList::Read(string const &File)
  306. {
  307. Reset();
  308. return ReadAppend(File);
  309. }
  310. /*}}}*/
  311. // SourceList::ReadAppend - Parse a sourcelist file /*{{{*/
  312. // ---------------------------------------------------------------------
  313. /* */
  314. bool pkgSourceList::ReadAppend(string const &File)
  315. {
  316. if (flExtension(File) == "sources")
  317. return ParseFileDeb822(File);
  318. else
  319. return ParseFileOldStyle(File);
  320. }
  321. /*}}}*/
  322. // SourceList::ReadFileOldStyle - Read Traditional style sources.list /*{{{*/
  323. // ---------------------------------------------------------------------
  324. /* */
  325. bool pkgSourceList::ParseFileOldStyle(std::string const &File)
  326. {
  327. // Open the stream for reading
  328. ifstream F(File.c_str(),ios::in /*| ios::nocreate*/);
  329. if (F.fail() == true)
  330. return _error->Errno("ifstream::ifstream",_("Opening %s"),File.c_str());
  331. std::string Buffer;
  332. for (unsigned int CurLine = 1; std::getline(F, Buffer); ++CurLine)
  333. {
  334. // remove comments
  335. size_t curpos = 0;
  336. while ((curpos = Buffer.find('#', curpos)) != std::string::npos)
  337. {
  338. size_t const openbrackets = std::count(Buffer.begin(), Buffer.begin() + curpos, '[');
  339. size_t const closedbrackets = std::count(Buffer.begin(), Buffer.begin() + curpos, ']');
  340. if (openbrackets > closedbrackets)
  341. {
  342. // a # in an option, unlikely, but oh well, it was supported so stick to it
  343. ++curpos;
  344. continue;
  345. }
  346. Buffer.erase(curpos);
  347. break;
  348. }
  349. // remove spaces before/after
  350. curpos = Buffer.find_first_not_of(" \t\r");
  351. if (curpos != 0)
  352. Buffer.erase(0, curpos);
  353. curpos = Buffer.find_last_not_of(" \t\r");
  354. if (curpos != std::string::npos)
  355. Buffer.erase(curpos + 1);
  356. if (Buffer.empty())
  357. continue;
  358. // Grok it
  359. std::string const LineType = Buffer.substr(0, Buffer.find_first_of(" \t\v"));
  360. if (LineType.empty() || LineType == Buffer)
  361. return _error->Error(_("Malformed line %u in source list %s (type)"),CurLine,File.c_str());
  362. Type *Parse = Type::GetType(LineType.c_str());
  363. if (Parse == 0)
  364. return _error->Error(_("Type '%s' is not known on line %u in source list %s"),LineType.c_str(),CurLine,File.c_str());
  365. if (Parse->ParseLine(SrcList, Buffer.c_str() + LineType.length(), CurLine, File) == false)
  366. return false;
  367. }
  368. return true;
  369. }
  370. /*}}}*/
  371. // SourceList::ParseFileDeb822 - Parse deb822 style sources.list /*{{{*/
  372. // ---------------------------------------------------------------------
  373. /* Returns: the number of stanzas parsed*/
  374. bool pkgSourceList::ParseFileDeb822(string const &File)
  375. {
  376. unsigned int i = 1;
  377. // see if we can read the file
  378. FileFd Fd(File, FileFd::ReadOnly);
  379. pkgTagFile Sources(&Fd, pkgTagFile::SUPPORT_COMMENTS);
  380. if (Fd.IsOpen() == false || Fd.Failed())
  381. return _error->Error(_("Malformed stanza %u in source list %s (type)"),i,File.c_str());
  382. // read step by step
  383. pkgTagSection Tags;
  384. while (Sources.Step(Tags) == true)
  385. {
  386. if(Tags.Exists("Types") == false)
  387. return _error->Error(_("Malformed stanza %u in source list %s (type)"),i,File.c_str());
  388. string const types = Tags.FindS("Types");
  389. std::vector<std::string> const list_types = VectorizeString(types, ' ');
  390. for (std::vector<std::string>::const_iterator I = list_types.begin();
  391. I != list_types.end(); ++I)
  392. {
  393. Type *Parse = Type::GetType((*I).c_str());
  394. if (Parse == 0)
  395. {
  396. _error->Error(_("Type '%s' is not known on stanza %u in source list %s"), (*I).c_str(),i,Fd.Name().c_str());
  397. return false;
  398. }
  399. if (!Parse->ParseStanza(SrcList, Tags, i, Fd))
  400. return false;
  401. ++i;
  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> ext;
  448. ext.push_back("list");
  449. ext.push_back("sources");
  450. std::vector<std::string> const List = GetListOfFilesInDir(Dir, ext, true);
  451. // Read the files
  452. for (vector<string>::const_iterator I = List.begin(); I != List.end(); ++I)
  453. if (ReadAppend(*I) == false)
  454. return false;
  455. return true;
  456. }
  457. /*}}}*/
  458. // GetLastModified() /*{{{*/
  459. // ---------------------------------------------------------------------
  460. /* */
  461. time_t pkgSourceList::GetLastModifiedTime()
  462. {
  463. vector<string> List;
  464. string Main = _config->FindFile("Dir::Etc::sourcelist");
  465. string Parts = _config->FindDir("Dir::Etc::sourceparts");
  466. // go over the parts
  467. if (DirectoryExists(Parts) == true)
  468. List = GetListOfFilesInDir(Parts, "list", true);
  469. // calculate the time
  470. std::vector<time_t> modtimes;
  471. modtimes.reserve(1 + List.size());
  472. modtimes.push_back(GetModificationTime(Main));
  473. std::transform(List.begin(), List.end(), std::back_inserter(modtimes), GetModificationTime);
  474. auto const maxmtime = std::max_element(modtimes.begin(), modtimes.end());
  475. return *maxmtime;
  476. }
  477. /*}}}*/
  478. std::vector<pkgIndexFile*> pkgSourceList::GetVolatileFiles() const /*{{{*/
  479. {
  480. return VolatileFiles;
  481. }
  482. /*}}}*/
  483. void pkgSourceList::AddVolatileFile(pkgIndexFile * const File) /*{{{*/
  484. {
  485. if (File != nullptr)
  486. VolatileFiles.push_back(File);
  487. }
  488. /*}}}*/
  489. bool pkgSourceList::AddVolatileFile(std::string const &File, std::vector<std::string> * const VolatileCmdL)/*{{{*/
  490. {
  491. // Note: FileExists matches directories and links, too!
  492. if (File.empty() || FileExists(File) == false)
  493. return false;
  494. std::string const ext = flExtension(File);
  495. if (ext == "deb")
  496. AddVolatileFile(new debDebPkgFileIndex(File));
  497. else if (ext == "dsc")
  498. AddVolatileFile(new debDscFileIndex(File));
  499. else if (FileExists(flCombine(File, "debian/control")))
  500. AddVolatileFile(new debDscFileIndex(flCombine(File, "debian/control")));
  501. else if (ext == "changes")
  502. {
  503. debDscRecordParser changes(File, nullptr);
  504. std::vector<pkgSrcRecords::File2> fileslst;
  505. if (changes.Files2(fileslst) == false || fileslst.empty())
  506. return false;
  507. auto const basedir = flNotFile(File);
  508. for (auto && file: fileslst)
  509. {
  510. auto const name = flCombine(basedir, file.Path);
  511. AddVolatileFile(name, VolatileCmdL);
  512. if (file.Hashes.VerifyFile(name) == false)
  513. return _error->Error("The file %s does not match with the hashes in the %s file!", name.c_str(), File.c_str());
  514. }
  515. return true;
  516. }
  517. else
  518. return false;
  519. if (VolatileCmdL != nullptr)
  520. VolatileCmdL->push_back(File);
  521. return true;
  522. }
  523. bool pkgSourceList::AddVolatileFile(std::string const &File)
  524. {
  525. return AddVolatileFile(File, nullptr);
  526. }
  527. /*}}}*/
  528. void pkgSourceList::AddVolatileFiles(CommandLine &CmdL, std::vector<std::string> * const VolatileCmdL)/*{{{*/
  529. {
  530. std::remove_if(CmdL.FileList + 1, CmdL.FileList + 1 + CmdL.FileSize(), [&](char const * const I) {
  531. if (I != nullptr && (I[0] == '/' || (I[0] == '.' && ((I[1] == '.' && I[2] == '/') || I[1] == '/'))))
  532. {
  533. if (AddVolatileFile(I, VolatileCmdL))
  534. ;
  535. else
  536. _error->Error(_("Unsupported file %s given on commandline"), I);
  537. return true;
  538. }
  539. return false;
  540. });
  541. }
  542. void pkgSourceList::AddVolatileFiles(CommandLine &CmdL, std::vector<const char*> * const VolatileCmdL)
  543. {
  544. std::remove_if(CmdL.FileList + 1, CmdL.FileList + 1 + CmdL.FileSize(), [&](char const * const I) {
  545. if (I != nullptr && (I[0] == '/' || (I[0] == '.' && ((I[1] == '.' && I[2] == '/') || I[1] == '/'))))
  546. {
  547. if (AddVolatileFile(I))
  548. {
  549. if (VolatileCmdL != nullptr)
  550. VolatileCmdL->push_back(I);
  551. }
  552. else
  553. _error->Error(_("Unsupported file %s given on commandline"), I);
  554. return true;
  555. }
  556. return false;
  557. });
  558. }
  559. /*}}}*/