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