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