]> git.saurik.com Git - apt.git/blame - ftparchive/writer.cc
* merged lp:~mvo/apt/history
[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);
9d20d8c8 311 LongDescription = _config->FindB("APT::FTPArchive::LongDescription",true);
b2e465d6
AL
312
313 if (Db.Loaded() == false)
314 DoContents = false;
64177f17 315
b2e465d6
AL
316 // Read the override file
317 if (Overrides.empty() == false && Over.ReadOverride(Overrides) == false)
318 return;
319 else
320 NoOverride = true;
64177f17
AL
321
322 if (ExtOverrides.empty() == false)
323 Over.ReadExtraOverride(ExtOverrides);
324
b2e465d6
AL
325 _error->DumpErrors();
326}
98953965
AL
327 /*}}}*/
328// FTWScanner::SetExts - Set extensions to support /*{{{*/
329// ---------------------------------------------------------------------
330/* */
331bool FTWScanner::SetExts(string Vals)
332{
333 ClearPatterns();
334 string::size_type Start = 0;
d6689735 335 while (Start <= Vals.length()-1)
98953965 336 {
d6689735
AL
337 string::size_type Space = Vals.find(' ',Start);
338 string::size_type Length;
339 if (Space == string::npos)
98953965 340 {
d6689735 341 Length = Vals.length()-Start;
98953965 342 }
d6689735
AL
343 else
344 {
345 Length = Space-Start;
346 }
347 AddPattern(string("*") + Vals.substr(Start, Length));
348 Start += Length + 1;
98953965
AL
349 }
350
351 return true;
352}
353
b2e465d6
AL
354 /*}}}*/
355// PackagesWriter::DoPackage - Process a single package /*{{{*/
356// ---------------------------------------------------------------------
357/* This method takes a package and gets its control information and
cde41ae8
MV
358 MD5, SHA1 and SHA256 then writes out a control record with the proper fields
359 rewritten and the path/size/hash appended. */
b2e465d6
AL
360bool PackagesWriter::DoPackage(string FileName)
361{
b2e465d6 362 // Pull all the data we need form the DB
cde41ae8
MV
363 if (Db.GetFileInfo(FileName, true, DoContents, true, DoMD5, DoSHA1, DoSHA256)
364 == false)
365 {
b2e465d6 366 return false;
cde41ae8 367 }
b2e465d6 368
cde41ae8
MV
369 off_t FileSize = Db.GetFileSize();
370 if (Delink(FileName,OriginalPath,Stats.DeLinkBytes,FileSize) == false)
b2e465d6
AL
371 return false;
372
373 // Lookup the overide information
374 pkgTagSection &Tags = Db.Control.Section;
375 string Package = Tags.FindS("Package");
0b41e0e7
MV
376 string Architecture;
377 // if we generate a Packages file for a given arch, we use it to
378 // look for overrides. if we run in "simple" mode without the
379 // "Architecures" variable in the config we use the architecure value
380 // from the deb file
381 if(Arch != "")
382 Architecture = Arch;
383 else
384 Architecture = Tags.FindS("Architecture");
385 auto_ptr<Override::Item> OverItem(Over.GetItem(Package,Architecture));
b2e465d6
AL
386
387 if (Package.empty() == true)
dc738e7a 388 return _error->Error(_("Archive had no package field"));
0b41e0e7 389
b2e465d6 390 // If we need to do any rewriting of the header do it now..
0b41e0e7 391 if (OverItem.get() == 0)
b2e465d6
AL
392 {
393 if (NoOverride == false)
394 {
395 NewLine(1);
dc738e7a 396 ioprintf(c1out, _(" %s has no override entry\n"), Package.c_str());
b2e465d6
AL
397 }
398
0b41e0e7
MV
399 OverItem = auto_ptr<Override::Item>(new Override::Item);
400 OverItem->FieldOverride["Section"] = Tags.FindS("Section");
401 OverItem->Priority = Tags.FindS("Priority");
b2e465d6
AL
402 }
403
404 char Size[40];
cde41ae8 405 sprintf(Size,"%lu", (unsigned long) FileSize);
b2e465d6
AL
406
407 // Strip the DirStrip prefix from the FileName and add the PathPrefix
408 string NewFileName;
409 if (DirStrip.empty() == false &&
410 FileName.length() > DirStrip.length() &&
411 stringcmp(FileName.begin(),FileName.begin() + DirStrip.length(),
412 DirStrip.begin(),DirStrip.end()) == 0)
413 NewFileName = string(FileName.begin() + DirStrip.length(),FileName.end());
414 else
415 NewFileName = FileName;
416 if (PathPrefix.empty() == false)
417 NewFileName = flCombine(PathPrefix,NewFileName);
9d20d8c8
MV
418
419 /* Configuration says we don't want to include the long Description
420 in the package file - instead we want to ship a separated file */
421 string desc;
422 if (LongDescription == false) {
423 desc = Tags.FindS("Description").append("\n");
424 OverItem->FieldOverride["Description"] = desc.substr(0, desc.find('\n')).c_str();
425 }
426
b2e465d6 427 // This lists all the changes to the fields we are going to make.
64177f17 428 // (7 hardcoded + maintainer + suggests + end marker)
9d20d8c8 429 TFRewriteData Changes[6+2+OverItem->FieldOverride.size()+1+1];
64177f17 430
b2e465d6 431 unsigned int End = 0;
64177f17 432 SetTFRewriteData(Changes[End++], "Size", Size);
cde41ae8
MV
433 SetTFRewriteData(Changes[End++], "MD5sum", Db.MD5Res.c_str());
434 SetTFRewriteData(Changes[End++], "SHA1", Db.SHA1Res.c_str());
435 SetTFRewriteData(Changes[End++], "SHA256", Db.SHA256Res.c_str());
64177f17
AL
436 SetTFRewriteData(Changes[End++], "Filename", NewFileName.c_str());
437 SetTFRewriteData(Changes[End++], "Priority", OverItem->Priority.c_str());
438 SetTFRewriteData(Changes[End++], "Status", 0);
439 SetTFRewriteData(Changes[End++], "Optional", 0);
440
9d20d8c8
MV
441 string DescriptionMd5;
442 if (LongDescription == false) {
443 MD5Summation descmd5;
444 descmd5.Add(desc.c_str());
445 DescriptionMd5 = descmd5.Result().Value();
446 SetTFRewriteData(Changes[End++], "Description-md5", DescriptionMd5.c_str());
447 }
448
b2e465d6
AL
449 // Rewrite the maintainer field if necessary
450 bool MaintFailed;
451 string NewMaint = OverItem->SwapMaint(Tags.FindS("Maintainer"),MaintFailed);
452 if (MaintFailed == true)
453 {
454 if (NoOverride == false)
455 {
456 NewLine(1);
dc738e7a
AL
457 ioprintf(c1out, _(" %s maintainer is %s not %s\n"),
458 Package.c_str(), Tags.FindS("Maintainer").c_str(), OverItem->OldMaint.c_str());
b2e465d6
AL
459 }
460 }
461
462 if (NewMaint.empty() == false)
64177f17 463 SetTFRewriteData(Changes[End++], "Maintainer", NewMaint.c_str());
b2e465d6
AL
464
465 /* Get rid of the Optional tag. This is an ugly, ugly, ugly hack that
ca4907db 466 dpkg-scanpackages does. Well sort of. dpkg-scanpackages just does renaming
b2e465d6
AL
467 but dpkg does this append bit. So we do the append bit, at least that way the
468 status file and package file will remain similar. There are other transforms
469 but optional is the only legacy one still in use for some lazy reason. */
470 string OptionalStr = Tags.FindS("Optional");
471 if (OptionalStr.empty() == false)
472 {
473 if (Tags.FindS("Suggests").empty() == false)
474 OptionalStr = Tags.FindS("Suggests") + ", " + OptionalStr;
64177f17 475 SetTFRewriteData(Changes[End++], "Suggests", OptionalStr.c_str());
b2e465d6 476 }
64177f17
AL
477
478 for (map<string,string>::iterator I = OverItem->FieldOverride.begin();
479 I != OverItem->FieldOverride.end(); I++)
480 SetTFRewriteData(Changes[End++],I->first.c_str(),I->second.c_str());
481
482 SetTFRewriteData(Changes[End++], 0, 0);
483
b2e465d6
AL
484 // Rewrite and store the fields.
485 if (TFRewrite(Output,Tags,TFRewritePackageOrder,Changes) == false)
486 return false;
487 fprintf(Output,"\n");
488
489 return Db.Finish();
490}
491 /*}}}*/
492
493// SourcesWriter::SourcesWriter - Constructor /*{{{*/
494// ---------------------------------------------------------------------
495/* */
64177f17
AL
496SourcesWriter::SourcesWriter(string BOverrides,string SOverrides,
497 string ExtOverrides)
b2e465d6
AL
498{
499 Output = stdout;
98953965 500 AddPattern("*.dsc");
b2e465d6
AL
501 DeLinkLimit = 0;
502 Buffer = 0;
503 BufSize = 0;
504
505 // Process the command line options
506 NoOverride = _config->FindB("APT::FTPArchive::NoOverrideMsg",false);
507
508 // Read the override file
509 if (BOverrides.empty() == false && BOver.ReadOverride(BOverrides) == false)
510 return;
511 else
512 NoOverride = true;
64177f17 513
cde41ae8
MV
514 // WTF?? The logic above: if we can't read binary overrides, don't even try
515 // reading source overrides. if we can read binary overrides, then say there
516 // are no overrides. THIS MAKES NO SENSE! -- ajt@d.o, 2006/02/28
517
64177f17
AL
518 if (ExtOverrides.empty() == false)
519 SOver.ReadExtraOverride(ExtOverrides);
b2e465d6 520
64177f17
AL
521 if (SOverrides.empty() == false && FileExists(SOverrides) == true)
522 SOver.ReadOverride(SOverrides,true);
b2e465d6
AL
523}
524 /*}}}*/
525// SourcesWriter::DoPackage - Process a single package /*{{{*/
526// ---------------------------------------------------------------------
527/* */
528bool SourcesWriter::DoPackage(string FileName)
529{
530 // Open the archive
531 FileFd F(FileName,FileFd::ReadOnly);
532 if (_error->PendingError() == true)
533 return false;
534
535 // Stat the file for later
536 struct stat St;
537 if (fstat(F.Fd(),&St) != 0)
538 return _error->Errno("fstat","Failed to stat %s",FileName.c_str());
539
540 if (St.st_size > 128*1024)
541 return _error->Error("DSC file '%s' is too large!",FileName.c_str());
542
543 if (BufSize < (unsigned)St.st_size+1)
544 {
545 BufSize = St.st_size+1;
546 Buffer = (char *)realloc(Buffer,St.st_size+1);
547 }
548
549 if (F.Read(Buffer,St.st_size) == false)
550 return false;
551
552 // Hash the file
553 char *Start = Buffer;
554 char *BlkEnd = Buffer + St.st_size;
555 MD5Summation MD5;
556 MD5.Add((unsigned char *)Start,BlkEnd - Start);
557
558 // Add an extra \n to the end, just in case
559 *BlkEnd++ = '\n';
560
561 /* Remove the PGP trailer. Some .dsc's have this without a blank line
562 before */
563 const char *Key = "-----BEGIN PGP SIGNATURE-----";
564 for (char *MsgEnd = Start; MsgEnd < BlkEnd - strlen(Key) -1; MsgEnd++)
565 {
566 if (*MsgEnd == '\n' && strncmp(MsgEnd+1,Key,strlen(Key)) == 0)
567 {
568 MsgEnd[1] = '\n';
569 break;
570 }
571 }
572
573 /* Read records until we locate the Source record. This neatly skips the
574 GPG header (which is RFC822 formed) without any trouble. */
575 pkgTagSection Tags;
576 do
577 {
578 unsigned Pos;
579 if (Tags.Scan(Start,BlkEnd - Start) == false)
580 return _error->Error("Could not find a record in the DSC '%s'",FileName.c_str());
581 if (Tags.Find("Source",Pos) == true)
582 break;
583 Start += Tags.size();
584 }
585 while (1);
586 Tags.Trim();
587
588 // Lookup the overide information, finding first the best priority.
589 string BestPrio;
b2e465d6 590 string Bins = Tags.FindS("Binary");
5200ec6f 591 char Buffer[Bins.length() + 1];
0b41e0e7 592 auto_ptr<Override::Item> OverItem(0);
5200ec6f 593 if (Bins.empty() == false)
b2e465d6
AL
594 {
595 strcpy(Buffer,Bins.c_str());
596
597 // Ignore too-long errors.
598 char *BinList[400];
599 TokSplitString(',',Buffer,BinList,sizeof(BinList)/sizeof(BinList[0]));
600
601 // Look at all the binaries
602 unsigned char BestPrioV = pkgCache::State::Extra;
603 for (unsigned I = 0; BinList[I] != 0; I++)
604 {
0b41e0e7
MV
605 auto_ptr<Override::Item> Itm(BOver.GetItem(BinList[I]));
606 if (Itm.get() == 0)
b2e465d6 607 continue;
b2e465d6
AL
608
609 unsigned char NewPrioV = debListParser::GetPrio(Itm->Priority);
610 if (NewPrioV < BestPrioV || BestPrio.empty() == true)
611 {
612 BestPrioV = NewPrioV;
613 BestPrio = Itm->Priority;
614 }
7524e348
MV
615
616 if (OverItem.get() == 0)
617 OverItem = Itm;
b2e465d6
AL
618 }
619 }
620
621 // If we need to do any rewriting of the header do it now..
0b41e0e7 622 if (OverItem.get() == 0)
b2e465d6
AL
623 {
624 if (NoOverride == false)
625 {
626 NewLine(1);
dc738e7a 627 ioprintf(c1out, _(" %s has no override entry\n"), Tags.FindS("Source").c_str());
b2e465d6
AL
628 }
629
0b41e0e7 630 OverItem = auto_ptr<Override::Item>(new Override::Item);
b2e465d6
AL
631 }
632
0b41e0e7 633 auto_ptr<Override::Item> SOverItem(SOver.GetItem(Tags.FindS("Source")));
cde41ae8 634 // const auto_ptr<Override::Item> autoSOverItem(SOverItem);
0b41e0e7 635 if (SOverItem.get() == 0)
b2e465d6 636 {
cde41ae8 637 ioprintf(c1out, _(" %s has no source override entry\n"), Tags.FindS("Source").c_str());
0b41e0e7
MV
638 SOverItem = auto_ptr<Override::Item>(BOver.GetItem(Tags.FindS("Source")));
639 if (SOverItem.get() == 0)
640 {
cde41ae8 641 ioprintf(c1out, _(" %s has no binary override entry either\n"), Tags.FindS("Source").c_str());
0b41e0e7
MV
642 SOverItem = auto_ptr<Override::Item>(new Override::Item);
643 *SOverItem = *OverItem;
644 }
b2e465d6
AL
645 }
646
647 // Add the dsc to the files hash list
648 char Files[1000];
649 snprintf(Files,sizeof(Files),"\n %s %lu %s\n %s",
650 string(MD5.Result()).c_str(),St.st_size,
651 flNotDir(FileName).c_str(),
652 Tags.FindS("Files").c_str());
653
654 // Strip the DirStrip prefix from the FileName and add the PathPrefix
655 string NewFileName;
656 if (DirStrip.empty() == false &&
657 FileName.length() > DirStrip.length() &&
8c58f506 658 stringcmp(DirStrip,OriginalPath,OriginalPath + DirStrip.length()) == 0)
b2e465d6
AL
659 NewFileName = string(OriginalPath + DirStrip.length());
660 else
661 NewFileName = OriginalPath;
662 if (PathPrefix.empty() == false)
663 NewFileName = flCombine(PathPrefix,NewFileName);
171c45bc 664
b2e465d6
AL
665 string Directory = flNotFile(OriginalPath);
666 string Package = Tags.FindS("Source");
171c45bc 667
b2e465d6
AL
668 // Perform the delinking operation over all of the files
669 string ParseJnk;
670 const char *C = Files;
671 for (;isspace(*C); C++);
672 while (*C != 0)
673 {
674 // Parse each of the elements
675 if (ParseQuoteWord(C,ParseJnk) == false ||
676 ParseQuoteWord(C,ParseJnk) == false ||
677 ParseQuoteWord(C,ParseJnk) == false)
678 return _error->Error("Error parsing file record");
679
680 char Jnk[2];
681 string OriginalPath = Directory + ParseJnk;
682 if (RealPath != 0 && readlink(OriginalPath.c_str(),Jnk,sizeof(Jnk)) != -1 &&
683 realpath(OriginalPath.c_str(),RealPath) != 0)
684 {
685 string RP = RealPath;
cde41ae8 686 if (Delink(RP,OriginalPath.c_str(),Stats.DeLinkBytes,St.st_size) == false)
b2e465d6
AL
687 return false;
688 }
689 }
690
691 Directory = flNotFile(NewFileName);
692 if (Directory.length() > 2)
693 Directory.erase(Directory.end()-1);
171c45bc 694
b2e465d6 695 // This lists all the changes to the fields we are going to make.
64177f17
AL
696 // (5 hardcoded + maintainer + end marker)
697 TFRewriteData Changes[5+1+SOverItem->FieldOverride.size()+1];
698
b2e465d6 699 unsigned int End = 0;
64177f17
AL
700 SetTFRewriteData(Changes[End++],"Source",Package.c_str(),"Package");
701 SetTFRewriteData(Changes[End++],"Files",Files);
171c45bc
AL
702 if (Directory != "./")
703 SetTFRewriteData(Changes[End++],"Directory",Directory.c_str());
64177f17
AL
704 SetTFRewriteData(Changes[End++],"Priority",BestPrio.c_str());
705 SetTFRewriteData(Changes[End++],"Status",0);
b2e465d6
AL
706
707 // Rewrite the maintainer field if necessary
708 bool MaintFailed;
709 string NewMaint = OverItem->SwapMaint(Tags.FindS("Maintainer"),MaintFailed);
710 if (MaintFailed == true)
711 {
712 if (NoOverride == false)
713 {
714 NewLine(1);
dc738e7a
AL
715 ioprintf(c1out, _(" %s maintainer is %s not %s\n"), Package.c_str(),
716 Tags.FindS("Maintainer").c_str(), OverItem->OldMaint.c_str());
b2e465d6
AL
717 }
718 }
719 if (NewMaint.empty() == false)
64177f17
AL
720 SetTFRewriteData(Changes[End++], "Maintainer", NewMaint.c_str());
721
722 for (map<string,string>::iterator I = SOverItem->FieldOverride.begin();
723 I != SOverItem->FieldOverride.end(); I++)
724 SetTFRewriteData(Changes[End++],I->first.c_str(),I->second.c_str());
725
726 SetTFRewriteData(Changes[End++], 0, 0);
b2e465d6
AL
727
728 // Rewrite and store the fields.
729 if (TFRewrite(Output,Tags,TFRewriteSourceOrder,Changes) == false)
730 return false;
731 fprintf(Output,"\n");
732
733 Stats.Packages++;
734
735 return true;
736}
737 /*}}}*/
738
739// ContentsWriter::ContentsWriter - Constructor /*{{{*/
740// ---------------------------------------------------------------------
741/* */
742ContentsWriter::ContentsWriter(string DB) :
743 Db(DB), Stats(Db.Stats)
744
745{
98953965 746 AddPattern("*.deb");
b2e465d6
AL
747 Output = stdout;
748}
749 /*}}}*/
750// ContentsWriter::DoPackage - Process a single package /*{{{*/
751// ---------------------------------------------------------------------
752/* If Package is the empty string the control record will be parsed to
753 determine what the package name is. */
754bool ContentsWriter::DoPackage(string FileName,string Package)
755{
cde41ae8
MV
756 if (!Db.GetFileInfo(FileName, Package.empty(), true, false, false, false, false))
757 {
b2e465d6 758 return false;
cde41ae8 759 }
b2e465d6
AL
760
761 // Parse the package name
762 if (Package.empty() == true)
763 {
b2e465d6
AL
764 Package = Db.Control.Section.FindS("Package");
765 }
766
767 Db.Contents.Add(Gen,Package);
768
769 return Db.Finish();
770}
771 /*}}}*/
772// ContentsWriter::ReadFromPkgs - Read from a packages file /*{{{*/
773// ---------------------------------------------------------------------
774/* */
775bool ContentsWriter::ReadFromPkgs(string PkgFile,string PkgCompress)
776{
777 MultiCompress Pkgs(PkgFile,PkgCompress,0,false);
778 if (_error->PendingError() == true)
779 return false;
780
781 // Open the package file
782 int CompFd = -1;
b3d44315 783 pid_t Proc = -1;
b2e465d6
AL
784 if (Pkgs.OpenOld(CompFd,Proc) == false)
785 return false;
786
787 // No auto-close FD
788 FileFd Fd(CompFd,false);
789 pkgTagFile Tags(&Fd);
790 if (_error->PendingError() == true)
791 {
792 Pkgs.CloseOld(CompFd,Proc);
793 return false;
794 }
795
796 // Parse.
797 pkgTagSection Section;
798 while (Tags.Step(Section) == true)
799 {
800 string File = flCombine(Prefix,Section.FindS("FileName"));
801 string Package = Section.FindS("Section");
802 if (Package.empty() == false && Package.end()[-1] != '/')
803 {
804 Package += '/';
805 Package += Section.FindS("Package");
806 }
807 else
808 Package += Section.FindS("Package");
809
810 DoPackage(File,Package);
811 if (_error->empty() == false)
812 {
813 _error->Error("Errors apply to file '%s'",File.c_str());
814 _error->DumpErrors();
815 }
816 }
817
818 // Tidy the compressor
819 if (Pkgs.CloseOld(CompFd,Proc) == false)
820 return false;
821
822 return true;
823}
98953965 824
b2e465d6 825 /*}}}*/
98953965
AL
826
827// ReleaseWriter::ReleaseWriter - Constructor /*{{{*/
828// ---------------------------------------------------------------------
829/* */
830ReleaseWriter::ReleaseWriter(string DB)
831{
832 AddPattern("Packages");
833 AddPattern("Packages.gz");
187492a6 834 AddPattern("Packages.bz2");
e85b4cd5 835 AddPattern("Packages.lzma");
187492a6
AL
836 AddPattern("Sources");
837 AddPattern("Sources.gz");
838 AddPattern("Sources.bz2");
e85b4cd5 839 AddPattern("Sources.lzma");
187492a6
AL
840 AddPattern("Release");
841 AddPattern("md5sum.txt");
842
98953965
AL
843 Output = stdout;
844 time_t now = time(NULL);
845 char datestr[128];
846 if (strftime(datestr, sizeof(datestr), "%a, %d %b %Y %H:%M:%S UTC",
847 gmtime(&now)) == 0)
848 {
849 datestr[0] = '\0';
850 }
851
852 map<string,string> Fields;
853 Fields["Origin"] = "";
854 Fields["Label"] = "";
855 Fields["Suite"] = "";
856 Fields["Version"] = "";
857 Fields["Codename"] = "";
858 Fields["Date"] = datestr;
859 Fields["Architectures"] = "";
860 Fields["Components"] = "";
861 Fields["Description"] = "";
862
863 for(map<string,string>::const_iterator I = Fields.begin();
864 I != Fields.end();
865 ++I)
866 {
867 string Config = string("APT::FTPArchive::Release::") + (*I).first;
868 string Value = _config->Find(Config, (*I).second.c_str());
869 if (Value == "")
870 continue;
871
872 fprintf(Output, "%s: %s\n", (*I).first.c_str(), Value.c_str());
873 }
98953965
AL
874}
875 /*}}}*/
876// ReleaseWriter::DoPackage - Process a single package /*{{{*/
877// ---------------------------------------------------------------------
878bool ReleaseWriter::DoPackage(string FileName)
879{
880 // Strip the DirStrip prefix from the FileName and add the PathPrefix
881 string NewFileName;
882 if (DirStrip.empty() == false &&
883 FileName.length() > DirStrip.length() &&
884 stringcmp(FileName.begin(),FileName.begin() + DirStrip.length(),
885 DirStrip.begin(),DirStrip.end()) == 0)
c0eb6bc6 886 {
98953965 887 NewFileName = string(FileName.begin() + DirStrip.length(),FileName.end());
c0eb6bc6 888 while (NewFileName[0] == '/')
9202409d 889 NewFileName = string(NewFileName.begin() + 1,NewFileName.end());
c0eb6bc6 890 }
98953965
AL
891 else
892 NewFileName = FileName;
c0eb6bc6 893
98953965
AL
894 if (PathPrefix.empty() == false)
895 NewFileName = flCombine(PathPrefix,NewFileName);
896
897 FileFd fd(FileName, FileFd::ReadOnly);
898
899 if (!fd.IsOpen())
900 {
901 return false;
902 }
903
c0eb6bc6 904 CheckSums[NewFileName].size = fd.Size();
f7291f62 905
98953965
AL
906 MD5Summation MD5;
907 MD5.AddFD(fd.Fd(), fd.Size());
c0eb6bc6 908 CheckSums[NewFileName].MD5 = MD5.Result();
98953965 909
f7291f62
AL
910 fd.Seek(0);
911 SHA1Summation SHA1;
912 SHA1.AddFD(fd.Fd(), fd.Size());
c0eb6bc6 913 CheckSums[NewFileName].SHA1 = SHA1.Result();
98953965 914
cde41ae8
MV
915 fd.Seek(0);
916 SHA256Summation SHA256;
917 SHA256.AddFD(fd.Fd(), fd.Size());
918 CheckSums[NewFileName].SHA256 = SHA256.Result();
919
98953965
AL
920 fd.Close();
921
922 return true;
923}
f7291f62
AL
924
925 /*}}}*/
926// ReleaseWriter::Finish - Output the checksums /*{{{*/
927// ---------------------------------------------------------------------
928void ReleaseWriter::Finish()
929{
930 fprintf(Output, "MD5Sum:\n");
931 for(map<string,struct CheckSum>::iterator I = CheckSums.begin();
932 I != CheckSums.end();
933 ++I)
934 {
935 fprintf(Output, " %s %16ld %s\n",
936 (*I).second.MD5.c_str(),
937 (*I).second.size,
938 (*I).first.c_str());
939 }
940
941 fprintf(Output, "SHA1:\n");
942 for(map<string,struct CheckSum>::iterator I = CheckSums.begin();
943 I != CheckSums.end();
944 ++I)
945 {
946 fprintf(Output, " %s %16ld %s\n",
947 (*I).second.SHA1.c_str(),
948 (*I).second.size,
949 (*I).first.c_str());
950 }
cde41ae8
MV
951
952 fprintf(Output, "SHA256:\n");
953 for(map<string,struct CheckSum>::iterator I = CheckSums.begin();
954 I != CheckSums.end();
955 ++I)
956 {
957 fprintf(Output, " %s %16ld %s\n",
958 (*I).second.SHA256.c_str(),
959 (*I).second.size,
960 (*I).first.c_str());
961 }
f7291f62
AL
962}
963