indexcopy.cc 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785
  1. // -*- mode: cpp; mode: fold -*-
  2. // Description /*{{{*/
  3. // $Id: indexcopy.cc,v 1.10 2002/03/26 07:38:58 jgg Exp $
  4. /* ######################################################################
  5. Index Copying - Aid for copying and verifying the index files
  6. This class helps apt-cache reconstruct a damaged index files.
  7. ##################################################################### */
  8. /*}}}*/
  9. // Include Files /*{{{*/
  10. #include<config.h>
  11. #include <apt-pkg/error.h>
  12. #include <apt-pkg/progress.h>
  13. #include <apt-pkg/strutl.h>
  14. #include <apt-pkg/fileutl.h>
  15. #include <apt-pkg/aptconfiguration.h>
  16. #include <apt-pkg/configuration.h>
  17. #include <apt-pkg/tagfile.h>
  18. #include <apt-pkg/metaindex.h>
  19. #include <apt-pkg/cdrom.h>
  20. #include <apt-pkg/gpgv.h>
  21. #include <apt-pkg/hashes.h>
  22. #include <apt-pkg/debmetaindex.h>
  23. #include <iostream>
  24. #include <unistd.h>
  25. #include <sys/stat.h>
  26. #include <stdio.h>
  27. #include <stdlib.h>
  28. #include <string.h>
  29. #include <sstream>
  30. #include "indexcopy.h"
  31. #include <apti18n.h>
  32. /*}}}*/
  33. using namespace std;
  34. // IndexCopy::CopyPackages - Copy the package files from the CD /*{{{*/
  35. // ---------------------------------------------------------------------
  36. /* */
  37. bool IndexCopy::CopyPackages(string CDROM,string Name,vector<string> &List,
  38. pkgCdromStatus *log)
  39. {
  40. OpProgress *Progress = NULL;
  41. if (List.empty() == true)
  42. return true;
  43. if(log)
  44. Progress = log->GetOpProgress();
  45. bool NoStat = _config->FindB("APT::CDROM::Fast",false);
  46. bool Debug = _config->FindB("Debug::aptcdrom",false);
  47. // Prepare the progress indicator
  48. off_t TotalSize = 0;
  49. std::vector<APT::Configuration::Compressor> const compressor = APT::Configuration::getCompressors();
  50. for (vector<string>::iterator I = List.begin(); I != List.end(); ++I)
  51. {
  52. struct stat Buf;
  53. bool found = false;
  54. std::string file = std::string(*I).append(GetFileName());
  55. for (std::vector<APT::Configuration::Compressor>::const_iterator c = compressor.begin();
  56. c != compressor.end(); ++c)
  57. {
  58. if (stat((file + c->Extension).c_str(), &Buf) != 0)
  59. continue;
  60. found = true;
  61. break;
  62. }
  63. if (found == false)
  64. return _error->Errno("stat", "Stat failed for %s", file.c_str());
  65. TotalSize += Buf.st_size;
  66. }
  67. off_t CurrentSize = 0;
  68. unsigned int NotFound = 0;
  69. unsigned int WrongSize = 0;
  70. unsigned int Packages = 0;
  71. for (vector<string>::iterator I = List.begin(); I != List.end(); ++I)
  72. {
  73. string OrigPath = string(*I,CDROM.length());
  74. // Open the package file
  75. FileFd Pkg(*I + GetFileName(), FileFd::ReadOnly, FileFd::Auto);
  76. off_t const FileSize = Pkg.Size();
  77. pkgTagFile Parser(&Pkg);
  78. if (Pkg.IsOpen() == false || Pkg.Failed())
  79. return false;
  80. // Open the output file
  81. char S[400];
  82. snprintf(S,sizeof(S),"cdrom:[%s]/%s%s",Name.c_str(),
  83. (*I).c_str() + CDROM.length(),GetFileName());
  84. string TargetF = _config->FindDir("Dir::State::lists") + "partial/";
  85. TargetF += URItoFileName(S);
  86. FileFd Target;
  87. if (_config->FindB("APT::CDROM::NoAct",false) == true)
  88. {
  89. TargetF = "/dev/null";
  90. Target.Open(TargetF,FileFd::WriteExists);
  91. } else {
  92. Target.Open(TargetF,FileFd::WriteAtomic);
  93. }
  94. if (Target.IsOpen() == false || Target.Failed())
  95. return false;
  96. // Setup the progress meter
  97. if(Progress)
  98. Progress->OverallProgress(CurrentSize,TotalSize,FileSize,
  99. string("Reading ") + Type() + " Indexes");
  100. // Parse
  101. if(Progress)
  102. Progress->SubProgress(Pkg.Size());
  103. pkgTagSection Section;
  104. this->Section = &Section;
  105. string Prefix;
  106. unsigned long Hits = 0;
  107. unsigned long Chop = 0;
  108. while (Parser.Step(Section) == true)
  109. {
  110. if(Progress)
  111. Progress->Progress(Parser.Offset());
  112. string File;
  113. unsigned long long Size;
  114. if (GetFile(File,Size) == false)
  115. return false;
  116. if (Chop != 0)
  117. File = OrigPath + ChopDirs(File,Chop);
  118. // See if the file exists
  119. if (NoStat == false || Hits < 10)
  120. {
  121. // Attempt to fix broken structure
  122. if (Hits == 0)
  123. {
  124. if (ReconstructPrefix(Prefix,OrigPath,CDROM,File) == false &&
  125. ReconstructChop(Chop,*I,File) == false)
  126. {
  127. if (Debug == true)
  128. clog << "Missed: " << File << endl;
  129. NotFound++;
  130. continue;
  131. }
  132. if (Chop != 0)
  133. File = OrigPath + ChopDirs(File,Chop);
  134. }
  135. // Get the size
  136. struct stat Buf;
  137. if (stat((CDROM + Prefix + File).c_str(),&Buf) != 0 ||
  138. Buf.st_size == 0)
  139. {
  140. bool Mangled = false;
  141. // Attempt to fix busted symlink support for one instance
  142. string OrigFile = File;
  143. string::size_type Start = File.find("binary-");
  144. string::size_type End = File.find("/",Start+3);
  145. if (Start != string::npos && End != string::npos)
  146. {
  147. File.replace(Start,End-Start,"binary-all");
  148. Mangled = true;
  149. }
  150. if (Mangled == false ||
  151. stat((CDROM + Prefix + File).c_str(),&Buf) != 0)
  152. {
  153. if (Debug == true)
  154. clog << "Missed(2): " << OrigFile << endl;
  155. NotFound++;
  156. continue;
  157. }
  158. }
  159. // Size match
  160. if ((unsigned long long)Buf.st_size != Size)
  161. {
  162. if (Debug == true)
  163. clog << "Wrong Size: " << File << endl;
  164. WrongSize++;
  165. continue;
  166. }
  167. }
  168. Packages++;
  169. Hits++;
  170. if (RewriteEntry(Target, File) == false)
  171. return false;
  172. }
  173. if (Debug == true)
  174. cout << " Processed by using Prefix '" << Prefix << "' and chop " << Chop << endl;
  175. if (_config->FindB("APT::CDROM::NoAct",false) == false)
  176. {
  177. // Move out of the partial directory
  178. Target.Close();
  179. string FinalF = _config->FindDir("Dir::State::lists");
  180. FinalF += URItoFileName(S);
  181. if (rename(TargetF.c_str(),FinalF.c_str()) != 0)
  182. return _error->Errno("rename","Failed to rename");
  183. ChangeOwnerAndPermissionOfFile("CopyPackages", FinalF.c_str(), "root", ROOT_GROUP, 0644);
  184. }
  185. /* Mangle the source to be in the proper notation with
  186. prefix dist [component] */
  187. *I = string(*I,Prefix.length());
  188. ConvertToSourceList(CDROM,*I);
  189. *I = Prefix + ' ' + *I;
  190. CurrentSize += FileSize;
  191. }
  192. if(Progress)
  193. Progress->Done();
  194. // Some stats
  195. if(log) {
  196. stringstream msg;
  197. if(NotFound == 0 && WrongSize == 0)
  198. ioprintf(msg, _("Wrote %i records.\n"), Packages);
  199. else if (NotFound != 0 && WrongSize == 0)
  200. ioprintf(msg, _("Wrote %i records with %i missing files.\n"),
  201. Packages, NotFound);
  202. else if (NotFound == 0 && WrongSize != 0)
  203. ioprintf(msg, _("Wrote %i records with %i mismatched files\n"),
  204. Packages, WrongSize);
  205. if (NotFound != 0 && WrongSize != 0)
  206. ioprintf(msg, _("Wrote %i records with %i missing files and %i mismatched files\n"), Packages, NotFound, WrongSize);
  207. }
  208. if (Packages == 0)
  209. _error->Warning("No valid records were found.");
  210. if (NotFound + WrongSize > 10)
  211. _error->Warning("A lot of entries were discarded, something may be wrong.\n");
  212. return true;
  213. }
  214. /*}}}*/
  215. // IndexCopy::ChopDirs - Chop off the leading directory components /*{{{*/
  216. // ---------------------------------------------------------------------
  217. /* */
  218. string IndexCopy::ChopDirs(string Path,unsigned int Depth)
  219. {
  220. string::size_type I = 0;
  221. do
  222. {
  223. I = Path.find('/',I+1);
  224. Depth--;
  225. }
  226. while (I != string::npos && Depth != 0);
  227. if (I == string::npos)
  228. return string();
  229. return string(Path,I+1);
  230. }
  231. /*}}}*/
  232. // IndexCopy::ReconstructPrefix - Fix strange prefixing /*{{{*/
  233. // ---------------------------------------------------------------------
  234. /* This prepends dir components from the path to the package files to
  235. the path to the deb until it is found */
  236. bool IndexCopy::ReconstructPrefix(string &Prefix,string OrigPath,string CD,
  237. string File)
  238. {
  239. bool Debug = _config->FindB("Debug::aptcdrom",false);
  240. unsigned int Depth = 1;
  241. string MyPrefix = Prefix;
  242. while (1)
  243. {
  244. struct stat Buf;
  245. if (stat((CD + MyPrefix + File).c_str(),&Buf) != 0)
  246. {
  247. if (Debug == true)
  248. cout << "Failed, " << CD + MyPrefix + File << endl;
  249. if (GrabFirst(OrigPath,MyPrefix,Depth++) == true)
  250. continue;
  251. return false;
  252. }
  253. else
  254. {
  255. Prefix = MyPrefix;
  256. return true;
  257. }
  258. }
  259. return false;
  260. }
  261. /*}}}*/
  262. // IndexCopy::ReconstructChop - Fixes bad source paths /*{{{*/
  263. // ---------------------------------------------------------------------
  264. /* This removes path components from the filename and prepends the location
  265. of the package files until a file is found */
  266. bool IndexCopy::ReconstructChop(unsigned long &Chop,string Dir,string File)
  267. {
  268. // Attempt to reconstruct the filename
  269. unsigned long Depth = 0;
  270. while (1)
  271. {
  272. struct stat Buf;
  273. if (stat((Dir + File).c_str(),&Buf) != 0)
  274. {
  275. File = ChopDirs(File,1);
  276. Depth++;
  277. if (File.empty() == false)
  278. continue;
  279. return false;
  280. }
  281. else
  282. {
  283. Chop = Depth;
  284. return true;
  285. }
  286. }
  287. return false;
  288. }
  289. /*}}}*/
  290. // IndexCopy::ConvertToSourceList - Convert a Path to a sourcelist /*{{{*/
  291. // ---------------------------------------------------------------------
  292. /* We look for things in dists/ notation and convert them to
  293. <dist> <component> form otherwise it is left alone. This also strips
  294. the CD path.
  295. This implements a regex sort of like:
  296. (.*)/dists/([^/]*)/(.*)/binary-*
  297. ^ ^ ^- Component
  298. | |-------- Distribution
  299. |------------------- Path
  300. It was deciced to use only a single word for dist (rather than say
  301. unstable/non-us) to increase the chance that each CD gets a single
  302. line in sources.list.
  303. */
  304. void IndexCopy::ConvertToSourceList(string CD,string &Path)
  305. {
  306. // Strip the cdrom base path
  307. Path = string(Path,CD.length());
  308. if (Path.empty() == true)
  309. Path = "/";
  310. // Too short to be a dists/ type
  311. if (Path.length() < strlen("dists/"))
  312. return;
  313. // Not a dists type.
  314. if (stringcmp(Path.c_str(),Path.c_str()+strlen("dists/"),"dists/") != 0)
  315. return;
  316. // Isolate the dist
  317. string::size_type Slash = strlen("dists/");
  318. string::size_type Slash2 = Path.find('/',Slash + 1);
  319. if (Slash2 == string::npos || Slash2 + 2 >= Path.length())
  320. return;
  321. string Dist = string(Path,Slash,Slash2 - Slash);
  322. // Isolate the component
  323. Slash = Slash2;
  324. for (unsigned I = 0; I != 10; I++)
  325. {
  326. Slash = Path.find('/',Slash+1);
  327. if (Slash == string::npos || Slash + 2 >= Path.length())
  328. return;
  329. string Comp = string(Path,Slash2+1,Slash - Slash2-1);
  330. // Verify the trailing binary- bit
  331. string::size_type BinSlash = Path.find('/',Slash + 1);
  332. if (Slash == string::npos)
  333. return;
  334. string Binary = string(Path,Slash+1,BinSlash - Slash-1);
  335. if (strncmp(Binary.c_str(), "binary-", strlen("binary-")) == 0)
  336. {
  337. Binary.erase(0, strlen("binary-"));
  338. if (APT::Configuration::checkArchitecture(Binary) == false)
  339. continue;
  340. }
  341. else if (Binary != "source")
  342. continue;
  343. Path = Dist + ' ' + Comp;
  344. return;
  345. }
  346. }
  347. /*}}}*/
  348. // IndexCopy::GrabFirst - Return the first Depth path components /*{{{*/
  349. // ---------------------------------------------------------------------
  350. /* */
  351. bool IndexCopy::GrabFirst(string Path,string &To,unsigned int Depth)
  352. {
  353. string::size_type I = 0;
  354. do
  355. {
  356. I = Path.find('/',I+1);
  357. Depth--;
  358. }
  359. while (I != string::npos && Depth != 0);
  360. if (I == string::npos)
  361. return false;
  362. To = string(Path,0,I+1);
  363. return true;
  364. }
  365. /*}}}*/
  366. // PackageCopy::GetFile - Get the file information from the section /*{{{*/
  367. // ---------------------------------------------------------------------
  368. /* */
  369. bool PackageCopy::GetFile(string &File,unsigned long long &Size)
  370. {
  371. File = Section->FindS("Filename");
  372. Size = Section->FindI("Size");
  373. if (File.empty() || Size == 0)
  374. return _error->Error("Cannot find filename or size tag");
  375. return true;
  376. }
  377. /*}}}*/
  378. // PackageCopy::RewriteEntry - Rewrite the entry with a new filename /*{{{*/
  379. bool PackageCopy::RewriteEntry(FileFd &Target,string const &File)
  380. {
  381. std::vector<pkgTagSection::Tag> Changes;
  382. Changes.push_back(pkgTagSection::Tag::Rewrite("Filename", File));
  383. if (Section->Write(Target, TFRewritePackageOrder, Changes) == false)
  384. return false;
  385. return Target.Write("\n", 1);
  386. }
  387. /*}}}*/
  388. // SourceCopy::GetFile - Get the file information from the section /*{{{*/
  389. // ---------------------------------------------------------------------
  390. /* */
  391. bool SourceCopy::GetFile(string &File,unsigned long long &Size)
  392. {
  393. string Files = Section->FindS("Files");
  394. if (Files.empty() == true)
  395. return false;
  396. // Stash the / terminated directory prefix
  397. string Base = Section->FindS("Directory");
  398. if (Base.empty() == false && Base[Base.length()-1] != '/')
  399. Base += '/';
  400. // Read the first file triplet
  401. const char *C = Files.c_str();
  402. string sSize;
  403. string MD5Hash;
  404. // Parse each of the elements
  405. if (ParseQuoteWord(C,MD5Hash) == false ||
  406. ParseQuoteWord(C,sSize) == false ||
  407. ParseQuoteWord(C,File) == false)
  408. return _error->Error("Error parsing file record");
  409. // Parse the size and append the directory
  410. Size = strtoull(sSize.c_str(), NULL, 10);
  411. File = Base + File;
  412. return true;
  413. }
  414. /*}}}*/
  415. // SourceCopy::RewriteEntry - Rewrite the entry with a new filename /*{{{*/
  416. bool SourceCopy::RewriteEntry(FileFd &Target, std::string const &File)
  417. {
  418. string const Dir(File,0,File.rfind('/'));
  419. std::vector<pkgTagSection::Tag> Changes;
  420. Changes.push_back(pkgTagSection::Tag::Rewrite("Directory", Dir));
  421. if (Section->Write(Target, TFRewriteSourceOrder, Changes) == false)
  422. return false;
  423. return Target.Write("\n", 1);
  424. }
  425. /*}}}*/
  426. // SigVerify::Verify - Verify a files md5sum against its metaindex /*{{{*/
  427. bool SigVerify::Verify(string prefix, string file, metaIndex *MetaIndex)
  428. {
  429. const metaIndex::checkSum *Record = MetaIndex->Lookup(file);
  430. bool const Debug = _config->FindB("Debug::aptcdrom",false);
  431. // we skip non-existing files in the verifcation of the Release file
  432. // as non-existing files do not harm, but a warning scares people and
  433. // makes it hard to strip unneeded files from an ISO like uncompressed
  434. // indexes as it is done on the mirrors (see also LP: #255545 )
  435. if(!RealFileExists(prefix+file))
  436. {
  437. if (Debug == true)
  438. cout << "Skipping nonexistent in " << prefix << " file " << file << std::endl;
  439. return true;
  440. }
  441. if (!Record)
  442. {
  443. _error->Warning(_("Can't find authentication record for: %s"), file.c_str());
  444. return false;
  445. }
  446. if (!Record->Hashes.VerifyFile(prefix+file))
  447. {
  448. _error->Warning(_("Hash mismatch for: %s"),file.c_str());
  449. return false;
  450. }
  451. if(Debug == true)
  452. {
  453. cout << "File: " << prefix+file << endl
  454. << "Expected Hash " << endl;
  455. for (HashStringList::const_iterator hs = Record->Hashes.begin(); hs != Record->Hashes.end(); ++hs)
  456. std::cout << "\t- " << hs->toStr() << std::endl;
  457. }
  458. return true;
  459. }
  460. /*}}}*/
  461. bool SigVerify::CopyMetaIndex(string CDROM, string CDName, /*{{{*/
  462. string prefix, string file)
  463. {
  464. char S[400];
  465. snprintf(S,sizeof(S),"cdrom:[%s]/%s%s",CDName.c_str(),
  466. (prefix).c_str() + CDROM.length(),file.c_str());
  467. string TargetF = _config->FindDir("Dir::State::lists");
  468. TargetF += URItoFileName(S);
  469. FileFd Target;
  470. FileFd Rel;
  471. Target.Open(TargetF,FileFd::WriteAtomic);
  472. Rel.Open(prefix + file,FileFd::ReadOnly);
  473. if (CopyFile(Rel,Target) == false || Target.Close() == false)
  474. return _error->Error("Copying of '%s' for '%s' from '%s' failed", file.c_str(), CDName.c_str(), prefix.c_str());
  475. ChangeOwnerAndPermissionOfFile("CopyPackages", TargetF.c_str(), "root", ROOT_GROUP, 0644);
  476. return true;
  477. }
  478. /*}}}*/
  479. bool SigVerify::CopyAndVerify(string CDROM,string Name,vector<string> &SigList, /*{{{*/
  480. vector<string> /*PkgList*/,vector<string> /*SrcList*/)
  481. {
  482. if (SigList.empty() == true)
  483. return true;
  484. bool Debug = _config->FindB("Debug::aptcdrom",false);
  485. // Read all Release files
  486. for (vector<string>::iterator I = SigList.begin(); I != SigList.end(); ++I)
  487. {
  488. if(Debug)
  489. cout << "Signature verify for: " << *I << endl;
  490. metaIndex *MetaIndex = new debReleaseIndex("","");
  491. string prefix = *I;
  492. string const releasegpg = *I+"Release.gpg";
  493. string const release = *I+"Release";
  494. string const inrelease = *I+"InRelease";
  495. bool useInRelease = true;
  496. // a Release.gpg without a Release should never happen
  497. if (RealFileExists(inrelease) == true)
  498. ;
  499. else if(RealFileExists(release) == false || RealFileExists(releasegpg) == false)
  500. {
  501. delete MetaIndex;
  502. continue;
  503. }
  504. else
  505. useInRelease = false;
  506. pid_t pid = ExecFork();
  507. if(pid < 0) {
  508. _error->Error("Fork failed");
  509. return false;
  510. }
  511. if(pid == 0)
  512. {
  513. if (useInRelease == true)
  514. ExecGPGV(inrelease, inrelease);
  515. else
  516. ExecGPGV(release, releasegpg);
  517. }
  518. if(!ExecWait(pid, "gpgv")) {
  519. _error->Warning("Signature verification failed for: %s",
  520. (useInRelease ? inrelease.c_str() : releasegpg.c_str()));
  521. // something went wrong, don't copy the Release.gpg
  522. // FIXME: delete any existing gpg file?
  523. delete MetaIndex;
  524. continue;
  525. }
  526. // Open the Release file and add it to the MetaIndex
  527. std::string ErrorText;
  528. if(MetaIndex->Load(release, &ErrorText) == false)
  529. {
  530. _error->Error("%s", ErrorText.c_str());
  531. return false;
  532. }
  533. // go over the Indexfiles and see if they verify
  534. // if so, remove them from our copy of the lists
  535. vector<string> keys = MetaIndex->MetaKeys();
  536. for (vector<string>::iterator I = keys.begin(); I != keys.end(); ++I)
  537. {
  538. if(!Verify(prefix,*I, MetaIndex)) {
  539. // something went wrong, don't copy the Release.gpg
  540. // FIXME: delete any existing gpg file?
  541. _error->Discard();
  542. continue;
  543. }
  544. }
  545. // we need a fresh one for the Release.gpg
  546. delete MetaIndex;
  547. // everything was fine, copy the Release and Release.gpg file
  548. if (useInRelease == true)
  549. CopyMetaIndex(CDROM, Name, prefix, "InRelease");
  550. else
  551. {
  552. CopyMetaIndex(CDROM, Name, prefix, "Release");
  553. CopyMetaIndex(CDROM, Name, prefix, "Release.gpg");
  554. }
  555. }
  556. return true;
  557. }
  558. /*}}}*/
  559. // SigVerify::RunGPGV - deprecated wrapper calling ExecGPGV /*{{{*/
  560. APT_NORETURN bool SigVerify::RunGPGV(std::string const &File, std::string const &FileOut,
  561. int const &statusfd, int fd[2]) {
  562. ExecGPGV(File, FileOut, statusfd, fd);
  563. }
  564. APT_NORETURN bool SigVerify::RunGPGV(std::string const &File, std::string const &FileOut,
  565. int const &statusfd) {
  566. ExecGPGV(File, FileOut, statusfd);
  567. }
  568. /*}}}*/
  569. bool TranslationsCopy::CopyTranslations(string CDROM,string Name, /*{{{*/
  570. vector<string> &List, pkgCdromStatus *log)
  571. {
  572. OpProgress *Progress = NULL;
  573. if (List.empty() == true)
  574. return true;
  575. if(log)
  576. Progress = log->GetOpProgress();
  577. bool Debug = _config->FindB("Debug::aptcdrom",false);
  578. // Prepare the progress indicator
  579. off_t TotalSize = 0;
  580. std::vector<APT::Configuration::Compressor> const compressor = APT::Configuration::getCompressors();
  581. for (vector<string>::iterator I = List.begin(); I != List.end(); ++I)
  582. {
  583. struct stat Buf;
  584. bool found = false;
  585. std::string file = *I;
  586. for (std::vector<APT::Configuration::Compressor>::const_iterator c = compressor.begin();
  587. c != compressor.end(); ++c)
  588. {
  589. if (stat((file + c->Extension).c_str(), &Buf) != 0)
  590. continue;
  591. found = true;
  592. break;
  593. }
  594. if (found == false)
  595. return _error->Errno("stat", "Stat failed for %s", file.c_str());
  596. TotalSize += Buf.st_size;
  597. }
  598. off_t CurrentSize = 0;
  599. unsigned int NotFound = 0;
  600. unsigned int WrongSize = 0;
  601. unsigned int Packages = 0;
  602. for (vector<string>::iterator I = List.begin(); I != List.end(); ++I)
  603. {
  604. // Open the package file
  605. FileFd Pkg(*I, FileFd::ReadOnly, FileFd::Auto);
  606. off_t const FileSize = Pkg.Size();
  607. pkgTagFile Parser(&Pkg);
  608. if (Pkg.IsOpen() == false || Pkg.Failed())
  609. return false;
  610. // Open the output file
  611. char S[400];
  612. snprintf(S,sizeof(S),"cdrom:[%s]/%s",Name.c_str(),
  613. (*I).c_str() + CDROM.length());
  614. string TargetF = _config->FindDir("Dir::State::lists") + "partial/";
  615. TargetF += URItoFileName(S);
  616. FileFd Target;
  617. if (_config->FindB("APT::CDROM::NoAct",false) == true)
  618. {
  619. TargetF = "/dev/null";
  620. Target.Open(TargetF,FileFd::WriteExists);
  621. } else {
  622. Target.Open(TargetF,FileFd::WriteAtomic);
  623. }
  624. if (Pkg.IsOpen() == false || Pkg.Failed())
  625. return false;
  626. // Setup the progress meter
  627. if(Progress)
  628. Progress->OverallProgress(CurrentSize,TotalSize,FileSize,
  629. string("Reading Translation Indexes"));
  630. // Parse
  631. if(Progress)
  632. Progress->SubProgress(Pkg.Size());
  633. pkgTagSection Section;
  634. this->Section = &Section;
  635. string Prefix;
  636. unsigned long Hits = 0;
  637. while (Parser.Step(Section) == true)
  638. {
  639. if(Progress)
  640. Progress->Progress(Parser.Offset());
  641. if (Section.Write(Target) == false || Target.Write("\n", 1) == false)
  642. return false;
  643. Packages++;
  644. Hits++;
  645. }
  646. if (Debug == true)
  647. cout << " Processed by using Prefix '" << Prefix << "' and chop " << endl;
  648. if (_config->FindB("APT::CDROM::NoAct",false) == false)
  649. {
  650. // Move out of the partial directory
  651. Target.Close();
  652. string FinalF = _config->FindDir("Dir::State::lists");
  653. FinalF += URItoFileName(S);
  654. if (rename(TargetF.c_str(),FinalF.c_str()) != 0)
  655. return _error->Errno("rename","Failed to rename");
  656. ChangeOwnerAndPermissionOfFile("CopyTranslations", FinalF.c_str(), "root", ROOT_GROUP, 0644);
  657. }
  658. CurrentSize += FileSize;
  659. }
  660. if(Progress)
  661. Progress->Done();
  662. // Some stats
  663. if(log) {
  664. stringstream msg;
  665. if(NotFound == 0 && WrongSize == 0)
  666. ioprintf(msg, _("Wrote %i records.\n"), Packages);
  667. else if (NotFound != 0 && WrongSize == 0)
  668. ioprintf(msg, _("Wrote %i records with %i missing files.\n"),
  669. Packages, NotFound);
  670. else if (NotFound == 0 && WrongSize != 0)
  671. ioprintf(msg, _("Wrote %i records with %i mismatched files\n"),
  672. Packages, WrongSize);
  673. if (NotFound != 0 && WrongSize != 0)
  674. ioprintf(msg, _("Wrote %i records with %i missing files and %i mismatched files\n"), Packages, NotFound, WrongSize);
  675. }
  676. if (Packages == 0)
  677. _error->Warning("No valid records were found.");
  678. if (NotFound + WrongSize > 10)
  679. _error->Warning("A lot of entries were discarded, something may be wrong.\n");
  680. return true;
  681. }
  682. /*}}}*/
  683. IndexCopy::IndexCopy() : d(nullptr), Section(nullptr) {}
  684. APT_CONST IndexCopy::~IndexCopy() {}
  685. PackageCopy::PackageCopy() : IndexCopy(), d(NULL) {}
  686. APT_CONST PackageCopy::~PackageCopy() {}
  687. SourceCopy::SourceCopy() : IndexCopy(), d(NULL) {}
  688. APT_CONST SourceCopy::~SourceCopy() {}
  689. TranslationsCopy::TranslationsCopy() : d(nullptr), Section(nullptr) {}
  690. APT_CONST TranslationsCopy::~TranslationsCopy() {}
  691. SigVerify::SigVerify() : d(NULL) {}
  692. APT_CONST SigVerify::~SigVerify() {}