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