sourcelist.cc 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466
  1. // -*- mode: cpp; mode: fold -*-
  2. // Description /*{{{*/
  3. // $Id: sourcelist.cc,v 1.1 1998/07/07 04:17:06 jgg Exp $
  4. /* ######################################################################
  5. List of Sources
  6. ##################################################################### */
  7. /*}}}*/
  8. // Include Files /*{{{*/
  9. #ifdef __GNUG__
  10. #pragma implementation "pkglib/sourcelist.h"
  11. #endif
  12. #include <pkglib/sourcelist.h>
  13. #include <pkglib/error.h>
  14. #include <pkglib/fileutl.h>
  15. #include <strutl.h>
  16. #include <options.h>
  17. #include <fstream.h>
  18. #include <stdio.h>
  19. #include <unistd.h>
  20. #include <sys/stat.h>
  21. /*}}}*/
  22. // SourceList::pkgSourceList - Constructors /*{{{*/
  23. // ---------------------------------------------------------------------
  24. /* */
  25. pkgSourceList::pkgSourceList()
  26. {
  27. }
  28. pkgSourceList::pkgSourceList(string File)
  29. {
  30. Read(File);
  31. }
  32. /*}}}*/
  33. // SourceList::ReadMainList - Read the main source list from etc /*{{{*/
  34. // ---------------------------------------------------------------------
  35. /* */
  36. bool pkgSourceList::ReadMainList()
  37. {
  38. return Read(PKG_DEB_CF_SOURCELIST);
  39. }
  40. /*}}}*/
  41. // SourceList::Read - Parse the sourcelist file /*{{{*/
  42. // ---------------------------------------------------------------------
  43. /* */
  44. bool pkgSourceList::Read(string File)
  45. {
  46. // Open the stream for reading
  47. ifstream F(File.c_str(),ios::in | ios::nocreate);
  48. if (!F != 0)
  49. return _error->Errno("ifstream::ifstream","Opening %s",File.c_str());
  50. List.erase(List.begin(),List.end());
  51. char Buffer[300];
  52. int CurLine = 0;
  53. while (F.eof() == false)
  54. {
  55. F.getline(Buffer,sizeof(Buffer));
  56. CurLine++;
  57. _strtabexpand(Buffer,sizeof(Buffer));
  58. _strstrip(Buffer);
  59. // Comment or blank
  60. if (Buffer[0] == '#' || Buffer[0] == 0)
  61. continue;
  62. // Grok it
  63. string Type;
  64. string URI;
  65. Item Itm;
  66. char *C = Buffer;
  67. if (ParseQuoteWord(C,Type) == false)
  68. return _error->Error("Malformed line %u in source list %s (type)",CurLine,File.c_str());
  69. if (ParseQuoteWord(C,URI) == false)
  70. return _error->Error("Malformed line %u in source list %s (URI)",CurLine,File.c_str());
  71. if (ParseQuoteWord(C,Itm.Dist) == false)
  72. return _error->Error("Malformed line %u in source list %s (dist)",CurLine,File.c_str());
  73. if (Itm.SetType(Type) == false)
  74. return _error->Error("Malformed line %u in source list %s (type parse)",CurLine,File.c_str());
  75. if (Itm.SetURI(URI) == false)
  76. return _error->Error("Malformed line %u in source list %s (URI parse)",CurLine,File.c_str());
  77. // Check for an absolute dists specification.
  78. if (Itm.Dist.empty() == false && Itm.Dist[Itm.Dist.size() - 1] == '/')
  79. {
  80. if (ParseQuoteWord(C,Itm.Section) == true)
  81. return _error->Error("Malformed line %u in source list %s (Absolute dist)",CurLine,File.c_str());
  82. Itm.Dist = SubstVar(Itm.Dist,"$(ARCH)",PKG_DEB_ARCH);
  83. List.push_back(Itm);
  84. continue;
  85. }
  86. // Grab the rest of the dists
  87. if (ParseQuoteWord(C,Itm.Section) == false)
  88. return _error->Error("Malformed line %u in source list %s (dist parse)",CurLine,File.c_str());
  89. do
  90. {
  91. List.push_back(Itm);
  92. }
  93. while (ParseQuoteWord(C,Itm.Section) == true);
  94. }
  95. return true;
  96. }
  97. /*}}}*/
  98. // SourceList::SanitizeURI - Hash the uri /*{{{*/
  99. // ---------------------------------------------------------------------
  100. /* This converts a URI into a safe filename. It quotes all unsafe characters
  101. and converts / to _ and removes the scheme identifier. */
  102. string pkgSourceList::SanitizeURI(string URI)
  103. {
  104. string::const_iterator I = URI.begin() + URI.find(':') + 1;
  105. for (; I < URI.end() && *I == '/'; I++);
  106. // "\x00-\x20{}|\\\\^\\[\\]<>\"\x7F-\xFF";
  107. URI = QuoteString(string(I,URI.end() - I),"\\|{}[]<>\"^~_=!@#$%^&*");
  108. string::iterator J = URI.begin();
  109. for (; J != URI.end(); J++)
  110. if (*J == '/')
  111. *J = '_';
  112. return URI;
  113. }
  114. /*}}}*/
  115. // SourceList::MatchPkgFile - Find the package file that has the ver /*{{{*/
  116. // ---------------------------------------------------------------------
  117. /* This will return List.end() if it could not find the matching
  118. file */
  119. pkgSourceList::const_iterator pkgSourceList::MatchPkgFile(pkgCache::VerIterator Ver)
  120. {
  121. string Base = PKG_DEB_ST_LIST;
  122. for (const_iterator I = List.begin(); I != List.end(); I++)
  123. {
  124. string URI = I->PackagesURI();
  125. switch (I->Type)
  126. {
  127. case Item::Deb:
  128. if (Base + SanitizeURI(URI) == Ver.File().FileName())
  129. return I;
  130. break;
  131. };
  132. }
  133. return List.end();
  134. }
  135. /*}}}*/
  136. // SourceList::Item << - Writes the item to a stream /*{{{*/
  137. // ---------------------------------------------------------------------
  138. /* This is not suitable for rebuilding the sourcelist file but it good for
  139. debugging. */
  140. ostream &operator <<(ostream &O,pkgSourceList::Item &Itm)
  141. {
  142. O << Itm.Type << ' ' << Itm.URI << ' ' << Itm.Dist << ' ' << Itm.Section;
  143. return O;
  144. }
  145. /*}}}*/
  146. // SourceList::Item::SetType - Sets the distribution type /*{{{*/
  147. // ---------------------------------------------------------------------
  148. /* */
  149. bool pkgSourceList::Item::SetType(string S)
  150. {
  151. if (S == "deb")
  152. {
  153. Type = Deb;
  154. return true;
  155. }
  156. return true;
  157. }
  158. /*}}}*/
  159. // SourceList::Item::SetURI - Set the URI /*{{{*/
  160. // ---------------------------------------------------------------------
  161. /* For simplicity we strip the scheme off the uri */
  162. bool pkgSourceList::Item::SetURI(string S)
  163. {
  164. if (S.empty() == true)
  165. return false;
  166. if (S.find(':') == string::npos)
  167. return false;
  168. S = SubstVar(S,"$(ARCH)",PKG_DEB_ARCH);
  169. // Make sure that the URN is / postfixed
  170. URI = S;
  171. if (URI[URI.size() - 1] != '/')
  172. URI += '/';
  173. return true;
  174. }
  175. /*}}}*/
  176. // SourceList::Item::PackagesURI - Returns a URI to the packages file /*{{{*/
  177. // ---------------------------------------------------------------------
  178. /* */
  179. string pkgSourceList::Item::PackagesURI() const
  180. {
  181. string Res;
  182. switch (Type)
  183. {
  184. case Deb:
  185. if (Dist[Dist.size() - 1] == '/')
  186. Res = URI + Dist;
  187. else
  188. Res = URI + "dists/" + Dist + '/' + Section +
  189. "/binary-" + PKG_DEB_ARCH + '/';
  190. Res += "Packages";
  191. break;
  192. };
  193. return Res;
  194. }
  195. /*}}}*/
  196. // SourceList::Item::PackagesInfo - Shorter version of the URI /*{{{*/
  197. // ---------------------------------------------------------------------
  198. /* This is a shorter version that is designed to be < 60 chars or so */
  199. string pkgSourceList::Item::PackagesInfo() const
  200. {
  201. string Res;
  202. switch (Type)
  203. {
  204. case Deb:
  205. Res += SiteOnly(URI) + ' ';
  206. if (Dist[Dist.size() - 1] == '/')
  207. Res += Dist;
  208. else
  209. Res += Dist + '/' + Section;
  210. Res += " Packages";
  211. break;
  212. };
  213. return Res;
  214. }
  215. /*}}}*/
  216. // SourceList::Item::ArchiveInfo - Shorter version of the archive spec /*{{{*/
  217. // ---------------------------------------------------------------------
  218. /* This is a shorter version that is designed to be < 60 chars or so */
  219. string pkgSourceList::Item::ArchiveInfo(pkgCache::VerIterator Ver) const
  220. {
  221. string Res;
  222. switch (Type)
  223. {
  224. case Deb:
  225. Res += SiteOnly(URI) + ' ';
  226. if (Dist[Dist.size() - 1] == '/')
  227. Res += Dist;
  228. else
  229. Res += Dist + '/' + Section;
  230. Res += " ";
  231. Res += Ver.ParentPkg().Name();
  232. break;
  233. };
  234. return Res;
  235. }
  236. /*}}}*/
  237. // SourceList::Item::ArchiveURI - Returns a URI to the given archive /*{{{*/
  238. // ---------------------------------------------------------------------
  239. /* */
  240. string pkgSourceList::Item::ArchiveURI(string File) const
  241. {
  242. string Res;
  243. switch (Type)
  244. {
  245. case Deb:
  246. Res = URI + File;
  247. break;
  248. };
  249. return Res;
  250. }
  251. /*}}}*/
  252. // SourceList::Item::SiteOnly - Strip off the path part of a URI /*{{{*/
  253. // ---------------------------------------------------------------------
  254. /* */
  255. string pkgSourceList::Item::SiteOnly(string URI) const
  256. {
  257. unsigned int Pos = URI.find(':');
  258. if (Pos == string::npos || Pos + 3 > URI.length())
  259. return URI;
  260. if (URI[Pos + 1] != '/' || URI[Pos + 2] != '/')
  261. return URI;
  262. Pos = URI.find('/',Pos + 3);
  263. if (Pos == string::npos)
  264. return URI;
  265. return string(URI,0,Pos);
  266. }
  267. /*}}}*/
  268. // UpdateMeta - Update the meta information /*{{{*/
  269. // ---------------------------------------------------------------------
  270. /* The meta information is package files, revision information and mirror
  271. lists. */
  272. bool pkgUpdateMeta(pkgSourceList &List,pkgAquire &Engine)
  273. {
  274. if (Engine.OutputDir(PKG_DEB_ST_LIST) == false)
  275. return false;
  276. for (pkgSourceList::const_iterator I = List.begin(); I != List.end(); I++)
  277. {
  278. string URI = I->PackagesURI();
  279. string GetInfo = I->PackagesInfo();
  280. switch (I->Type)
  281. {
  282. case pkgSourceList::Item::Deb:
  283. if (Engine.Get(URI + ".gz",List.SanitizeURI(URI),GetInfo) == false)
  284. return false;
  285. break;
  286. };
  287. }
  288. return true;
  289. }
  290. /*}}}*/
  291. // MakeSrcCache - Generate a cache file of all the package files /*{{{*/
  292. // ---------------------------------------------------------------------
  293. /* This goes over the source list and builds a cache of all the package
  294. files. */
  295. bool pkgMakeSrcCache(pkgSourceList &List)
  296. {
  297. // First we date check the cache
  298. bool Bad = false;
  299. while (Bad == false)
  300. {
  301. if (FileExists(PKG_DEB_CA_SRCCACHE) == false)
  302. break;
  303. pkgCache Cache(PKG_DEB_CA_SRCCACHE,true,true);
  304. if (_error->PendingError() == true)
  305. {
  306. _error->Discard();
  307. break;
  308. }
  309. // They are certianly out of sync
  310. if (Cache.Head().PackageFileCount != List.size())
  311. break;
  312. for (pkgCache::PkgFileIterator F(Cache); F.end() == false; F++)
  313. {
  314. // Search for a match in the source list
  315. Bad = true;
  316. for (pkgSourceList::const_iterator I = List.begin();
  317. I != List.end(); I++)
  318. {
  319. string File = string(PKG_DEB_ST_LIST) +
  320. List.SanitizeURI(I->PackagesURI());
  321. if (F.FileName() == File)
  322. {
  323. Bad = false;
  324. break;
  325. }
  326. }
  327. // Check if the file matches what was cached
  328. Bad |= !F.IsOk();
  329. if (Bad == true)
  330. break;
  331. }
  332. if (Bad == false)
  333. return true;
  334. }
  335. unlink(PKG_DEB_CA_SRCCACHE);
  336. pkgCache::MergeState Merge(PKG_DEB_CA_SRCCACHE);
  337. if (_error->PendingError() == true)
  338. return false;
  339. for (pkgSourceList::const_iterator I = List.begin(); I != List.end(); I++)
  340. {
  341. string File = string(PKG_DEB_ST_LIST) + List.SanitizeURI(I->PackagesURI());
  342. if (Merge.MergePackageFile(File,"??","??") == false)
  343. return false;
  344. }
  345. return true;
  346. }
  347. /*}}}*/
  348. // MakeStatusCache - Generates a cache that includes the status files /*{{{*/
  349. // ---------------------------------------------------------------------
  350. /* This copies the package source cache and then merges the status and
  351. xstatus files into it. */
  352. bool pkgMakeStatusCache()
  353. {
  354. // Quickly check if the existing package cache is ok
  355. bool Bad = false;
  356. while (Bad == false)
  357. {
  358. if (FileExists(PKG_DEB_CA_PKGCACHE) == false)
  359. break;
  360. /* We check the dates of the two caches. This takes care of most things
  361. quickly and easially */
  362. struct stat Src;
  363. struct stat Pkg;
  364. if (stat(PKG_DEB_CA_PKGCACHE,&Pkg) != 0 ||
  365. stat(PKG_DEB_CA_SRCCACHE,&Src) != 0)
  366. break;
  367. if (difftime(Src.st_mtime,Pkg.st_mtime) > 0)
  368. break;
  369. pkgCache Cache(PKG_DEB_CA_PKGCACHE,true,true);
  370. if (_error->PendingError() == true)
  371. {
  372. _error->Discard();
  373. break;
  374. }
  375. for (pkgCache::PkgFileIterator F(Cache); F.end() == false; F++)
  376. {
  377. if (F.IsOk() == false)
  378. {
  379. Bad = true;
  380. break;
  381. }
  382. }
  383. if (Bad == false)
  384. return true;
  385. }
  386. // Check the integrity of the source cache.
  387. {
  388. pkgCache Cache(PKG_DEB_CA_SRCCACHE,true,true);
  389. if (_error->PendingError() == true)
  390. return false;
  391. }
  392. // Sub scope so that merge destructs before we rename the file...
  393. string Cache = PKG_DEB_CA_PKGCACHE ".new";
  394. {
  395. if (CopyFile(PKG_DEB_CA_SRCCACHE,Cache) == false)
  396. return false;
  397. pkgCache::MergeState Merge(Cache);
  398. if (_error->PendingError() == true)
  399. return false;
  400. // Merge in the user status file
  401. if (FileExists(PKG_DEB_ST_USERSTATUS) == true)
  402. if (Merge.MergePackageFile(PKG_DEB_ST_USERSTATUS,"status","0",
  403. pkgFLAG_NotSource) == false)
  404. return false;
  405. // Merge in the extra status file
  406. if (FileExists(PKG_DEB_ST_XSTATUS) == true)
  407. if (Merge.MergePackageFile(PKG_DEB_ST_XSTATUS,"status","0",
  408. pkgFLAG_NotSource) == false)
  409. return false;
  410. // Merge in the status file
  411. if (Merge.MergePackageFile("/var/lib/dpkg/status","status","0",
  412. pkgFLAG_NotSource) == false)
  413. return false;
  414. }
  415. if (rename(Cache.c_str(),PKG_DEB_CA_PKGCACHE) != 0)
  416. return false;
  417. return true;
  418. }
  419. /*}}}*/