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