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