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