writer.cc 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757
  1. // -*- mode: cpp; mode: fold -*-
  2. // Description /*{{{*/
  3. // $Id: writer.cc,v 1.2 2001/02/20 07:03:18 jgg Exp $
  4. /* ######################################################################
  5. Writer
  6. The file writer classes. These write various types of output, sources,
  7. packages and contents.
  8. ##################################################################### */
  9. /*}}}*/
  10. // Include Files /*{{{*/
  11. #ifdef __GNUG__
  12. #pragma implementation "writer.h"
  13. #endif
  14. #include "writer.h"
  15. #include <apt-pkg/strutl.h>
  16. #include <apt-pkg/error.h>
  17. #include <apt-pkg/configuration.h>
  18. #include <apt-pkg/md5.h>
  19. #include <apt-pkg/deblistparser.h>
  20. #include <sys/types.h>
  21. #include <unistd.h>
  22. #include <ftw.h>
  23. #include "cachedb.h"
  24. #include "apt-ftparchive.h"
  25. #include "multicompress.h"
  26. /*}}}*/
  27. FTWScanner *FTWScanner::Owner;
  28. // FTWScanner::FTWScanner - Constructor /*{{{*/
  29. // ---------------------------------------------------------------------
  30. /* */
  31. FTWScanner::FTWScanner()
  32. {
  33. ErrorPrinted = false;
  34. NoLinkAct = !_config->FindB("APT::FTPArchive::DeLinkAct",true);
  35. TmpExt = 0;
  36. Ext[0] = 0;
  37. RealPath = 0;
  38. long PMax = pathconf(".",_PC_PATH_MAX);
  39. if (PMax > 0)
  40. RealPath = new char[PMax];
  41. }
  42. /*}}}*/
  43. // FTWScanner::Scanner - FTW Scanner /*{{{*/
  44. // ---------------------------------------------------------------------
  45. /* This is the FTW scanner, it processes each directory element in the
  46. directory tree. */
  47. int FTWScanner::Scanner(const char *File,const struct stat *sb,int Flag)
  48. {
  49. if (Flag == FTW_DNR)
  50. {
  51. Owner->NewLine(1);
  52. c1out << "W: Unable to read directory " << File << endl;
  53. }
  54. if (Flag == FTW_NS)
  55. {
  56. Owner->NewLine(1);
  57. c1out << "W: Unable to stat " << File << endl;
  58. }
  59. if (Flag != FTW_F)
  60. return 0;
  61. // See if it is a .deb
  62. if (strlen(File) < 4)
  63. return 0;
  64. unsigned CurExt = 0;
  65. for (; Owner->Ext[CurExt] != 0; CurExt++)
  66. if (strcmp(File+strlen(File)-strlen(Owner->Ext[CurExt]),
  67. Owner->Ext[CurExt]) == 0)
  68. break;
  69. if (Owner->Ext[CurExt] == 0)
  70. return 0;
  71. /* Process it. If the file is a link then resolve it into an absolute
  72. name.. This works best if the directory components the scanner are
  73. given are not links themselves. */
  74. char Jnk[2];
  75. Owner->OriginalPath = File;
  76. if (Owner->RealPath != 0 && readlink(File,Jnk,sizeof(Jnk)) != -1 &&
  77. realpath(File,Owner->RealPath) != 0)
  78. Owner->DoPackage(Owner->RealPath);
  79. else
  80. Owner->DoPackage(File);
  81. if (_error->empty() == false)
  82. {
  83. // Print any errors or warnings found
  84. string Err;
  85. bool SeenPath = false;
  86. while (_error->empty() == false)
  87. {
  88. Owner->NewLine(1);
  89. bool Type = _error->PopMessage(Err);
  90. if (Type == true)
  91. c1out << "E: " << Err << endl;
  92. else
  93. c1out << "W: " << Err << endl;
  94. if (Err.find(File) != string::npos)
  95. SeenPath = true;
  96. }
  97. if (SeenPath == false)
  98. cerr << "E: Errors apply to file '" << File << "'" << endl;
  99. return 0;
  100. }
  101. return 0;
  102. }
  103. /*}}}*/
  104. // FTWScanner::RecursiveScan - Just scan a directory tree /*{{{*/
  105. // ---------------------------------------------------------------------
  106. /* */
  107. bool FTWScanner::RecursiveScan(string Dir)
  108. {
  109. /* If noprefix is set then jam the scan root in, so we don't generate
  110. link followed paths out of control */
  111. if (InternalPrefix.empty() == true)
  112. {
  113. if (realpath(Dir.c_str(),RealPath) == 0)
  114. return _error->Errno("realpath","Failed to resolve %s",Dir.c_str());
  115. InternalPrefix = RealPath;
  116. }
  117. // Do recursive directory searching
  118. Owner = this;
  119. int Res = ftw(Dir.c_str(),Scanner,30);
  120. // Error treewalking?
  121. if (Res != 0)
  122. {
  123. if (_error->PendingError() == false)
  124. _error->Errno("ftw","Tree walking failed");
  125. return false;
  126. }
  127. return true;
  128. }
  129. /*}}}*/
  130. // FTWScanner::LoadFileList - Load the file list from a file /*{{{*/
  131. // ---------------------------------------------------------------------
  132. /* This is an alternative to using FTW to locate files, it reads the list
  133. of files from another file. */
  134. bool FTWScanner::LoadFileList(string Dir,string File)
  135. {
  136. /* If noprefix is set then jam the scan root in, so we don't generate
  137. link followed paths out of control */
  138. if (InternalPrefix.empty() == true)
  139. {
  140. if (realpath(Dir.c_str(),RealPath) == 0)
  141. return _error->Errno("realpath","Failed to resolve %s",Dir.c_str());
  142. InternalPrefix = RealPath;
  143. }
  144. Owner = this;
  145. FILE *List = fopen(File.c_str(),"r");
  146. if (List == 0)
  147. return _error->Errno("fopen","Failed to open %s",File.c_str());
  148. /* We are a tad tricky here.. We prefix the buffer with the directory
  149. name, that way if we need a full path with just use line.. Sneaky and
  150. fully evil. */
  151. char Line[1000];
  152. char *FileStart;
  153. if (Dir.empty() == true || Dir.end()[-1] != '/')
  154. FileStart = Line + snprintf(Line,sizeof(Line),"%s/",Dir.c_str());
  155. else
  156. FileStart = Line + snprintf(Line,sizeof(Line),"%s",Dir.c_str());
  157. while (fgets(FileStart,sizeof(Line) - (FileStart - Line),List) != 0)
  158. {
  159. char *FileName = _strstrip(FileStart);
  160. if (FileName[0] == 0)
  161. continue;
  162. if (FileName[0] != '/')
  163. {
  164. if (FileName != FileStart)
  165. memmove(FileStart,FileName,strlen(FileStart));
  166. FileName = Line;
  167. }
  168. struct stat St;
  169. int Flag = FTW_F;
  170. if (stat(FileName,&St) != 0)
  171. Flag = FTW_NS;
  172. if (Scanner(FileName,&St,Flag) != 0)
  173. break;
  174. }
  175. fclose(List);
  176. return true;
  177. }
  178. /*}}}*/
  179. // FTWScanner::Delink - Delink symlinks /*{{{*/
  180. // ---------------------------------------------------------------------
  181. /* */
  182. bool FTWScanner::Delink(string &FileName,const char *OriginalPath,
  183. unsigned long &DeLinkBytes,
  184. struct stat &St)
  185. {
  186. // See if this isn't an internaly prefix'd file name.
  187. if (InternalPrefix.empty() == false &&
  188. InternalPrefix.length() < FileName.length() &&
  189. stringcmp(FileName.begin(),FileName.begin() + InternalPrefix.length(),
  190. InternalPrefix.begin(),InternalPrefix.end()) != 0)
  191. {
  192. if (DeLinkLimit != 0 && DeLinkBytes/1024 < DeLinkLimit)
  193. {
  194. // Tidy up the display
  195. if (DeLinkBytes == 0)
  196. cout << endl;
  197. NewLine(1);
  198. c1out << " DeLink " << (OriginalPath + InternalPrefix.length())
  199. << " [" << SizeToStr(St.st_size) << "B]" << endl << flush;
  200. if (NoLinkAct == false)
  201. {
  202. char OldLink[400];
  203. if (readlink(OriginalPath,OldLink,sizeof(OldLink)) == -1)
  204. _error->Errno("readlink","Failed to readlink %s",OriginalPath);
  205. else
  206. {
  207. if (unlink(OriginalPath) != 0)
  208. _error->Errno("unlink","Failed to unlink %s",OriginalPath);
  209. else
  210. {
  211. if (link(FileName.c_str(),OriginalPath) != 0)
  212. {
  213. // Panic! Restore the symlink
  214. symlink(OldLink,OriginalPath);
  215. return _error->Errno("link","*** Failed to link %s to %s",
  216. FileName.c_str(),
  217. OriginalPath);
  218. }
  219. }
  220. }
  221. }
  222. DeLinkBytes += St.st_size;
  223. if (DeLinkBytes/1024 >= DeLinkLimit)
  224. c1out << " DeLink limit of " << SizeToStr(DeLinkBytes) << "B hit." << endl;
  225. }
  226. FileName = OriginalPath;
  227. }
  228. return true;
  229. }
  230. /*}}}*/
  231. // FTWScanner::SetExts - Set extensions to support /*{{{*/
  232. // ---------------------------------------------------------------------
  233. /* */
  234. bool FTWScanner::SetExts(string Vals)
  235. {
  236. delete [] TmpExt;
  237. TmpExt = new char[Vals.length()+1];
  238. strcpy(TmpExt,Vals.c_str());
  239. return TokSplitString(' ',TmpExt,(char **)Ext,sizeof(Ext)/sizeof(Ext[0]));
  240. }
  241. /*}}}*/
  242. // PackagesWriter::PackagesWriter - Constructor /*{{{*/
  243. // ---------------------------------------------------------------------
  244. /* */
  245. PackagesWriter::PackagesWriter(string DB,string Overrides) :
  246. Db(DB),Stats(Db.Stats)
  247. {
  248. Output = stdout;
  249. Ext[0] = ".deb";
  250. Ext[1] = 0;
  251. DeLinkLimit = 0;
  252. // Process the command line options
  253. DoMD5 = _config->FindB("APT::FTPArchive::MD5",true);
  254. DoContents = _config->FindB("APT::FTPArchive::Contents",true);
  255. NoOverride = _config->FindB("APT::FTPArchive::NoOverrideMsg",false);
  256. if (Db.Loaded() == false)
  257. DoContents = false;
  258. // Read the override file
  259. if (Overrides.empty() == false && Over.ReadOverride(Overrides) == false)
  260. return;
  261. else
  262. NoOverride = true;
  263. _error->DumpErrors();
  264. }
  265. /*}}}*/
  266. // PackagesWriter::DoPackage - Process a single package /*{{{*/
  267. // ---------------------------------------------------------------------
  268. /* This method takes a package and gets its control information and
  269. MD5 then writes out a control record with the proper fields rewritten
  270. and the path/size/hash appended. */
  271. bool PackagesWriter::DoPackage(string FileName)
  272. {
  273. // Open the archive
  274. FileFd F(FileName,FileFd::ReadOnly);
  275. if (_error->PendingError() == true)
  276. return false;
  277. // Stat the file for later
  278. struct stat St;
  279. if (fstat(F.Fd(),&St) != 0)
  280. return _error->Errno("fstat","Failed to stat %s",FileName.c_str());
  281. // Pull all the data we need form the DB
  282. string MD5Res;
  283. if (Db.SetFile(FileName,St,&F) == false ||
  284. Db.LoadControl() == false ||
  285. (DoContents == true && Db.LoadContents(true) == false) ||
  286. (DoMD5 == true && Db.GetMD5(MD5Res,false) == false))
  287. return false;
  288. if (Delink(FileName,OriginalPath,Stats.DeLinkBytes,St) == false)
  289. return false;
  290. // Lookup the overide information
  291. pkgTagSection &Tags = Db.Control.Section;
  292. string Package = Tags.FindS("Package");
  293. Override::Item Tmp;
  294. Override::Item *OverItem = Over.GetItem(Package);
  295. if (Package.empty() == true)
  296. return _error->Error("Archive had no package field");
  297. // If we need to do any rewriting of the header do it now..
  298. if (OverItem == 0)
  299. {
  300. if (NoOverride == false)
  301. {
  302. NewLine(1);
  303. c1out << " " << Package << " has no override entry" << endl;
  304. }
  305. OverItem = &Tmp;
  306. Tmp.Section = Tags.FindS("Section");
  307. Tmp.Priority = Tags.FindS("Priority");
  308. }
  309. char Size[40];
  310. sprintf(Size,"%lu",St.st_size);
  311. // Strip the DirStrip prefix from the FileName and add the PathPrefix
  312. string NewFileName;
  313. if (DirStrip.empty() == false &&
  314. FileName.length() > DirStrip.length() &&
  315. stringcmp(FileName.begin(),FileName.begin() + DirStrip.length(),
  316. DirStrip.begin(),DirStrip.end()) == 0)
  317. NewFileName = string(FileName.begin() + DirStrip.length(),FileName.end());
  318. else
  319. NewFileName = FileName;
  320. if (PathPrefix.empty() == false)
  321. NewFileName = flCombine(PathPrefix,NewFileName);
  322. // This lists all the changes to the fields we are going to make.
  323. TFRewriteData Changes[] = {{"Size",Size},
  324. {"MD5sum",MD5Res.c_str()},
  325. {"Filename",NewFileName.c_str()},
  326. {"Section",OverItem->Section.c_str()},
  327. {"Priority",OverItem->Priority.c_str()},
  328. {"Status",0},
  329. {"Optional",0},
  330. {}, // For maintainer
  331. {}, // For Suggests
  332. {}};
  333. unsigned int End = 0;
  334. for (End = 0; Changes[End].Tag != 0; End++);
  335. // Rewrite the maintainer field if necessary
  336. bool MaintFailed;
  337. string NewMaint = OverItem->SwapMaint(Tags.FindS("Maintainer"),MaintFailed);
  338. if (MaintFailed == true)
  339. {
  340. if (NoOverride == false)
  341. {
  342. NewLine(1);
  343. c1out << " " << Package << " maintainer is " <<
  344. Tags.FindS("Maintainer") << " not " <<
  345. OverItem->OldMaint << endl;
  346. }
  347. }
  348. if (NewMaint.empty() == false)
  349. {
  350. Changes[End].Rewrite = NewMaint.c_str();
  351. Changes[End++].Tag = "Maintainer";
  352. }
  353. /* Get rid of the Optional tag. This is an ugly, ugly, ugly hack that
  354. dpkg-scanpackages does.. Well sort of. dpkg-scanpackages just does renaming
  355. but dpkg does this append bit. So we do the append bit, at least that way the
  356. status file and package file will remain similar. There are other transforms
  357. but optional is the only legacy one still in use for some lazy reason. */
  358. string OptionalStr = Tags.FindS("Optional");
  359. if (OptionalStr.empty() == false)
  360. {
  361. if (Tags.FindS("Suggests").empty() == false)
  362. OptionalStr = Tags.FindS("Suggests") + ", " + OptionalStr;
  363. Changes[End].Rewrite = OptionalStr.c_str();
  364. Changes[End++].Tag = "Suggests";
  365. }
  366. // Rewrite and store the fields.
  367. if (TFRewrite(Output,Tags,TFRewritePackageOrder,Changes) == false)
  368. return false;
  369. fprintf(Output,"\n");
  370. return Db.Finish();
  371. }
  372. /*}}}*/
  373. // SourcesWriter::SourcesWriter - Constructor /*{{{*/
  374. // ---------------------------------------------------------------------
  375. /* */
  376. SourcesWriter::SourcesWriter(string BOverrides,string SOverrides)
  377. {
  378. Output = stdout;
  379. Ext[0] = ".dsc";
  380. Ext[1] = 0;
  381. DeLinkLimit = 0;
  382. Buffer = 0;
  383. BufSize = 0;
  384. // Process the command line options
  385. NoOverride = _config->FindB("APT::FTPArchive::NoOverrideMsg",false);
  386. // Read the override file
  387. if (BOverrides.empty() == false && BOver.ReadOverride(BOverrides) == false)
  388. return;
  389. else
  390. NoOverride = true;
  391. if (SOverrides.empty() == false && FileExists(SOverrides) == true &&
  392. SOver.ReadOverride(SOverrides,true) == false)
  393. return;
  394. // _error->DumpErrors();
  395. }
  396. /*}}}*/
  397. // SourcesWriter::DoPackage - Process a single package /*{{{*/
  398. // ---------------------------------------------------------------------
  399. /* */
  400. bool SourcesWriter::DoPackage(string FileName)
  401. {
  402. // Open the archive
  403. FileFd F(FileName,FileFd::ReadOnly);
  404. if (_error->PendingError() == true)
  405. return false;
  406. // Stat the file for later
  407. struct stat St;
  408. if (fstat(F.Fd(),&St) != 0)
  409. return _error->Errno("fstat","Failed to stat %s",FileName.c_str());
  410. if (St.st_size > 128*1024)
  411. return _error->Error("DSC file '%s' is too large!",FileName.c_str());
  412. if (BufSize < (unsigned)St.st_size+1)
  413. {
  414. BufSize = St.st_size+1;
  415. Buffer = (char *)realloc(Buffer,St.st_size+1);
  416. }
  417. if (F.Read(Buffer,St.st_size) == false)
  418. return false;
  419. // Hash the file
  420. char *Start = Buffer;
  421. char *BlkEnd = Buffer + St.st_size;
  422. MD5Summation MD5;
  423. MD5.Add((unsigned char *)Start,BlkEnd - Start);
  424. // Add an extra \n to the end, just in case
  425. *BlkEnd++ = '\n';
  426. /* Remove the PGP trailer. Some .dsc's have this without a blank line
  427. before */
  428. const char *Key = "-----BEGIN PGP SIGNATURE-----";
  429. for (char *MsgEnd = Start; MsgEnd < BlkEnd - strlen(Key) -1; MsgEnd++)
  430. {
  431. if (*MsgEnd == '\n' && strncmp(MsgEnd+1,Key,strlen(Key)) == 0)
  432. {
  433. MsgEnd[1] = '\n';
  434. break;
  435. }
  436. }
  437. /* Read records until we locate the Source record. This neatly skips the
  438. GPG header (which is RFC822 formed) without any trouble. */
  439. pkgTagSection Tags;
  440. do
  441. {
  442. unsigned Pos;
  443. if (Tags.Scan(Start,BlkEnd - Start) == false)
  444. return _error->Error("Could not find a record in the DSC '%s'",FileName.c_str());
  445. if (Tags.Find("Source",Pos) == true)
  446. break;
  447. Start += Tags.size();
  448. }
  449. while (1);
  450. Tags.Trim();
  451. // Lookup the overide information, finding first the best priority.
  452. string BestPrio;
  453. char Buffer[1000];
  454. string Bins = Tags.FindS("Binary");
  455. Override::Item *OverItem = 0;
  456. if (Bins.empty() == false && Bins.length() < sizeof(Buffer))
  457. {
  458. strcpy(Buffer,Bins.c_str());
  459. // Ignore too-long errors.
  460. char *BinList[400];
  461. TokSplitString(',',Buffer,BinList,sizeof(BinList)/sizeof(BinList[0]));
  462. // Look at all the binaries
  463. unsigned char BestPrioV = pkgCache::State::Extra;
  464. for (unsigned I = 0; BinList[I] != 0; I++)
  465. {
  466. Override::Item *Itm = BOver.GetItem(BinList[I]);
  467. if (Itm == 0)
  468. continue;
  469. if (OverItem == 0)
  470. OverItem = Itm;
  471. unsigned char NewPrioV = debListParser::GetPrio(Itm->Priority);
  472. if (NewPrioV < BestPrioV || BestPrio.empty() == true)
  473. {
  474. BestPrioV = NewPrioV;
  475. BestPrio = Itm->Priority;
  476. }
  477. }
  478. }
  479. // If we need to do any rewriting of the header do it now..
  480. Override::Item Tmp;
  481. if (OverItem == 0)
  482. {
  483. if (NoOverride == false)
  484. {
  485. NewLine(1);
  486. c1out << " " << Tags.FindS("Source") << " has no override entry" << endl;
  487. }
  488. OverItem = &Tmp;
  489. }
  490. Override::Item *SOverItem = SOver.GetItem(Tags.FindS("Source"));
  491. if (SOverItem == 0)
  492. {
  493. SOverItem = BOver.GetItem(Tags.FindS("Source"));
  494. if (SOverItem == 0)
  495. SOverItem = OverItem;
  496. }
  497. // Add the dsc to the files hash list
  498. char Files[1000];
  499. snprintf(Files,sizeof(Files),"\n %s %lu %s\n %s",
  500. string(MD5.Result()).c_str(),St.st_size,
  501. flNotDir(FileName).c_str(),
  502. Tags.FindS("Files").c_str());
  503. // Strip the DirStrip prefix from the FileName and add the PathPrefix
  504. string NewFileName;
  505. if (DirStrip.empty() == false &&
  506. FileName.length() > DirStrip.length() &&
  507. stringcmp(OriginalPath,OriginalPath + DirStrip.length(),
  508. DirStrip.begin(),DirStrip.end()) == 0)
  509. NewFileName = string(OriginalPath + DirStrip.length());
  510. else
  511. NewFileName = OriginalPath;
  512. if (PathPrefix.empty() == false)
  513. NewFileName = flCombine(PathPrefix,NewFileName);
  514. string Directory = flNotFile(OriginalPath);
  515. string Package = Tags.FindS("Source");
  516. // Perform the delinking operation over all of the files
  517. string ParseJnk;
  518. const char *C = Files;
  519. for (;isspace(*C); C++);
  520. while (*C != 0)
  521. {
  522. // Parse each of the elements
  523. if (ParseQuoteWord(C,ParseJnk) == false ||
  524. ParseQuoteWord(C,ParseJnk) == false ||
  525. ParseQuoteWord(C,ParseJnk) == false)
  526. return _error->Error("Error parsing file record");
  527. char Jnk[2];
  528. string OriginalPath = Directory + ParseJnk;
  529. if (RealPath != 0 && readlink(OriginalPath.c_str(),Jnk,sizeof(Jnk)) != -1 &&
  530. realpath(OriginalPath.c_str(),RealPath) != 0)
  531. {
  532. string RP = RealPath;
  533. if (Delink(RP,OriginalPath.c_str(),Stats.DeLinkBytes,St) == false)
  534. return false;
  535. }
  536. }
  537. Directory = flNotFile(NewFileName);
  538. if (Directory.length() > 2)
  539. Directory.erase(Directory.end()-1);
  540. // This lists all the changes to the fields we are going to make.
  541. TFRewriteData Changes[] = {{"Source",Package.c_str(),"Package"},
  542. {"Files",Files},
  543. {"Directory",Directory.c_str()},
  544. {"Section",SOverItem->Section.c_str()},
  545. {"Priority",BestPrio.c_str()},
  546. {"Status",0},
  547. {}, // For maintainer
  548. {}};
  549. unsigned int End = 0;
  550. for (End = 0; Changes[End].Tag != 0; End++);
  551. // Rewrite the maintainer field if necessary
  552. bool MaintFailed;
  553. string NewMaint = OverItem->SwapMaint(Tags.FindS("Maintainer"),MaintFailed);
  554. if (MaintFailed == true)
  555. {
  556. if (NoOverride == false)
  557. {
  558. NewLine(1);
  559. c1out << " " << Package << " maintainer is " <<
  560. Tags.FindS("Maintainer") << " not " <<
  561. OverItem->OldMaint << endl;
  562. }
  563. }
  564. if (NewMaint.empty() == false)
  565. {
  566. Changes[End].Rewrite = NewMaint.c_str();
  567. Changes[End++].Tag = "Maintainer";
  568. }
  569. // Rewrite and store the fields.
  570. if (TFRewrite(Output,Tags,TFRewriteSourceOrder,Changes) == false)
  571. return false;
  572. fprintf(Output,"\n");
  573. Stats.Packages++;
  574. return true;
  575. }
  576. /*}}}*/
  577. // ContentsWriter::ContentsWriter - Constructor /*{{{*/
  578. // ---------------------------------------------------------------------
  579. /* */
  580. ContentsWriter::ContentsWriter(string DB) :
  581. Db(DB), Stats(Db.Stats)
  582. {
  583. Ext[0] = ".deb";
  584. Ext[1] = 0;
  585. Output = stdout;
  586. }
  587. /*}}}*/
  588. // ContentsWriter::DoPackage - Process a single package /*{{{*/
  589. // ---------------------------------------------------------------------
  590. /* If Package is the empty string the control record will be parsed to
  591. determine what the package name is. */
  592. bool ContentsWriter::DoPackage(string FileName,string Package)
  593. {
  594. // Open the archive
  595. FileFd F(FileName,FileFd::ReadOnly);
  596. if (_error->PendingError() == true)
  597. return false;
  598. // Stat the file for later
  599. struct stat St;
  600. if (fstat(F.Fd(),&St) != 0)
  601. return _error->Errno("fstat","Failed too stat %s",FileName.c_str());
  602. // Ready the DB
  603. if (Db.SetFile(FileName,St,&F) == false ||
  604. Db.LoadContents(false) == false)
  605. return false;
  606. // Parse the package name
  607. if (Package.empty() == true)
  608. {
  609. if (Db.LoadControl() == false)
  610. return false;
  611. Package = Db.Control.Section.FindS("Package");
  612. }
  613. Db.Contents.Add(Gen,Package);
  614. return Db.Finish();
  615. }
  616. /*}}}*/
  617. // ContentsWriter::ReadFromPkgs - Read from a packages file /*{{{*/
  618. // ---------------------------------------------------------------------
  619. /* */
  620. bool ContentsWriter::ReadFromPkgs(string PkgFile,string PkgCompress)
  621. {
  622. MultiCompress Pkgs(PkgFile,PkgCompress,0,false);
  623. if (_error->PendingError() == true)
  624. return false;
  625. // Open the package file
  626. int CompFd = -1;
  627. int Proc = -1;
  628. if (Pkgs.OpenOld(CompFd,Proc) == false)
  629. return false;
  630. // No auto-close FD
  631. FileFd Fd(CompFd,false);
  632. pkgTagFile Tags(&Fd);
  633. if (_error->PendingError() == true)
  634. {
  635. Pkgs.CloseOld(CompFd,Proc);
  636. return false;
  637. }
  638. // Parse.
  639. pkgTagSection Section;
  640. while (Tags.Step(Section) == true)
  641. {
  642. string File = flCombine(Prefix,Section.FindS("FileName"));
  643. string Package = Section.FindS("Section");
  644. if (Package.empty() == false && Package.end()[-1] != '/')
  645. {
  646. Package += '/';
  647. Package += Section.FindS("Package");
  648. }
  649. else
  650. Package += Section.FindS("Package");
  651. DoPackage(File,Package);
  652. if (_error->empty() == false)
  653. {
  654. _error->Error("Errors apply to file '%s'",File.c_str());
  655. _error->DumpErrors();
  656. }
  657. }
  658. // Tidy the compressor
  659. if (Pkgs.CloseOld(CompFd,Proc) == false)
  660. return false;
  661. return true;
  662. }
  663. /*}}}*/