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