// -*- mode: cpp; mode: fold -*-
// Description /*{{{*/
-// $Id: writer.cc,v 1.3 2001/05/29 04:08:09 jgg Exp $
+// $Id: writer.cc,v 1.11 2004/01/02 21:48:13 mdz Exp $
/* ######################################################################
Writer
#include "writer.h"
+#include <apti18n.h>
#include <apt-pkg/strutl.h>
#include <apt-pkg/error.h>
#include <apt-pkg/configuration.h>
#include <apt-pkg/md5.h>
+#include <apt-pkg/sha1.h>
#include <apt-pkg/deblistparser.h>
#include <sys/types.h>
#include <unistd.h>
+#include <ctime>
#include <ftw.h>
+#include <fnmatch.h>
#include <iostream>
#include "cachedb.h"
using namespace std;
FTWScanner *FTWScanner::Owner;
+// SetTFRewriteData - Helper for setting rewrite lists /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+inline void SetTFRewriteData(struct TFRewriteData &tfrd,
+ const char *tag,
+ const char *rewrite,
+ const char *newtag = 0)
+{
+ tfrd.Tag = tag;
+ tfrd.Rewrite = rewrite;
+ tfrd.NewTag = newtag;
+}
+ /*}}}*/
+
// FTWScanner::FTWScanner - Constructor /*{{{*/
// ---------------------------------------------------------------------
/* */
{
ErrorPrinted = false;
NoLinkAct = !_config->FindB("APT::FTPArchive::DeLinkAct",true);
- TmpExt = 0;
- Ext[0] = 0;
RealPath = 0;
long PMax = pathconf(".",_PC_PATH_MAX);
if (PMax > 0)
if (Flag == FTW_DNR)
{
Owner->NewLine(1);
- c1out << "W: Unable to read directory " << File << endl;
+ ioprintf(c1out, _("W: Unable to read directory %s\n"), File);
}
if (Flag == FTW_NS)
{
Owner->NewLine(1);
- c1out << "W: Unable to stat " << File << endl;
+ ioprintf(c1out, _("W: Unable to stat %s\n"), File);
}
if (Flag != FTW_F)
return 0;
- // See if it is a .deb
- if (strlen(File) < 4)
- return 0;
-
- unsigned CurExt = 0;
- for (; Owner->Ext[CurExt] != 0; CurExt++)
- if (strcmp(File+strlen(File)-strlen(Owner->Ext[CurExt]),
- Owner->Ext[CurExt]) == 0)
- break;
- if (Owner->Ext[CurExt] == 0)
+ const char *LastComponent = strrchr(File, '/');
+ if (LastComponent == NULL)
+ LastComponent = File;
+ else
+ LastComponent++;
+
+ vector<string>::iterator I;
+ for(I = Owner->Patterns.begin(); I != Owner->Patterns.end(); ++I)
+ {
+ if (fnmatch((*I).c_str(), LastComponent, 0) == 0)
+ break;
+ }
+ if (I == Owner->Patterns.end())
return 0;
/* Process it. If the file is a link then resolve it into an absolute
bool Type = _error->PopMessage(Err);
if (Type == true)
- c1out << "E: " << Err << endl;
+ cerr << _("E: ") << Err << endl;
else
- c1out << "W: " << Err << endl;
+ cerr << _("W: ") << Err << endl;
if (Err.find(File) != string::npos)
SeenPath = true;
}
if (SeenPath == false)
- cerr << "E: Errors apply to file '" << File << "'" << endl;
+ cerr << _("E: Errors apply to file ") << "'" << File << "'" << endl;
return 0;
}
if (InternalPrefix.empty() == true)
{
if (realpath(Dir.c_str(),RealPath) == 0)
- return _error->Errno("realpath","Failed to resolve %s",Dir.c_str());
+ return _error->Errno("realpath",_("Failed to resolve %s"),Dir.c_str());
InternalPrefix = RealPath;
}
if (Res != 0)
{
if (_error->PendingError() == false)
- _error->Errno("ftw","Tree walking failed");
+ _error->Errno("ftw",_("Tree walking failed"));
return false;
}
if (InternalPrefix.empty() == true)
{
if (realpath(Dir.c_str(),RealPath) == 0)
- return _error->Errno("realpath","Failed to resolve %s",Dir.c_str());
+ return _error->Errno("realpath",_("Failed to resolve %s"),Dir.c_str());
InternalPrefix = RealPath;
}
Owner = this;
FILE *List = fopen(File.c_str(),"r");
if (List == 0)
- return _error->Errno("fopen","Failed to open %s",File.c_str());
+ return _error->Errno("fopen",_("Failed to open %s"),File.c_str());
/* We are a tad tricky here.. We prefix the buffer with the directory
name, that way if we need a full path with just use line.. Sneaky and
cout << endl;
NewLine(1);
- c1out << " DeLink " << (OriginalPath + InternalPrefix.length())
- << " [" << SizeToStr(St.st_size) << "B]" << endl << flush;
+ ioprintf(c1out, _(" DeLink %s [%s]\n"), (OriginalPath + InternalPrefix.length()),
+ SizeToStr(St.st_size).c_str());
+ c1out << flush;
if (NoLinkAct == false)
{
char OldLink[400];
if (readlink(OriginalPath,OldLink,sizeof(OldLink)) == -1)
- _error->Errno("readlink","Failed to readlink %s",OriginalPath);
+ _error->Errno("readlink",_("Failed to readlink %s"),OriginalPath);
else
{
if (unlink(OriginalPath) != 0)
- _error->Errno("unlink","Failed to unlink %s",OriginalPath);
+ _error->Errno("unlink",_("Failed to unlink %s"),OriginalPath);
else
{
if (link(FileName.c_str(),OriginalPath) != 0)
{
// Panic! Restore the symlink
symlink(OldLink,OriginalPath);
- return _error->Errno("link","*** Failed to link %s to %s",
+ return _error->Errno("link",_("*** Failed to link %s to %s"),
FileName.c_str(),
OriginalPath);
}
DeLinkBytes += St.st_size;
if (DeLinkBytes/1024 >= DeLinkLimit)
- c1out << " DeLink limit of " << SizeToStr(DeLinkBytes) << "B hit." << endl;
+ ioprintf(c1out, _(" DeLink limit of %sB hit.\n"), SizeToStr(DeLinkBytes).c_str());
}
FileName = OriginalPath;
return true;
}
/*}}}*/
-// FTWScanner::SetExts - Set extensions to support /*{{{*/
-// ---------------------------------------------------------------------
-/* */
-bool FTWScanner::SetExts(string Vals)
-{
- delete [] TmpExt;
- TmpExt = new char[Vals.length()+1];
- strcpy(TmpExt,Vals.c_str());
- return TokSplitString(' ',TmpExt,(char **)Ext,sizeof(Ext)/sizeof(Ext[0]));
-}
- /*}}}*/
// PackagesWriter::PackagesWriter - Constructor /*{{{*/
// ---------------------------------------------------------------------
/* */
-PackagesWriter::PackagesWriter(string DB,string Overrides) :
+PackagesWriter::PackagesWriter(string DB,string Overrides,string ExtOverrides) :
Db(DB),Stats(Db.Stats)
{
Output = stdout;
- Ext[0] = ".deb";
- Ext[1] = 0;
+ AddPattern("*.deb");
DeLinkLimit = 0;
// Process the command line options
if (Db.Loaded() == false)
DoContents = false;
-
+
// Read the override file
if (Overrides.empty() == false && Over.ReadOverride(Overrides) == false)
return;
else
NoOverride = true;
+
+ if (ExtOverrides.empty() == false)
+ Over.ReadExtraOverride(ExtOverrides);
+
_error->DumpErrors();
}
+ /*}}}*/
+// FTWScanner::SetExts - Set extensions to support /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool FTWScanner::SetExts(string Vals)
+{
+ ClearPatterns();
+ string::size_type Start = 0;
+ for(string::size_type space = Vals.find(' ');
+ space != string::npos;
+ space = Vals.find(' ', space))
+ {
+ if (space > 0)
+ {
+ AddPattern(string("*") + string(Start, space-1));
+ Start = space + 1;
+ }
+ }
+
+ return true;
+}
+
/*}}}*/
// PackagesWriter::DoPackage - Process a single package /*{{{*/
// ---------------------------------------------------------------------
// Stat the file for later
struct stat St;
if (fstat(F.Fd(),&St) != 0)
- return _error->Errno("fstat","Failed to stat %s",FileName.c_str());
+ return _error->Errno("fstat",_("Failed to stat %s"),FileName.c_str());
// Pull all the data we need form the DB
string MD5Res;
Override::Item *OverItem = Over.GetItem(Package);
if (Package.empty() == true)
- return _error->Error("Archive had no package field");
+ return _error->Error(_("Archive had no package field"));
// If we need to do any rewriting of the header do it now..
if (OverItem == 0)
if (NoOverride == false)
{
NewLine(1);
- c1out << " " << Package << " has no override entry" << endl;
+ ioprintf(c1out, _(" %s has no override entry\n"), Package.c_str());
}
OverItem = &Tmp;
- Tmp.Section = Tags.FindS("Section");
+ Tmp.FieldOverride["Section"] = Tags.FindS("Section");
Tmp.Priority = Tags.FindS("Priority");
}
NewFileName = flCombine(PathPrefix,NewFileName);
// This lists all the changes to the fields we are going to make.
- TFRewriteData Changes[] = {{"Size",Size},
- {"MD5sum",MD5Res.c_str()},
- {"Filename",NewFileName.c_str()},
- {"Section",OverItem->Section.c_str()},
- {"Priority",OverItem->Priority.c_str()},
- {"Status",0},
- {"Optional",0},
- {}, // For maintainer
- {}, // For Suggests
- {}};
+ // (7 hardcoded + maintainer + suggests + end marker)
+ TFRewriteData Changes[6+2+OverItem->FieldOverride.size()+1];
+
unsigned int End = 0;
- for (End = 0; Changes[End].Tag != 0; End++);
-
+ SetTFRewriteData(Changes[End++], "Size", Size);
+ SetTFRewriteData(Changes[End++], "MD5sum", MD5Res.c_str());
+ SetTFRewriteData(Changes[End++], "Filename", NewFileName.c_str());
+ SetTFRewriteData(Changes[End++], "Priority", OverItem->Priority.c_str());
+ SetTFRewriteData(Changes[End++], "Status", 0);
+ SetTFRewriteData(Changes[End++], "Optional", 0);
+
// Rewrite the maintainer field if necessary
bool MaintFailed;
string NewMaint = OverItem->SwapMaint(Tags.FindS("Maintainer"),MaintFailed);
if (NoOverride == false)
{
NewLine(1);
- c1out << " " << Package << " maintainer is " <<
- Tags.FindS("Maintainer") << " not " <<
- OverItem->OldMaint << endl;
+ ioprintf(c1out, _(" %s maintainer is %s not %s\n"),
+ Package.c_str(), Tags.FindS("Maintainer").c_str(), OverItem->OldMaint.c_str());
}
}
if (NewMaint.empty() == false)
- {
- Changes[End].Rewrite = NewMaint.c_str();
- Changes[End++].Tag = "Maintainer";
- }
+ SetTFRewriteData(Changes[End++], "Maintainer", NewMaint.c_str());
/* Get rid of the Optional tag. This is an ugly, ugly, ugly hack that
dpkg-scanpackages does.. Well sort of. dpkg-scanpackages just does renaming
{
if (Tags.FindS("Suggests").empty() == false)
OptionalStr = Tags.FindS("Suggests") + ", " + OptionalStr;
- Changes[End].Rewrite = OptionalStr.c_str();
- Changes[End++].Tag = "Suggests";
+ SetTFRewriteData(Changes[End++], "Suggests", OptionalStr.c_str());
}
-
+
+ for (map<string,string>::iterator I = OverItem->FieldOverride.begin();
+ I != OverItem->FieldOverride.end(); I++)
+ SetTFRewriteData(Changes[End++],I->first.c_str(),I->second.c_str());
+
+ SetTFRewriteData(Changes[End++], 0, 0);
+
// Rewrite and store the fields.
if (TFRewrite(Output,Tags,TFRewritePackageOrder,Changes) == false)
return false;
// SourcesWriter::SourcesWriter - Constructor /*{{{*/
// ---------------------------------------------------------------------
/* */
-SourcesWriter::SourcesWriter(string BOverrides,string SOverrides)
+SourcesWriter::SourcesWriter(string BOverrides,string SOverrides,
+ string ExtOverrides)
{
Output = stdout;
- Ext[0] = ".dsc";
- Ext[1] = 0;
+ AddPattern("*.dsc");
DeLinkLimit = 0;
Buffer = 0;
BufSize = 0;
return;
else
NoOverride = true;
+
+ if (ExtOverrides.empty() == false)
+ SOver.ReadExtraOverride(ExtOverrides);
- if (SOverrides.empty() == false && FileExists(SOverrides) == true &&
- SOver.ReadOverride(SOverrides,true) == false)
- return;
-// _error->DumpErrors();
+ if (SOverrides.empty() == false && FileExists(SOverrides) == true)
+ SOver.ReadOverride(SOverrides,true);
}
/*}}}*/
// SourcesWriter::DoPackage - Process a single package /*{{{*/
if (NoOverride == false)
{
NewLine(1);
- c1out << " " << Tags.FindS("Source") << " has no override entry" << endl;
+ ioprintf(c1out, _(" %s has no override entry\n"), Tags.FindS("Source").c_str());
}
OverItem = &Tmp;
NewFileName = OriginalPath;
if (PathPrefix.empty() == false)
NewFileName = flCombine(PathPrefix,NewFileName);
-
+
string Directory = flNotFile(OriginalPath);
string Package = Tags.FindS("Source");
-
+
// Perform the delinking operation over all of the files
string ParseJnk;
const char *C = Files;
Directory = flNotFile(NewFileName);
if (Directory.length() > 2)
Directory.erase(Directory.end()-1);
-
+
// This lists all the changes to the fields we are going to make.
- TFRewriteData Changes[] = {{"Source",Package.c_str(),"Package"},
- {"Files",Files},
- {"Directory",Directory.c_str()},
- {"Section",SOverItem->Section.c_str()},
- {"Priority",BestPrio.c_str()},
- {"Status",0},
- {}, // For maintainer
- {}};
+ // (5 hardcoded + maintainer + end marker)
+ TFRewriteData Changes[5+1+SOverItem->FieldOverride.size()+1];
+
unsigned int End = 0;
- for (End = 0; Changes[End].Tag != 0; End++);
+ SetTFRewriteData(Changes[End++],"Source",Package.c_str(),"Package");
+ SetTFRewriteData(Changes[End++],"Files",Files);
+ if (Directory != "./")
+ SetTFRewriteData(Changes[End++],"Directory",Directory.c_str());
+ SetTFRewriteData(Changes[End++],"Priority",BestPrio.c_str());
+ SetTFRewriteData(Changes[End++],"Status",0);
// Rewrite the maintainer field if necessary
bool MaintFailed;
if (NoOverride == false)
{
NewLine(1);
- c1out << " " << Package << " maintainer is " <<
- Tags.FindS("Maintainer") << " not " <<
- OverItem->OldMaint << endl;
+ ioprintf(c1out, _(" %s maintainer is %s not %s\n"), Package.c_str(),
+ Tags.FindS("Maintainer").c_str(), OverItem->OldMaint.c_str());
}
}
if (NewMaint.empty() == false)
- {
- Changes[End].Rewrite = NewMaint.c_str();
- Changes[End++].Tag = "Maintainer";
- }
+ SetTFRewriteData(Changes[End++], "Maintainer", NewMaint.c_str());
+
+ for (map<string,string>::iterator I = SOverItem->FieldOverride.begin();
+ I != SOverItem->FieldOverride.end(); I++)
+ SetTFRewriteData(Changes[End++],I->first.c_str(),I->second.c_str());
+
+ SetTFRewriteData(Changes[End++], 0, 0);
// Rewrite and store the fields.
if (TFRewrite(Output,Tags,TFRewriteSourceOrder,Changes) == false)
Db(DB), Stats(Db.Stats)
{
- Ext[0] = ".deb";
- Ext[1] = 0;
+ AddPattern("*.deb");
Output = stdout;
}
/*}}}*/
return true;
}
+
+ /*}}}*/
+
+// ReleaseWriter::ReleaseWriter - Constructor /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+ReleaseWriter::ReleaseWriter(string DB)
+{
+ AddPattern("Packages");
+ AddPattern("Packages.gz");
+ AddPattern("Packages.bz2");
+ AddPattern("Sources");
+ AddPattern("Sources.gz");
+ AddPattern("Sources.bz2");
+ AddPattern("Release");
+ AddPattern("md5sum.txt");
+
+ Output = stdout;
+ time_t now = time(NULL);
+ char datestr[128];
+ if (strftime(datestr, sizeof(datestr), "%a, %d %b %Y %H:%M:%S UTC",
+ gmtime(&now)) == 0)
+ {
+ datestr[0] = '\0';
+ }
+
+ map<string,string> Fields;
+ Fields["Origin"] = "";
+ Fields["Label"] = "";
+ Fields["Suite"] = "";
+ Fields["Version"] = "";
+ Fields["Codename"] = "";
+ Fields["Date"] = datestr;
+ Fields["Architectures"] = "";
+ Fields["Components"] = "";
+ Fields["Description"] = "";
+
+ for(map<string,string>::const_iterator I = Fields.begin();
+ I != Fields.end();
+ ++I)
+ {
+ string Config = string("APT::FTPArchive::Release::") + (*I).first;
+ string Value = _config->Find(Config, (*I).second.c_str());
+ if (Value == "")
+ continue;
+
+ fprintf(Output, "%s: %s\n", (*I).first.c_str(), Value.c_str());
+ }
+}
+ /*}}}*/
+// ReleaseWriter::DoPackage - Process a single package /*{{{*/
+// ---------------------------------------------------------------------
+bool ReleaseWriter::DoPackage(string FileName)
+{
+ // Strip the DirStrip prefix from the FileName and add the PathPrefix
+ string NewFileName;
+ if (DirStrip.empty() == false &&
+ FileName.length() > DirStrip.length() &&
+ stringcmp(FileName.begin(),FileName.begin() + DirStrip.length(),
+ DirStrip.begin(),DirStrip.end()) == 0)
+ {
+ NewFileName = string(FileName.begin() + DirStrip.length(),FileName.end());
+ while (NewFileName[0] == '/')
+ NewFileName = string(FileName.begin() + 1,FileName.end());
+ }
+ else
+ NewFileName = FileName;
+
+ if (PathPrefix.empty() == false)
+ NewFileName = flCombine(PathPrefix,NewFileName);
+
+ FileFd fd(FileName, FileFd::ReadOnly);
+
+ if (!fd.IsOpen())
+ {
+ return false;
+ }
+
+ CheckSums[NewFileName].size = fd.Size();
+
+ MD5Summation MD5;
+ MD5.AddFD(fd.Fd(), fd.Size());
+ CheckSums[NewFileName].MD5 = MD5.Result();
+
+ fd.Seek(0);
+ SHA1Summation SHA1;
+ SHA1.AddFD(fd.Fd(), fd.Size());
+ CheckSums[NewFileName].SHA1 = SHA1.Result();
+
+ fd.Close();
+
+ return true;
+}
+
/*}}}*/
+// ReleaseWriter::Finish - Output the checksums /*{{{*/
+// ---------------------------------------------------------------------
+void ReleaseWriter::Finish()
+{
+ fprintf(Output, "MD5Sum:\n");
+ for(map<string,struct CheckSum>::iterator I = CheckSums.begin();
+ I != CheckSums.end();
+ ++I)
+ {
+ fprintf(Output, " %s %16ld %s\n",
+ (*I).second.MD5.c_str(),
+ (*I).second.size,
+ (*I).first.c_str());
+ }
+
+ fprintf(Output, "SHA1:\n");
+ for(map<string,struct CheckSum>::iterator I = CheckSums.begin();
+ I != CheckSums.end();
+ ++I)
+ {
+ fprintf(Output, " %s %16ld %s\n",
+ (*I).second.SHA1.c_str(),
+ (*I).second.size,
+ (*I).first.c_str());
+ }
+}
+