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