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