Procházet zdrojové kódy

rewrite all TFRewrite instances to use the new pkgTagSection::Write

While it is mostly busywork to rewrite all instances it actually fixes
bugs as the data storage used by the new method is std::string rather
than a char*, the later mostly created by c_str() from a std::string
which the caller has to ensure keeps in scope – something apt-ftparchive
actually didn't ensure and relied on copy-on-write behavior instead
which c++11 forbids and hence the new default gcc abi doesn't use it.
David Kalnischkies před 11 roky
rodič
revize
88593886a4

+ 20 - 30
apt-pkg/depcache.cc

@@ -33,7 +33,6 @@
 #include <vector>
 #include <vector>
 #include <algorithm>
 #include <algorithm>
 #include <iostream>
 #include <iostream>
-#include <sstream>
 #include <set>
 #include <set>
 
 
 #include <sys/stat.h>
 #include <sys/stat.h>
@@ -252,17 +251,14 @@ bool pkgDepCache::writeStateFile(OpProgress * /*prog*/, bool InstalledOnly)	/*{{
       return _error->Error(_("Failed to open StateFile %s"),
       return _error->Error(_("Failed to open StateFile %s"),
 			   state.c_str());
 			   state.c_str());
 
 
-   FILE *OutFile;
-   string const outfile = state + ".tmp";
-   if((OutFile = fopen(outfile.c_str(),"w")) == NULL)
-      return _error->Error(_("Failed to write temporary StateFile %s"),
-			   outfile.c_str());
+   FileFd OutFile(state, FileFd::ReadWrite | FileFd::Atomic);
+   if (OutFile.IsOpen() == false || OutFile.Failed() == true)
+      return _error->Error(_("Failed to write temporary StateFile %s"), state.c_str());
 
 
    // first merge with the existing sections
    // first merge with the existing sections
    pkgTagFile tagfile(&StateFile);
    pkgTagFile tagfile(&StateFile);
    pkgTagSection section;
    pkgTagSection section;
    std::set<string> pkgs_seen;
    std::set<string> pkgs_seen;
-   const char *nullreorderlist[] = {0};
    while(tagfile.Step(section)) {
    while(tagfile.Step(section)) {
 	 string const pkgname = section.FindS("Package");
 	 string const pkgname = section.FindS("Package");
 	 string pkgarch = section.FindS("Architecture");
 	 string pkgarch = section.FindS("Architecture");
@@ -271,7 +267,7 @@ bool pkgDepCache::writeStateFile(OpProgress * /*prog*/, bool InstalledOnly)	/*{{
 	 // Silently ignore unknown packages and packages with no actual
 	 // Silently ignore unknown packages and packages with no actual
 	 // version.
 	 // version.
 	 pkgCache::PkgIterator pkg = Cache->FindPkg(pkgname, pkgarch);
 	 pkgCache::PkgIterator pkg = Cache->FindPkg(pkgname, pkgarch);
-	 if(pkg.end() || pkg.VersionList().end()) 
+	 if(pkg.end() || pkg.VersionList().end())
 	    continue;
 	    continue;
 	 StateCache const &P = PkgState[pkg->ID];
 	 StateCache const &P = PkgState[pkg->ID];
 	 bool newAuto = (P.Flags & Flag::Auto);
 	 bool newAuto = (P.Flags & Flag::Auto);
@@ -292,21 +288,17 @@ bool pkgDepCache::writeStateFile(OpProgress * /*prog*/, bool InstalledOnly)	/*{{
 	 if(_config->FindB("Debug::pkgAutoRemove",false))
 	 if(_config->FindB("Debug::pkgAutoRemove",false))
 	    std::clog << "Update existing AutoInstall info: " 
 	    std::clog << "Update existing AutoInstall info: " 
 		      << pkg.FullName() << std::endl;
 		      << pkg.FullName() << std::endl;
-	 TFRewriteData rewrite[3];
-	 rewrite[0].Tag = "Architecture";
-	 rewrite[0].Rewrite = pkg.Arch();
-	 rewrite[0].NewTag = 0;
-	 rewrite[1].Tag = "Auto-Installed";
-	 rewrite[1].Rewrite = newAuto ? "1" : "0";
-	 rewrite[1].NewTag = 0;
-	 rewrite[2].Tag = 0;
-	 TFRewrite(OutFile, section, nullreorderlist, rewrite);
-	 fprintf(OutFile,"\n");
+
+	 std::vector<pkgTagSection::Tag> rewrite;
+	 rewrite.push_back(pkgTagSection::Tag::Rewrite("Architecture", pkg.Arch()));
+	 rewrite.push_back(pkgTagSection::Tag::Rewrite("Auto-Installed", newAuto ? "1" : "0"));
+	 section.Write(OutFile, NULL, rewrite);
+	 if (OutFile.Write("\n", 1) == false)
+	    return false;
 	 pkgs_seen.insert(pkg.FullName());
 	 pkgs_seen.insert(pkg.FullName());
    }
    }
-   
+
    // then write the ones we have not seen yet
    // then write the ones we have not seen yet
-   std::ostringstream ostr;
    for(pkgCache::PkgIterator pkg=Cache->PkgBegin(); !pkg.end(); ++pkg) {
    for(pkgCache::PkgIterator pkg=Cache->PkgBegin(); !pkg.end(); ++pkg) {
       StateCache const &P = PkgState[pkg->ID];
       StateCache const &P = PkgState[pkg->ID];
       if(P.Flags & Flag::Auto) {
       if(P.Flags & Flag::Auto) {
@@ -325,19 +317,17 @@ bool pkgDepCache::writeStateFile(OpProgress * /*prog*/, bool InstalledOnly)	/*{{
 	    continue;
 	    continue;
 	 if(debug_autoremove)
 	 if(debug_autoremove)
 	    std::clog << "Writing new AutoInstall: " << pkg.FullName() << std::endl;
 	    std::clog << "Writing new AutoInstall: " << pkg.FullName() << std::endl;
-	 ostr.str(string(""));
-	 ostr << "Package: " << pkg.Name()
-	      << "\nArchitecture: " << pkgarch
-	      << "\nAuto-Installed: 1\n\n";
-	 fprintf(OutFile,"%s",ostr.str().c_str());
+	 std::string stanza = "Package: ";
+	 stanza.append(pkg.Name())
+	      .append("\nArchitecture: ").append(pkgarch)
+	      .append("\nAuto-Installed: 1\n\n");
+	 if (OutFile.Write(stanza.c_str(), stanza.length()) == false)
+	    return false;
       }
       }
    }
    }
-   fclose(OutFile);
-
-   // move the outfile over the real file and set permissions
-   rename(outfile.c_str(), state.c_str());
+   if (OutFile.Close() == false)
+      return false;
    chmod(state.c_str(), 0644);
    chmod(state.c_str(), 0644);
-
    return true;
    return true;
 }
 }
 									/*}}}*/
 									/*}}}*/

+ 49 - 76
apt-pkg/indexcopy.cc

@@ -108,10 +108,7 @@ bool IndexCopy::CopyPackages(string CDROM,string Name,vector<string> &List,
       }
       }
       if (_error->PendingError() == true)
       if (_error->PendingError() == true)
 	 return false;
 	 return false;
-      FILE *TargetFl = fdopen(dup(Target.Fd()),"w");
-      if (TargetFl == 0)
-	 return _error->Errno("fdopen","Failed to reopen fd");
-      
+
       // Setup the progress meter
       // Setup the progress meter
       if(Progress)
       if(Progress)
 	 Progress->OverallProgress(CurrentSize,TotalSize,FileSize,
 	 Progress->OverallProgress(CurrentSize,TotalSize,FileSize,
@@ -132,14 +129,11 @@ bool IndexCopy::CopyPackages(string CDROM,string Name,vector<string> &List,
 	 string File;
 	 string File;
 	 unsigned long long Size;
 	 unsigned long long Size;
 	 if (GetFile(File,Size) == false)
 	 if (GetFile(File,Size) == false)
-	 {
-	    fclose(TargetFl);
 	    return false;
 	    return false;
-	 }
-	 
+
 	 if (Chop != 0)
 	 if (Chop != 0)
 	    File = OrigPath + ChopDirs(File,Chop);
 	    File = OrigPath + ChopDirs(File,Chop);
-	 
+
 	 // See if the file exists
 	 // See if the file exists
 	 if (NoStat == false || Hits < 10)
 	 if (NoStat == false || Hits < 10)
 	 {
 	 {
@@ -157,10 +151,10 @@ bool IndexCopy::CopyPackages(string CDROM,string Name,vector<string> &List,
 	       if (Chop != 0)
 	       if (Chop != 0)
 		  File = OrigPath + ChopDirs(File,Chop);
 		  File = OrigPath + ChopDirs(File,Chop);
 	    }
 	    }
-	    
+
 	    // Get the size
 	    // Get the size
 	    struct stat Buf;
 	    struct stat Buf;
-	    if (stat((CDROM + Prefix + File).c_str(),&Buf) != 0 || 
+	    if (stat((CDROM + Prefix + File).c_str(),&Buf) != 0 ||
 		Buf.st_size == 0)
 		Buf.st_size == 0)
 	    {
 	    {
 	       bool Mangled = false;
 	       bool Mangled = false;
@@ -173,7 +167,7 @@ bool IndexCopy::CopyPackages(string CDROM,string Name,vector<string> &List,
 		  File.replace(Start,End-Start,"binary-all");
 		  File.replace(Start,End-Start,"binary-all");
 		  Mangled = true;
 		  Mangled = true;
 	       }
 	       }
-	       
+
 	       if (Mangled == false ||
 	       if (Mangled == false ||
 		   stat((CDROM + Prefix + File).c_str(),&Buf) != 0)
 		   stat((CDROM + Prefix + File).c_str(),&Buf) != 0)
 	       {
 	       {
@@ -181,9 +175,9 @@ bool IndexCopy::CopyPackages(string CDROM,string Name,vector<string> &List,
 		     clog << "Missed(2): " << OrigFile << endl;
 		     clog << "Missed(2): " << OrigFile << endl;
 		  NotFound++;
 		  NotFound++;
 		  continue;
 		  continue;
-	       }	       
-	    }	    
-	    			    	    
+	       }
+	    }
+
 	    // Size match
 	    // Size match
 	    if ((unsigned long long)Buf.st_size != Size)
 	    if ((unsigned long long)Buf.st_size != Size)
 	    {
 	    {
@@ -193,21 +187,17 @@ bool IndexCopy::CopyPackages(string CDROM,string Name,vector<string> &List,
 	       continue;
 	       continue;
 	    }
 	    }
 	 }
 	 }
-	 
+
 	 Packages++;
 	 Packages++;
 	 Hits++;
 	 Hits++;
-	 
-	 if (RewriteEntry(TargetFl,File) == false)
-	 {
-	    fclose(TargetFl);
+
+	 if (RewriteEntry(Target, File) == false)
 	    return false;
 	    return false;
-	 }
       }
       }
-      fclose(TargetFl);
 
 
       if (Debug == true)
       if (Debug == true)
 	 cout << " Processed by using Prefix '" << Prefix << "' and chop " << Chop << endl;
 	 cout << " Processed by using Prefix '" << Prefix << "' and chop " << Chop << endl;
-	 
+
       if (_config->FindB("APT::CDROM::NoAct",false) == false)
       if (_config->FindB("APT::CDROM::NoAct",false) == false)
       {
       {
 	 // Move out of the partial directory
 	 // Move out of the partial directory
@@ -218,39 +208,38 @@ bool IndexCopy::CopyPackages(string CDROM,string Name,vector<string> &List,
 	    return _error->Errno("rename","Failed to rename");
 	    return _error->Errno("rename","Failed to rename");
 	 ChangeOwnerAndPermissionOfFile("CopyPackages", FinalF.c_str(), "root", "root", 0644);
 	 ChangeOwnerAndPermissionOfFile("CopyPackages", FinalF.c_str(), "root", "root", 0644);
       }
       }
-	 
+
       /* Mangle the source to be in the proper notation with
       /* Mangle the source to be in the proper notation with
-       	 prefix dist [component] */ 
+	 prefix dist [component] */
       *I = string(*I,Prefix.length());
       *I = string(*I,Prefix.length());
       ConvertToSourceList(CDROM,*I);
       ConvertToSourceList(CDROM,*I);
       *I = Prefix + ' ' + *I;
       *I = Prefix + ' ' + *I;
-      
+
       CurrentSize += FileSize;
       CurrentSize += FileSize;
-   }   
+   }
    if(Progress)
    if(Progress)
       Progress->Done();
       Progress->Done();
-   
+
    // Some stats
    // Some stats
    if(log) {
    if(log) {
       stringstream msg;
       stringstream msg;
       if(NotFound == 0 && WrongSize == 0)
       if(NotFound == 0 && WrongSize == 0)
 	 ioprintf(msg, _("Wrote %i records.\n"), Packages);
 	 ioprintf(msg, _("Wrote %i records.\n"), Packages);
       else if (NotFound != 0 && WrongSize == 0)
       else if (NotFound != 0 && WrongSize == 0)
-	 ioprintf(msg, _("Wrote %i records with %i missing files.\n"), 
+	 ioprintf(msg, _("Wrote %i records with %i missing files.\n"),
 		  Packages, NotFound);
 		  Packages, NotFound);
       else if (NotFound == 0 && WrongSize != 0)
       else if (NotFound == 0 && WrongSize != 0)
-	 ioprintf(msg, _("Wrote %i records with %i mismatched files\n"), 
+	 ioprintf(msg, _("Wrote %i records with %i mismatched files\n"),
 		  Packages, WrongSize);
 		  Packages, WrongSize);
       if (NotFound != 0 && WrongSize != 0)
       if (NotFound != 0 && WrongSize != 0)
 	 ioprintf(msg, _("Wrote %i records with %i missing files and %i mismatched files\n"), Packages, NotFound, WrongSize);
 	 ioprintf(msg, _("Wrote %i records with %i missing files and %i mismatched files\n"), Packages, NotFound, WrongSize);
    }
    }
-   
+
    if (Packages == 0)
    if (Packages == 0)
       _error->Warning("No valid records were found.");
       _error->Warning("No valid records were found.");
 
 
    if (NotFound + WrongSize > 10)
    if (NotFound + WrongSize > 10)
       _error->Warning("A lot of entries were discarded, something may be wrong.\n");
       _error->Warning("A lot of entries were discarded, something may be wrong.\n");
-   
 
 
    return true;
    return true;
 }
 }
@@ -267,10 +256,10 @@ string IndexCopy::ChopDirs(string Path,unsigned int Depth)
       Depth--;
       Depth--;
    }
    }
    while (I != string::npos && Depth != 0);
    while (I != string::npos && Depth != 0);
-   
+
    if (I == string::npos)
    if (I == string::npos)
       return string();
       return string();
-   
+
    return string(Path,I+1);
    return string(Path,I+1);
 }
 }
 									/*}}}*/
 									/*}}}*/
@@ -433,17 +422,15 @@ bool PackageCopy::GetFile(string &File,unsigned long long &Size)
 }
 }
 									/*}}}*/
 									/*}}}*/
 // PackageCopy::RewriteEntry - Rewrite the entry with a new filename	/*{{{*/
 // PackageCopy::RewriteEntry - Rewrite the entry with a new filename	/*{{{*/
-// ---------------------------------------------------------------------
-/* */
-bool PackageCopy::RewriteEntry(FILE *Target,string File)
+bool PackageCopy::RewriteEntry(FileFd &Target,string const &File)
 {
 {
-   TFRewriteData Changes[] = {{ "Filename", File.c_str(), NULL },
-                              { NULL, NULL, NULL }};
-   
-   if (TFRewrite(Target,*Section,TFRewritePackageOrder,Changes) == false)
+   string const Dir(File,0,File.rfind('/'));
+   std::vector<pkgTagSection::Tag> Changes;
+   Changes.push_back(pkgTagSection::Tag::Rewrite("Filename", File));
+
+   if (Section->Write(Target, TFRewritePackageOrder, Changes) == false)
       return false;
       return false;
-   fputc('\n',Target);
-   return true;
+   return Target.Write("\n", 1);
 }
 }
 									/*}}}*/
 									/*}}}*/
 // SourceCopy::GetFile - Get the file information from the section	/*{{{*/
 // SourceCopy::GetFile - Get the file information from the section	/*{{{*/
@@ -478,23 +465,18 @@ bool SourceCopy::GetFile(string &File,unsigned long long &Size)
 }
 }
 									/*}}}*/
 									/*}}}*/
 // SourceCopy::RewriteEntry - Rewrite the entry with a new filename	/*{{{*/
 // SourceCopy::RewriteEntry - Rewrite the entry with a new filename	/*{{{*/
-// ---------------------------------------------------------------------
-/* */
-bool SourceCopy::RewriteEntry(FILE *Target,string File)
+bool SourceCopy::RewriteEntry(FileFd &Target, std::string const &File)
 {
 {
-   string Dir(File,0,File.rfind('/'));
-   TFRewriteData Changes[] = {{ "Directory", Dir.c_str(), NULL },
-                              { NULL, NULL, NULL }};
-   
-   if (TFRewrite(Target,*Section,TFRewriteSourceOrder,Changes) == false)
+   string const Dir(File,0,File.rfind('/'));
+   std::vector<pkgTagSection::Tag> Changes;
+   Changes.push_back(pkgTagSection::Tag::Rewrite("Directory", Dir));
+
+   if (Section->Write(Target, TFRewriteSourceOrder, Changes) == false)
       return false;
       return false;
-   fputc('\n',Target);
-   return true;
+   return Target.Write("\n", 1);
 }
 }
 									/*}}}*/
 									/*}}}*/
-// SigVerify::Verify - Verify a files md5sum against its metaindex     	/*{{{*/
-// ---------------------------------------------------------------------
-/* */
+// SigVerify::Verify - Verify a files md5sum against its metaindex	/*{{{*/
 bool SigVerify::Verify(string prefix, string file, indexRecords *MetaIndex)
 bool SigVerify::Verify(string prefix, string file, indexRecords *MetaIndex)
 {
 {
    const indexRecords::checkSum *Record = MetaIndex->Lookup(file);
    const indexRecords::checkSum *Record = MetaIndex->Lookup(file);
@@ -702,7 +684,7 @@ bool TranslationsCopy::CopyTranslations(string CDROM,string Name,	/*{{{*/
       pkgTagFile Parser(&Pkg);
       pkgTagFile Parser(&Pkg);
       if (_error->PendingError() == true)
       if (_error->PendingError() == true)
 	 return false;
 	 return false;
-      
+
       // Open the output file
       // Open the output file
       char S[400];
       char S[400];
       snprintf(S,sizeof(S),"cdrom:[%s]/%s",Name.c_str(),
       snprintf(S,sizeof(S),"cdrom:[%s]/%s",Name.c_str(),
@@ -719,10 +701,7 @@ bool TranslationsCopy::CopyTranslations(string CDROM,string Name,	/*{{{*/
       }
       }
       if (_error->PendingError() == true)
       if (_error->PendingError() == true)
 	 return false;
 	 return false;
-      FILE *TargetFl = fdopen(dup(Target.Fd()),"w");
-      if (TargetFl == 0)
-	 return _error->Errno("fdopen","Failed to reopen fd");
-      
+
       // Setup the progress meter
       // Setup the progress meter
       if(Progress)
       if(Progress)
 	 Progress->OverallProgress(CurrentSize,TotalSize,FileSize,
 	 Progress->OverallProgress(CurrentSize,TotalSize,FileSize,
@@ -740,20 +719,16 @@ bool TranslationsCopy::CopyTranslations(string CDROM,string Name,	/*{{{*/
 	 if(Progress)
 	 if(Progress)
 	    Progress->Progress(Parser.Offset());
 	    Progress->Progress(Parser.Offset());
 
 
-	 const char *Start;
-	 const char *Stop;
-	 Section.GetSection(Start,Stop);
-	 fwrite(Start,Stop-Start, 1, TargetFl);
-	 fputc('\n',TargetFl);
+	 if (Section.Write(Target) == false || Target.Write("\n", 1) == false)
+	    return false;
 
 
 	 Packages++;
 	 Packages++;
 	 Hits++;
 	 Hits++;
       }
       }
-      fclose(TargetFl);
 
 
       if (Debug == true)
       if (Debug == true)
 	 cout << " Processed by using Prefix '" << Prefix << "' and chop " << endl;
 	 cout << " Processed by using Prefix '" << Prefix << "' and chop " << endl;
-	 
+
       if (_config->FindB("APT::CDROM::NoAct",false) == false)
       if (_config->FindB("APT::CDROM::NoAct",false) == false)
       {
       {
 	 // Move out of the partial directory
 	 // Move out of the partial directory
@@ -764,34 +739,32 @@ bool TranslationsCopy::CopyTranslations(string CDROM,string Name,	/*{{{*/
 	    return _error->Errno("rename","Failed to rename");
 	    return _error->Errno("rename","Failed to rename");
 	 ChangeOwnerAndPermissionOfFile("CopyTranslations", FinalF.c_str(), "root", "root", 0644);
 	 ChangeOwnerAndPermissionOfFile("CopyTranslations", FinalF.c_str(), "root", "root", 0644);
       }
       }
-      
-      
+
       CurrentSize += FileSize;
       CurrentSize += FileSize;
-   }   
+   }
    if(Progress)
    if(Progress)
       Progress->Done();
       Progress->Done();
-   
+
    // Some stats
    // Some stats
    if(log) {
    if(log) {
       stringstream msg;
       stringstream msg;
       if(NotFound == 0 && WrongSize == 0)
       if(NotFound == 0 && WrongSize == 0)
 	 ioprintf(msg, _("Wrote %i records.\n"), Packages);
 	 ioprintf(msg, _("Wrote %i records.\n"), Packages);
       else if (NotFound != 0 && WrongSize == 0)
       else if (NotFound != 0 && WrongSize == 0)
-	 ioprintf(msg, _("Wrote %i records with %i missing files.\n"), 
+	 ioprintf(msg, _("Wrote %i records with %i missing files.\n"),
 		  Packages, NotFound);
 		  Packages, NotFound);
       else if (NotFound == 0 && WrongSize != 0)
       else if (NotFound == 0 && WrongSize != 0)
-	 ioprintf(msg, _("Wrote %i records with %i mismatched files\n"), 
+	 ioprintf(msg, _("Wrote %i records with %i mismatched files\n"),
 		  Packages, WrongSize);
 		  Packages, WrongSize);
       if (NotFound != 0 && WrongSize != 0)
       if (NotFound != 0 && WrongSize != 0)
 	 ioprintf(msg, _("Wrote %i records with %i missing files and %i mismatched files\n"), Packages, NotFound, WrongSize);
 	 ioprintf(msg, _("Wrote %i records with %i missing files and %i mismatched files\n"), Packages, NotFound, WrongSize);
    }
    }
-   
+
    if (Packages == 0)
    if (Packages == 0)
       _error->Warning("No valid records were found.");
       _error->Warning("No valid records were found.");
 
 
    if (NotFound + WrongSize > 10)
    if (NotFound + WrongSize > 10)
       _error->Warning("A lot of entries were discarded, something may be wrong.\n");
       _error->Warning("A lot of entries were discarded, something may be wrong.\n");
-   
 
 
    return true;
    return true;
 }
 }

+ 4 - 3
apt-pkg/indexcopy.h

@@ -28,6 +28,7 @@ using std::vector;
 class pkgTagSection;
 class pkgTagSection;
 class indexRecords;
 class indexRecords;
 class pkgCdromStatus;
 class pkgCdromStatus;
+class FileFd;
 
 
 class IndexCopy								/*{{{*/
 class IndexCopy								/*{{{*/
 {
 {
@@ -45,7 +46,7 @@ class IndexCopy								/*{{{*/
    void ConvertToSourceList(std::string CD,std::string &Path);
    void ConvertToSourceList(std::string CD,std::string &Path);
    bool GrabFirst(std::string Path,std::string &To,unsigned int Depth);
    bool GrabFirst(std::string Path,std::string &To,unsigned int Depth);
    virtual bool GetFile(std::string &Filename,unsigned long long &Size) = 0;
    virtual bool GetFile(std::string &Filename,unsigned long long &Size) = 0;
-   virtual bool RewriteEntry(FILE *Target,std::string File) = 0;
+   virtual bool RewriteEntry(FileFd &Target, std::string const &File) = 0;
    virtual const char *GetFileName() = 0;
    virtual const char *GetFileName() = 0;
    virtual const char *Type() = 0;
    virtual const char *Type() = 0;
    
    
@@ -61,7 +62,7 @@ class PackageCopy : public IndexCopy					/*{{{*/
    protected:
    protected:
    
    
    virtual bool GetFile(std::string &Filename,unsigned long long &Size);
    virtual bool GetFile(std::string &Filename,unsigned long long &Size);
-   virtual bool RewriteEntry(FILE *Target,std::string File);
+   virtual bool RewriteEntry(FileFd &Target, std::string const &File);
    virtual const char *GetFileName() {return "Packages";};
    virtual const char *GetFileName() {return "Packages";};
    virtual const char *Type() {return "Package";};
    virtual const char *Type() {return "Package";};
    
    
@@ -72,7 +73,7 @@ class SourceCopy : public IndexCopy					/*{{{*/
    protected:
    protected:
    
    
    virtual bool GetFile(std::string &Filename,unsigned long long &Size);
    virtual bool GetFile(std::string &Filename,unsigned long long &Size);
-   virtual bool RewriteEntry(FILE *Target,std::string File);
+   virtual bool RewriteEntry(FileFd &Target, std::string const &File);
    virtual const char *GetFileName() {return "Sources";};
    virtual const char *GetFileName() {return "Sources";};
    virtual const char *Type() {return "Source";};
    virtual const char *Type() {return "Source";};
    
    

+ 24 - 22
apt-private/private-show.cc

@@ -97,28 +97,30 @@ static bool DisplayRecord(pkgCacheFile &CacheFile, pkgCache::VerIterator V,
       manual_installed = 0;
       manual_installed = 0;
 
 
    // FIXME: add verbose that does not do the removal of the tags?
    // FIXME: add verbose that does not do the removal of the tags?
-   TFRewriteData RW[] = {
-      // delete, apt-cache show has this info and most users do not care
-      {"MD5sum", NULL, NULL},
-      {"SHA1", NULL, NULL},
-      {"SHA256", NULL, NULL},
-      {"Filename", NULL, NULL},
-      {"Multi-Arch", NULL, NULL},
-      {"Architecture", NULL, NULL},
-      {"Conffiles", NULL, NULL},
-      // we use the translated description
-      {"Description", NULL, NULL},
-      {"Description-md5", NULL, NULL},
-      // improve
-      {"Installed-Size", installed_size.c_str(), NULL},
-      {"Size", package_size.c_str(), "Download-Size"},
-      // add
-      {"APT-Manual-Installed", manual_installed, NULL},
-      {"APT-Sources", source_index_file.c_str(), NULL},
-      {NULL, NULL, NULL}
-   };
-
-   if(TFRewrite(stdout, Tags, NULL, RW) == false)
+   std::vector<pkgTagSection::Tag> RW;
+   // delete, apt-cache show has this info and most users do not care
+   RW.push_back(pkgTagSection::Tag::Remove("MD5sum"));
+   RW.push_back(pkgTagSection::Tag::Remove("SHA1"));
+   RW.push_back(pkgTagSection::Tag::Remove("SHA256"));
+   RW.push_back(pkgTagSection::Tag::Remove("SHA512"));
+   RW.push_back(pkgTagSection::Tag::Remove("Filename"));
+   RW.push_back(pkgTagSection::Tag::Remove("Multi-Arch"));
+   RW.push_back(pkgTagSection::Tag::Remove("Architecture"));
+   RW.push_back(pkgTagSection::Tag::Remove("Conffiles"));
+   // we use the translated description
+   RW.push_back(pkgTagSection::Tag::Remove("Description"));
+   RW.push_back(pkgTagSection::Tag::Remove("Description-md5"));
+   // improve
+   RW.push_back(pkgTagSection::Tag::Rewrite("Installed-Size", installed_size));
+   RW.push_back(pkgTagSection::Tag::Remove("Size"));
+   RW.push_back(pkgTagSection::Tag::Rewrite("Download-Size", package_size));
+   // add
+   RW.push_back(pkgTagSection::Tag::Rewrite("APT-Manual-Installed", manual_installed));
+   RW.push_back(pkgTagSection::Tag::Rewrite("APT-Sources", source_index_file));
+
+   FileFd stdoutfd;
+   if (stdoutfd.OpenDescriptor(STDOUT_FILENO, FileFd::WriteOnly, false) == false ||
+	 Tags.Write(stdoutfd, TFRewritePackageOrder, RW) == false || stdoutfd.Close() == false)
       return _error->Error("Internal Error, Unable to parse a package record");
       return _error->Error("Internal Error, Unable to parse a package record");
 
 
    // write the description
    // write the description

+ 12 - 9
cmdline/apt-cache.cc

@@ -580,6 +580,12 @@ static bool DumpAvail(CommandLine &)
    
    
    LocalitySort(VFList,Count,sizeof(*VFList));
    LocalitySort(VFList,Count,sizeof(*VFList));
 
 
+   std::vector<pkgTagSection::Tag> RW;
+   RW.push_back(pkgTagSection::Tag::Remove("Status"));
+   RW.push_back(pkgTagSection::Tag::Remove("Config-Version"));
+   FileFd stdoutfd;
+   stdoutfd.OpenDescriptor(STDOUT_FILENO, FileFd::WriteOnly, false);
+
    // Iterate over all the package files and write them out.
    // Iterate over all the package files and write them out.
    char *Buffer = new char[Cache->HeaderP->MaxVerFileSize+10];
    char *Buffer = new char[Cache->HeaderP->MaxVerFileSize+10];
    for (pkgCache::VerFile **J = VFList; *J != 0;)
    for (pkgCache::VerFile **J = VFList; *J != 0;)
@@ -620,35 +626,32 @@ static bool DumpAvail(CommandLine &)
 	 if (PkgF.Read(Buffer,VF.Size + Jitter) == false)
 	 if (PkgF.Read(Buffer,VF.Size + Jitter) == false)
 	    break;
 	    break;
 	 Buffer[VF.Size + Jitter] = '\n';
 	 Buffer[VF.Size + Jitter] = '\n';
-	 
+
 	 // See above..
 	 // See above..
 	 if ((File->Flags & pkgCache::Flag::NotSource) == pkgCache::Flag::NotSource)
 	 if ((File->Flags & pkgCache::Flag::NotSource) == pkgCache::Flag::NotSource)
 	 {
 	 {
 	    pkgTagSection Tags;
 	    pkgTagSection Tags;
-	    TFRewriteData RW[] = {{"Status", NULL, NULL},{"Config-Version", NULL, NULL},{NULL, NULL, NULL}};
-	    const char *Zero = 0;
 	    if (Tags.Scan(Buffer+Jitter,VF.Size+1) == false ||
 	    if (Tags.Scan(Buffer+Jitter,VF.Size+1) == false ||
-		TFRewrite(stdout,Tags,&Zero,RW) == false)
+		Tags.Write(stdoutfd, NULL, RW) == false ||
+		stdoutfd.Write("\n", 1) == false)
 	    {
 	    {
 	       _error->Error("Internal Error, Unable to parse a package record");
 	       _error->Error("Internal Error, Unable to parse a package record");
 	       break;
 	       break;
 	    }
 	    }
-	    fputc('\n',stdout);
 	 }
 	 }
 	 else
 	 else
 	 {
 	 {
-	    if (fwrite(Buffer+Jitter,VF.Size+1,1,stdout) != 1)
+	    if (stdoutfd.Write(Buffer + Jitter, VF.Size + 1) == false)
 	       break;
 	       break;
 	 }
 	 }
-	 
+
 	 Pos = VF.Offset + VF.Size;
 	 Pos = VF.Offset + VF.Size;
       }
       }
 
 
-      fflush(stdout);
       if (_error->PendingError() == true)
       if (_error->PendingError() == true)
          break;
          break;
    }
    }
-   
+
    delete [] Buffer;
    delete [] Buffer;
    delete [] VFList;
    delete [] VFList;
    return !_error->PendingError();
    return !_error->PendingError();

+ 7 - 7
cmdline/apt-sortpkgs.cc

@@ -108,8 +108,10 @@ static bool DoIt(string InFile)
    const char **Order = TFRewritePackageOrder;
    const char **Order = TFRewritePackageOrder;
    if (Source == true)
    if (Source == true)
       Order = TFRewriteSourceOrder;
       Order = TFRewriteSourceOrder;
-   
+
    // Emit
    // Emit
+   FileFd stdoutfd;
+   stdoutfd.OpenDescriptor(STDOUT_FILENO, FileFd::WriteOnly, false);
    unsigned char *Buffer = new unsigned char[Largest+1];
    unsigned char *Buffer = new unsigned char[Largest+1];
    for (vector<PkgName>::iterator I = List.begin(); I != List.end(); ++I)
    for (vector<PkgName>::iterator I = List.begin(); I != List.end(); ++I)
    {
    {
@@ -119,8 +121,8 @@ static bool DoIt(string InFile)
 	 delete [] Buffer;
 	 delete [] Buffer;
 	 return false;
 	 return false;
       }
       }
-      
-      Buffer[I->Length] = '\n';      
+
+      Buffer[I->Length] = '\n';
       if (Section.Scan((char *)Buffer,I->Length+1) == false)
       if (Section.Scan((char *)Buffer,I->Length+1) == false)
       {
       {
 	 delete [] Buffer;
 	 delete [] Buffer;
@@ -128,15 +130,13 @@ static bool DoIt(string InFile)
       }
       }
 
 
       // Sort the section
       // Sort the section
-      if (TFRewrite(stdout,Section,Order,0) == false)
+      if (Section.Write(stdoutfd, Order) == false || stdoutfd.Write("\n", 1) == false)
       {
       {
 	 delete [] Buffer;
 	 delete [] Buffer;
 	 return _error->Error("Internal error, failed to sort fields");
 	 return _error->Error("Internal error, failed to sort fields");
       }
       }
-      
-      fputc('\n',stdout);      
    }
    }
-   
+
    delete [] Buffer;
    delete [] Buffer;
    return true;
    return true;
 }
 }

+ 23 - 28
ftparchive/apt-ftparchive.cc

@@ -178,7 +178,9 @@ bool PackageMap::GenPackages(Configuration &Setup,struct CacheDB::Stats &Stats)
    PkgDone = true;
    PkgDone = true;
    
    
    // Create a package writer object.
    // Create a package writer object.
-   PackagesWriter Packages(flCombine(CacheDir,BinCacheDB),
+   MultiCompress Comp(flCombine(ArchiveDir,PkgFile),
+		      PkgCompress,Permissions);
+   PackagesWriter Packages(&Comp.Input, flCombine(CacheDir,BinCacheDB),
 			   flCombine(OverrideDir,BinOverride),
 			   flCombine(OverrideDir,BinOverride),
 			   flCombine(OverrideDir,ExtraOverride),
 			   flCombine(OverrideDir,ExtraOverride),
 			   Arch);
 			   Arch);
@@ -197,10 +199,6 @@ bool PackageMap::GenPackages(Configuration &Setup,struct CacheDB::Stats &Stats)
    Packages.Stats.DeLinkBytes = Stats.DeLinkBytes;
    Packages.Stats.DeLinkBytes = Stats.DeLinkBytes;
    Packages.DeLinkLimit = DeLinkLimit;
    Packages.DeLinkLimit = DeLinkLimit;
 
 
-   // Create a compressor object
-   MultiCompress Comp(flCombine(ArchiveDir,PkgFile),
-		      PkgCompress,Permissions);
-   Packages.Output = Comp.Input;
    if (_error->PendingError() == true)
    if (_error->PendingError() == true)
       return _error->Error(_("Error processing directory %s"),BaseDir.c_str());
       return _error->Error(_("Error processing directory %s"),BaseDir.c_str());
    
    
@@ -272,7 +270,9 @@ bool PackageMap::GenSources(Configuration &Setup,struct CacheDB::Stats &Stats)
    SrcDone = true;
    SrcDone = true;
    
    
    // Create a package writer object.
    // Create a package writer object.
-   SourcesWriter Sources(flCombine(CacheDir, SrcCacheDB),
+   MultiCompress Comp(flCombine(ArchiveDir,SrcFile),
+		      SrcCompress,Permissions);
+   SourcesWriter Sources(&Comp.Input, flCombine(CacheDir, SrcCacheDB),
 			 flCombine(OverrideDir,BinOverride),
 			 flCombine(OverrideDir,BinOverride),
 			 flCombine(OverrideDir,SrcOverride),
 			 flCombine(OverrideDir,SrcOverride),
 			 flCombine(OverrideDir,SrcExtraOverride));
 			 flCombine(OverrideDir,SrcExtraOverride));
@@ -287,11 +287,7 @@ bool PackageMap::GenSources(Configuration &Setup,struct CacheDB::Stats &Stats)
 
 
    Sources.DeLinkLimit = DeLinkLimit;
    Sources.DeLinkLimit = DeLinkLimit;
    Sources.Stats.DeLinkBytes = Stats.DeLinkBytes;
    Sources.Stats.DeLinkBytes = Stats.DeLinkBytes;
-   
-   // Create a compressor object
-   MultiCompress Comp(flCombine(ArchiveDir,SrcFile),
-		      SrcCompress,Permissions);
-   Sources.Output = Comp.Input;
+
    if (_error->PendingError() == true)
    if (_error->PendingError() == true)
       return _error->Error(_("Error processing directory %s"),BaseDir.c_str());
       return _error->Error(_("Error processing directory %s"),BaseDir.c_str());
 
 
@@ -365,16 +361,15 @@ bool PackageMap::GenContents(Configuration &Setup,
    gettimeofday(&StartTime,0);   
    gettimeofday(&StartTime,0);   
    
    
    // Create a package writer object.
    // Create a package writer object.
-   ContentsWriter Contents("", Arch);
+   MultiCompress Comp(flCombine(ArchiveDir,this->Contents),
+		      CntCompress,Permissions);
+   Comp.UpdateMTime = Setup.FindI("Default::ContentsAge",10)*24*60*60;
+   ContentsWriter Contents(&Comp.Input, "", Arch);
    if (PkgExt.empty() == false && Contents.SetExts(PkgExt) == false)
    if (PkgExt.empty() == false && Contents.SetExts(PkgExt) == false)
       return _error->Error(_("Package extension list is too long"));
       return _error->Error(_("Package extension list is too long"));
    if (_error->PendingError() == true)
    if (_error->PendingError() == true)
       return false;
       return false;
 
 
-   MultiCompress Comp(flCombine(ArchiveDir,this->Contents),
-		      CntCompress,Permissions);
-   Comp.UpdateMTime = Setup.FindI("Default::ContentsAge",10)*24*60*60;
-   Contents.Output = Comp.Input;
    if (_error->PendingError() == true)
    if (_error->PendingError() == true)
       return false;
       return false;
 
 
@@ -384,7 +379,7 @@ bool PackageMap::GenContents(Configuration &Setup,
       FileFd Head(flCombine(OverrideDir,ContentsHead),FileFd::ReadOnly);
       FileFd Head(flCombine(OverrideDir,ContentsHead),FileFd::ReadOnly);
       if (_error->PendingError() == true)
       if (_error->PendingError() == true)
 	 return false;
 	 return false;
-      
+
       unsigned long long Size = Head.Size();
       unsigned long long Size = Head.Size();
       unsigned char Buf[4096];
       unsigned char Buf[4096];
       while (Size != 0)
       while (Size != 0)
@@ -392,17 +387,17 @@ bool PackageMap::GenContents(Configuration &Setup,
 	 unsigned long long ToRead = Size;
 	 unsigned long long ToRead = Size;
 	 if (Size > sizeof(Buf))
 	 if (Size > sizeof(Buf))
 	    ToRead = sizeof(Buf);
 	    ToRead = sizeof(Buf);
-	 
+
 	 if (Head.Read(Buf,ToRead) == false)
 	 if (Head.Read(Buf,ToRead) == false)
 	    return false;
 	    return false;
-	 
-	 if (fwrite(Buf,1,ToRead,Comp.Input) != ToRead)
+
+	 if (Comp.Input.Write(Buf, ToRead) == false)
 	    return _error->Errno("fwrite",_("Error writing header to contents file"));
 	    return _error->Errno("fwrite",_("Error writing header to contents file"));
-	 
+
 	 Size -= ToRead;
 	 Size -= ToRead;
-      }            
-   }  
-      
+      }
+   }
+
    /* Go over all the package file records and parse all the package
    /* Go over all the package file records and parse all the package
       files associated with this contents file into one great big honking
       files associated with this contents file into one great big honking
       memory structure, then dump the sorted version */
       memory structure, then dump the sorted version */
@@ -676,7 +671,7 @@ static bool SimpleGenPackages(CommandLine &CmdL)
       Override = CmdL.FileList[2];
       Override = CmdL.FileList[2];
    
    
    // Create a package writer object.
    // Create a package writer object.
-   PackagesWriter Packages(_config->Find("APT::FTPArchive::DB"),
+   PackagesWriter Packages(NULL, _config->Find("APT::FTPArchive::DB"),
 			   Override, "", _config->Find("APT::FTPArchive::Architecture"));
 			   Override, "", _config->Find("APT::FTPArchive::Architecture"));
    if (_error->PendingError() == true)
    if (_error->PendingError() == true)
       return false;
       return false;
@@ -704,7 +699,7 @@ static bool SimpleGenContents(CommandLine &CmdL)
       return ShowHelp(CmdL);
       return ShowHelp(CmdL);
    
    
    // Create a package writer object.
    // Create a package writer object.
-   ContentsWriter Contents(_config->Find("APT::FTPArchive::DB"), _config->Find("APT::FTPArchive::Architecture"));
+   ContentsWriter Contents(NULL, _config->Find("APT::FTPArchive::DB"), _config->Find("APT::FTPArchive::Architecture"));
    if (_error->PendingError() == true)
    if (_error->PendingError() == true)
       return false;
       return false;
    
    
@@ -737,7 +732,7 @@ static bool SimpleGenSources(CommandLine &CmdL)
 			     SOverride.c_str());
 			     SOverride.c_str());
        
        
    // Create a package writer object.
    // Create a package writer object.
-   SourcesWriter Sources(_config->Find("APT::FTPArchive::DB"),Override,SOverride);
+   SourcesWriter Sources(NULL, _config->Find("APT::FTPArchive::DB"),Override,SOverride);
    if (_error->PendingError() == true)
    if (_error->PendingError() == true)
       return false;
       return false;
    
    
@@ -764,7 +759,7 @@ static bool SimpleGenRelease(CommandLine &CmdL)
 
 
    string Dir = CmdL.FileList[1];
    string Dir = CmdL.FileList[1];
 
 
-   ReleaseWriter Release("");
+   ReleaseWriter Release(NULL, "");
    Release.DirStrip = Dir;
    Release.DirStrip = Dir;
 
 
    if (_error->PendingError() == true)
    if (_error->PendingError() == true)

+ 18 - 16
ftparchive/contents.cc

@@ -38,6 +38,7 @@
 #include <apt-pkg/debfile.h>
 #include <apt-pkg/debfile.h>
 #include <apt-pkg/dirstream.h>
 #include <apt-pkg/dirstream.h>
 #include <apt-pkg/error.h>
 #include <apt-pkg/error.h>
+#include <apt-pkg/fileutl.h>
 
 
 #include <stdio.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdlib.h>
@@ -238,19 +239,19 @@ void GenContents::Add(const char *Dir,const char *Package)
 // GenContents::WriteSpace - Write a given number of white space chars	/*{{{*/
 // GenContents::WriteSpace - Write a given number of white space chars	/*{{{*/
 // ---------------------------------------------------------------------
 // ---------------------------------------------------------------------
 /* We mod 8 it and write tabs where possible. */
 /* We mod 8 it and write tabs where possible. */
-void GenContents::WriteSpace(FILE *Out,unsigned int Current,unsigned int Target)
+void GenContents::WriteSpace(std::string &out, size_t Current, size_t Target)
 {
 {
    if (Target <= Current)
    if (Target <= Current)
       Target = Current + 1;
       Target = Current + 1;
-   
+
    /* Now we write tabs so long as the next tab stop would not pass
    /* Now we write tabs so long as the next tab stop would not pass
       the target */
       the target */
    for (; (Current/8 + 1)*8 < Target; Current = (Current/8 + 1)*8)
    for (; (Current/8 + 1)*8 < Target; Current = (Current/8 + 1)*8)
-      fputc('\t',Out);
+      out.append("\t");
 
 
    // Fill the last bit with spaces
    // Fill the last bit with spaces
    for (; Current < Target; Current++)
    for (; Current < Target; Current++)
-      fputc(' ',Out);
+      out.append(" ");
 }
 }
 									/*}}}*/
 									/*}}}*/
 // GenContents::Print - Display the tree				/*{{{*/
 // GenContents::Print - Display the tree				/*{{{*/
@@ -259,13 +260,13 @@ void GenContents::WriteSpace(FILE *Out,unsigned int Current,unsigned int Target)
    calls itself and runs over each section of the tree printing out
    calls itself and runs over each section of the tree printing out
    the pathname and the hit packages. We use Buf to build the pathname
    the pathname and the hit packages. We use Buf to build the pathname
    summed over all the directory parents of this node. */
    summed over all the directory parents of this node. */
-void GenContents::Print(FILE *Out)
+void GenContents::Print(FileFd &Out)
 {
 {
    char Buffer[1024];
    char Buffer[1024];
    Buffer[0] = 0;
    Buffer[0] = 0;
    DoPrint(Out,&Root,Buffer);
    DoPrint(Out,&Root,Buffer);
 }
 }
-void GenContents::DoPrint(FILE *Out,GenContents::Node *Top, char *Buf)
+void GenContents::DoPrint(FileFd &Out,GenContents::Node *Top, char *Buf)
 {
 {
    if (Top == 0)
    if (Top == 0)
       return;
       return;
@@ -278,26 +279,27 @@ void GenContents::DoPrint(FILE *Out,GenContents::Node *Top, char *Buf)
    if (Top->Path != 0)
    if (Top->Path != 0)
    {
    {
       strcat(Buf,Top->Path);
       strcat(Buf,Top->Path);
-      
+
       // Do not show the item if it is a directory with dups
       // Do not show the item if it is a directory with dups
       if (Top->Path[strlen(Top->Path)-1] != '/' /*|| Top->Dups == 0*/)
       if (Top->Path[strlen(Top->Path)-1] != '/' /*|| Top->Dups == 0*/)
       {
       {
-	 fputs(Buf,Out);
-	 WriteSpace(Out,strlen(Buf),60);
+	 std::string out = Buf;
+	 WriteSpace(out, out.length(), 60);
 	 for (Node *I = Top; I != 0; I = I->Dups)
 	 for (Node *I = Top; I != 0; I = I->Dups)
 	 {
 	 {
 	    if (I != Top)
 	    if (I != Top)
-	       fputc(',',Out);
-	    fputs(I->Package,Out);
+	       out.append(",");
+	    out.append(I->Package);
 	 }
 	 }
-         fputc('\n',Out);
-      }      
-   }   
-   
+         out.append("\n");
+	 Out.Write(out.c_str(), out.length());
+      }
+   }
+
    // Go along the directory link
    // Go along the directory link
    DoPrint(Out,Top->DirDown,Buf);
    DoPrint(Out,Top->DirDown,Buf);
    *OldEnd = 0;
    *OldEnd = 0;
-   
+
    // Go right
    // Go right
    DoPrint(Out,Top->BTreeRight,Buf);  
    DoPrint(Out,Top->BTreeRight,Buf);  
 }
 }

+ 4 - 3
ftparchive/contents.h

@@ -17,6 +17,7 @@
 #include <string>
 #include <string>
 
 
 class debDebFile;
 class debDebFile;
+class FileFd;
 
 
 class GenContents
 class GenContents
 {
 {
@@ -54,14 +55,14 @@ class GenContents
    unsigned long NodeLeft;
    unsigned long NodeLeft;
    
    
    Node *Grab(Node *Top,const char *Name,const char *Package);
    Node *Grab(Node *Top,const char *Name,const char *Package);
-   void WriteSpace(FILE *Out,unsigned int Current,unsigned int Target);
-   void DoPrint(FILE *Out,Node *Top, char *Buf);
+   void WriteSpace(std::string &out, size_t Current, size_t Target);
+   void DoPrint(FileFd &Out,Node *Top, char *Buf);
    
    
    public:
    public:
    
    
    char *Mystrdup(const char *From);
    char *Mystrdup(const char *From);
    void Add(const char *Dir,const char *Package);   
    void Add(const char *Dir,const char *Package);   
-   void Print(FILE *Out);
+   void Print(FileFd &Out);
 
 
    GenContents() : BlockList(0), StrPool(0), StrLeft(0), 
    GenContents() : BlockList(0), StrPool(0), StrLeft(0), 
                    NodePool(0), NodeLeft(0) {};
                    NodePool(0), NodeLeft(0) {};

+ 8 - 11
ftparchive/multicompress.cc

@@ -46,7 +46,6 @@ MultiCompress::MultiCompress(string const &Output,string const &Compress,
 {
 {
    Outputs = 0;
    Outputs = 0;
    Outputter = -1;
    Outputter = -1;
-   Input = 0;
    UpdateMTime = 0;
    UpdateMTime = 0;
 
 
    /* Parse the compression string, a space separated lists of compresison
    /* Parse the compression string, a space separated lists of compresison
@@ -187,12 +186,11 @@ bool MultiCompress::Start()
    };
    };
 
 
    close(Pipe[0]);
    close(Pipe[0]);
-   Input = fdopen(Pipe[1],"w");
-   if (Input == 0)
-      return _error->Errno("fdopen",_("Failed to create FILE*"));
-   
+   if (Input.OpenDescriptor(Pipe[1], FileFd::WriteOnly, true) == false)
+      return false;
+
    if (Outputter == -1)
    if (Outputter == -1)
-      return _error->Errno("fork",_("Failed to fork"));   
+      return _error->Errno("fork",_("Failed to fork"));
    return true;
    return true;
 }
 }
 									/*}}}*/
 									/*}}}*/
@@ -201,11 +199,10 @@ bool MultiCompress::Start()
 /* */
 /* */
 bool MultiCompress::Die()
 bool MultiCompress::Die()
 {
 {
-   if (Input == 0)
+   if (Input.IsOpen() == false)
       return true;
       return true;
-   
-   fclose(Input);
-   Input = 0;
+
+   Input.Close();
    bool Res = ExecWait(Outputter,_("Compress child"),false);
    bool Res = ExecWait(Outputter,_("Compress child"),false);
    Outputter = -1;
    Outputter = -1;
    return Res;
    return Res;
@@ -217,7 +214,7 @@ bool MultiCompress::Die()
 bool MultiCompress::Finalize(unsigned long long &OutSize)
 bool MultiCompress::Finalize(unsigned long long &OutSize)
 {
 {
    OutSize = 0;
    OutSize = 0;
-   if (Input == 0 || Die() == false)
+   if (Input.IsOpen() == false || Die() == false)
       return false;
       return false;
    
    
    time_t Now;
    time_t Now;

+ 1 - 1
ftparchive/multicompress.h

@@ -48,7 +48,7 @@ class MultiCompress
    public:
    public:
    
    
    // The FD to write to for compression.
    // The FD to write to for compression.
-   FILE *Input;
+   FileFd Input;
    unsigned long UpdateMTime;
    unsigned long UpdateMTime;
    
    
    bool Finalize(unsigned long long &OutSize);
    bool Finalize(unsigned long long &OutSize);

+ 95 - 109
ftparchive/writer.cc

@@ -51,20 +51,6 @@
 using namespace std;
 using namespace std;
 FTWScanner *FTWScanner::Owner;
 FTWScanner *FTWScanner::Owner;
 
 
-// SetTFRewriteData - Helper for setting rewrite lists			/*{{{*/
-// ---------------------------------------------------------------------
-/* */
-static inline TFRewriteData SetTFRewriteData(const char *tag,
-			     const char *rewrite,
-			     const char *newtag = 0)
-{
-   TFRewriteData tfrd;
-   tfrd.Tag = tag;
-   tfrd.Rewrite = rewrite;
-   tfrd.NewTag = newtag;
-   return tfrd;
-}
-									/*}}}*/
 // ConfigToDoHashes - which hashes to generate				/*{{{*/
 // ConfigToDoHashes - which hashes to generate				/*{{{*/
 static void SingleConfigToDoHashes(unsigned int &DoHashes, std::string const &Conf, unsigned int const Flag)
 static void SingleConfigToDoHashes(unsigned int &DoHashes, std::string const &Conf, unsigned int const Flag)
 {
 {
@@ -85,8 +71,15 @@ static void ConfigToDoHashes(unsigned int &DoHashes, std::string const &Conf)
 // FTWScanner::FTWScanner - Constructor					/*{{{*/
 // FTWScanner::FTWScanner - Constructor					/*{{{*/
 // ---------------------------------------------------------------------
 // ---------------------------------------------------------------------
 /* */
 /* */
-FTWScanner::FTWScanner(string const &Arch): Arch(Arch), DoHashes(~0)
+FTWScanner::FTWScanner(FileFd * const GivenOutput, string const &Arch): Arch(Arch), DoHashes(~0)
 {
 {
+   if (GivenOutput == NULL)
+   {
+      Output = new FileFd;
+      Output->OpenDescriptor(STDOUT_FILENO, FileFd::WriteOnly, false);
+   }
+   else
+      Output = GivenOutput;
    ErrorPrinted = false;
    ErrorPrinted = false;
    NoLinkAct = !_config->FindB("APT::FTPArchive::DeLinkAct",true);
    NoLinkAct = !_config->FindB("APT::FTPArchive::DeLinkAct",true);
    ConfigToDoHashes(DoHashes, "APT::FTPArchive");
    ConfigToDoHashes(DoHashes, "APT::FTPArchive");
@@ -331,11 +324,10 @@ bool FTWScanner::Delink(string &FileName,const char *OriginalPath,
 // PackagesWriter::PackagesWriter - Constructor				/*{{{*/
 // PackagesWriter::PackagesWriter - Constructor				/*{{{*/
 // ---------------------------------------------------------------------
 // ---------------------------------------------------------------------
 /* */
 /* */
-PackagesWriter::PackagesWriter(string const &DB,string const &Overrides,string const &ExtOverrides,
+PackagesWriter::PackagesWriter(FileFd * const GivenOutput, string const &DB,string const &Overrides,string const &ExtOverrides,
 			       string const &Arch) :
 			       string const &Arch) :
-   FTWScanner(Arch), Db(DB), Stats(Db.Stats), TransWriter(NULL)
+   FTWScanner(GivenOutput, Arch), Db(DB), Stats(Db.Stats), TransWriter(NULL)
 {
 {
-   Output = stdout;
    SetExts(".deb .udeb");
    SetExts(".deb .udeb");
    DeLinkLimit = 0;
    DeLinkLimit = 0;
 
 
@@ -461,32 +453,32 @@ bool PackagesWriter::DoPackage(string FileName)
    }
    }
 
 
    // This lists all the changes to the fields we are going to make.
    // This lists all the changes to the fields we are going to make.
-   std::vector<TFRewriteData> Changes;
+   std::vector<pkgTagSection::Tag> Changes;
 
 
    std::string Size;
    std::string Size;
    strprintf(Size, "%llu", (unsigned long long) FileSize);
    strprintf(Size, "%llu", (unsigned long long) FileSize);
-   Changes.push_back(SetTFRewriteData("Size", Size.c_str()));
+   Changes.push_back(pkgTagSection::Tag::Rewrite("Size", Size));
 
 
    for (HashStringList::const_iterator hs = Db.HashesList.begin(); hs != Db.HashesList.end(); ++hs)
    for (HashStringList::const_iterator hs = Db.HashesList.begin(); hs != Db.HashesList.end(); ++hs)
    {
    {
       if (hs->HashType() == "MD5Sum")
       if (hs->HashType() == "MD5Sum")
-	 Changes.push_back(SetTFRewriteData("MD5sum", hs->HashValue().c_str()));
+	 Changes.push_back(pkgTagSection::Tag::Rewrite("MD5sum", hs->HashValue()));
       else if (hs->HashType() == "Checksum-FileSize")
       else if (hs->HashType() == "Checksum-FileSize")
 	 continue;
 	 continue;
       else
       else
-	 Changes.push_back(SetTFRewriteData(hs->HashType().c_str(), hs->HashValue().c_str()));
+	 Changes.push_back(pkgTagSection::Tag::Rewrite(hs->HashType(), hs->HashValue()));
    }
    }
-   Changes.push_back(SetTFRewriteData("Filename", NewFileName.c_str()));
-   Changes.push_back(SetTFRewriteData("Priority", OverItem->Priority.c_str()));
-   Changes.push_back(SetTFRewriteData("Status", 0));
-   Changes.push_back(SetTFRewriteData("Optional", 0));
+   Changes.push_back(pkgTagSection::Tag::Rewrite("Filename", NewFileName));
+   Changes.push_back(pkgTagSection::Tag::Rewrite("Priority", OverItem->Priority));
+   Changes.push_back(pkgTagSection::Tag::Remove("Status"));
+   Changes.push_back(pkgTagSection::Tag::Remove("Optional"));
 
 
    string DescriptionMd5;
    string DescriptionMd5;
    if (LongDescription == false) {
    if (LongDescription == false) {
       MD5Summation descmd5;
       MD5Summation descmd5;
       descmd5.Add(desc.c_str());
       descmd5.Add(desc.c_str());
       DescriptionMd5 = descmd5.Result().Value();
       DescriptionMd5 = descmd5.Result().Value();
-      Changes.push_back(SetTFRewriteData("Description-md5", DescriptionMd5.c_str()));
+      Changes.push_back(pkgTagSection::Tag::Rewrite("Description-md5", DescriptionMd5));
       if (TransWriter != NULL)
       if (TransWriter != NULL)
 	 TransWriter->DoPackage(Package, desc, DescriptionMd5);
 	 TransWriter->DoPackage(Package, desc, DescriptionMd5);
    }
    }
@@ -505,7 +497,7 @@ bool PackagesWriter::DoPackage(string FileName)
    }
    }
 
 
    if (NewMaint.empty() == false)
    if (NewMaint.empty() == false)
-      Changes.push_back(SetTFRewriteData("Maintainer", NewMaint.c_str()));
+      Changes.push_back(pkgTagSection::Tag::Rewrite("Maintainer", NewMaint));
 
 
    /* Get rid of the Optional tag. This is an ugly, ugly, ugly hack that
    /* 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
       dpkg-scanpackages does. Well sort of. dpkg-scanpackages just does renaming
@@ -517,19 +509,17 @@ bool PackagesWriter::DoPackage(string FileName)
    {
    {
       if (Tags.FindS("Suggests").empty() == false)
       if (Tags.FindS("Suggests").empty() == false)
 	 OptionalStr = Tags.FindS("Suggests") + ", " + OptionalStr;
 	 OptionalStr = Tags.FindS("Suggests") + ", " + OptionalStr;
-      Changes.push_back(SetTFRewriteData("Suggests", OptionalStr.c_str()));
+      Changes.push_back(pkgTagSection::Tag::Rewrite("Suggests", OptionalStr));
    }
    }
 
 
    for (map<string,string>::const_iterator I = OverItem->FieldOverride.begin();
    for (map<string,string>::const_iterator I = OverItem->FieldOverride.begin();
         I != OverItem->FieldOverride.end(); ++I)
         I != OverItem->FieldOverride.end(); ++I)
-      Changes.push_back(SetTFRewriteData(I->first.c_str(),I->second.c_str()));
-
-   Changes.push_back(SetTFRewriteData( 0, 0));
+      Changes.push_back(pkgTagSection::Tag::Rewrite(I->first, I->second));
 
 
    // Rewrite and store the fields.
    // Rewrite and store the fields.
-   if (TFRewrite(Output,Tags,TFRewritePackageOrder,Changes.data()) == false)
+   if (Tags.Write(*Output, TFRewritePackageOrder, Changes) == false ||
+	 Output->Write("\n", 1) == false)
       return false;
       return false;
-   fprintf(Output,"\n");
 
 
    return Db.Finish();
    return Db.Finish();
 }
 }
@@ -539,14 +529,13 @@ bool PackagesWriter::DoPackage(string FileName)
 // ---------------------------------------------------------------------
 // ---------------------------------------------------------------------
 /* Create a Translation-Master file for this Packages file */
 /* Create a Translation-Master file for this Packages file */
 TranslationWriter::TranslationWriter(string const &File, string const &TransCompress,
 TranslationWriter::TranslationWriter(string const &File, string const &TransCompress,
-					mode_t const &Permissions) : Output(NULL),
-							RefCounter(0)
+					mode_t const &Permissions) : RefCounter(0)
 {
 {
    if (File.empty() == true)
    if (File.empty() == true)
       return;
       return;
 
 
    Comp = new MultiCompress(File, TransCompress, Permissions);
    Comp = new MultiCompress(File, TransCompress, Permissions);
-   Output = Comp->Input;
+   Output = &Comp->Input;
 }
 }
 									/*}}}*/
 									/*}}}*/
 // TranslationWriter::DoPackage - Process a single package		/*{{{*/
 // TranslationWriter::DoPackage - Process a single package		/*{{{*/
@@ -565,8 +554,10 @@ bool TranslationWriter::DoPackage(string const &Pkg, string const &Desc,
    if (Included.find(Record) != Included.end())
    if (Included.find(Record) != Included.end())
       return true;
       return true;
 
 
-   fprintf(Output, "Package: %s\nDescription-md5: %s\nDescription-en: %s\n",
+   std::string out;
+   strprintf(out, "Package: %s\nDescription-md5: %s\nDescription-en: %s\n",
 	   Pkg.c_str(), MD5.c_str(), Desc.c_str());
 	   Pkg.c_str(), MD5.c_str(), Desc.c_str());
+   Output->Write(out.c_str(), out.length());
 
 
    Included.insert(Record);
    Included.insert(Record);
    return true;
    return true;
@@ -587,11 +578,10 @@ TranslationWriter::~TranslationWriter()
 // SourcesWriter::SourcesWriter - Constructor				/*{{{*/
 // SourcesWriter::SourcesWriter - Constructor				/*{{{*/
 // ---------------------------------------------------------------------
 // ---------------------------------------------------------------------
 /* */
 /* */
-SourcesWriter::SourcesWriter(string const &DB, string const &BOverrides,string const &SOverrides,
+SourcesWriter::SourcesWriter(FileFd * const GivenOutput, string const &DB, string const &BOverrides,string const &SOverrides,
 			     string const &ExtOverrides) :
 			     string const &ExtOverrides) :
-   Db(DB), Stats(Db.Stats)
+   FTWScanner(GivenOutput), Db(DB), Stats(Db.Stats)
 {
 {
-   Output = stdout;
    AddPattern("*.dsc");
    AddPattern("*.dsc");
    DeLinkLimit = 0;
    DeLinkLimit = 0;
    Buffer = 0;
    Buffer = 0;
@@ -620,15 +610,16 @@ SourcesWriter::SourcesWriter(string const &DB, string const &BOverrides,string c
 }
 }
 									/*}}}*/
 									/*}}}*/
 // SourcesWriter::DoPackage - Process a single package			/*{{{*/
 // SourcesWriter::DoPackage - Process a single package			/*{{{*/
-static std::ostream& addDscHash(std::ostream &out, unsigned int const DoHashes,
+static std::string getDscHash(unsigned int const DoHashes,
       Hashes::SupportedHashes const DoIt, pkgTagSection &Tags, char const * const FieldName,
       Hashes::SupportedHashes const DoIt, pkgTagSection &Tags, char const * const FieldName,
       HashString const * const Hash, unsigned long long Size, std::string FileName)
       HashString const * const Hash, unsigned long long Size, std::string FileName)
 {
 {
    if ((DoHashes & DoIt) != DoIt || Tags.Exists(FieldName) == false || Hash == NULL)
    if ((DoHashes & DoIt) != DoIt || Tags.Exists(FieldName) == false || Hash == NULL)
-      return out;
+      return "";
+   std::ostringstream out;
    out << "\n " << Hash->HashValue() << " " << Size << " " << FileName
    out << "\n " << Hash->HashValue() << " " << Size << " " << FileName
       << "\n " << Tags.FindS(FieldName);
       << "\n " << Tags.FindS(FieldName);
-   return out;
+   return out.str();
 }
 }
 bool SourcesWriter::DoPackage(string FileName)
 bool SourcesWriter::DoPackage(string FileName)
 {
 {
@@ -721,16 +712,10 @@ bool SourcesWriter::DoPackage(string FileName)
 
 
    // Add the dsc to the files hash list
    // Add the dsc to the files hash list
    string const strippedName = flNotDir(FileName);
    string const strippedName = flNotDir(FileName);
-   std::ostringstream ostreamFiles;
-   addDscHash(ostreamFiles, DoHashes, Hashes::MD5SUM, Tags, "Files", Db.HashesList.find("MD5Sum"), St.st_size, strippedName);
-   string const Files = ostreamFiles.str();
-
-   std::ostringstream ostreamSha1;
-   addDscHash(ostreamSha1, DoHashes, Hashes::SHA1SUM, Tags, "Checksums-Sha1", Db.HashesList.find("SHA1"), St.st_size, strippedName);
-   std::ostringstream ostreamSha256;
-   addDscHash(ostreamSha256, DoHashes, Hashes::SHA256SUM, Tags, "Checksums-Sha256", Db.HashesList.find("SHA256"), St.st_size, strippedName);
-   std::ostringstream ostreamSha512;
-   addDscHash(ostreamSha512, DoHashes, Hashes::SHA512SUM, Tags, "Checksums-Sha512", Db.HashesList.find("SHA512"), St.st_size, strippedName);
+   std::string const Files = getDscHash(DoHashes, Hashes::MD5SUM, Tags, "Files", Db.HashesList.find("MD5Sum"), St.st_size, strippedName);
+   std::string ChecksumsSha1 = getDscHash(DoHashes, Hashes::SHA1SUM, Tags, "Checksums-Sha1", Db.HashesList.find("SHA1"), St.st_size, strippedName);
+   std::string ChecksumsSha256 = getDscHash(DoHashes, Hashes::SHA256SUM, Tags, "Checksums-Sha256", Db.HashesList.find("SHA256"), St.st_size, strippedName);
+   std::string ChecksumsSha512 = getDscHash(DoHashes, Hashes::SHA512SUM, Tags, "Checksums-Sha512", Db.HashesList.find("SHA512"), St.st_size, strippedName);
 
 
    // Strip the DirStrip prefix from the FileName and add the PathPrefix
    // Strip the DirStrip prefix from the FileName and add the PathPrefix
    string NewFileName;
    string NewFileName;
@@ -752,7 +737,7 @@ bool SourcesWriter::DoPackage(string FileName)
    char *RealPath = NULL;
    char *RealPath = NULL;
    for (;isspace(*C); C++);
    for (;isspace(*C); C++);
    while (*C != 0)
    while (*C != 0)
-   {   
+   {
       // Parse each of the elements
       // Parse each of the elements
       if (ParseQuoteWord(C,ParseJnk) == false ||
       if (ParseQuoteWord(C,ParseJnk) == false ||
 	  ParseQuoteWord(C,ParseJnk) == false ||
 	  ParseQuoteWord(C,ParseJnk) == false ||
@@ -782,21 +767,21 @@ bool SourcesWriter::DoPackage(string FileName)
 	    if (hs->HashType() == "MD5Sum" || hs->HashType() == "Checksum-FileSize")
 	    if (hs->HashType() == "MD5Sum" || hs->HashType() == "Checksum-FileSize")
 	       continue;
 	       continue;
 	    char const * fieldname;
 	    char const * fieldname;
-	    std::ostream * out;
+	    std::string * out;
 	    if (hs->HashType() == "SHA1")
 	    if (hs->HashType() == "SHA1")
 	    {
 	    {
 	       fieldname = "Checksums-Sha1";
 	       fieldname = "Checksums-Sha1";
-	       out = &ostreamSha1;
+	       out = &ChecksumsSha1;
 	    }
 	    }
 	    else if (hs->HashType() == "SHA256")
 	    else if (hs->HashType() == "SHA256")
 	    {
 	    {
 	       fieldname = "Checksums-Sha256";
 	       fieldname = "Checksums-Sha256";
-	       out = &ostreamSha256;
+	       out = &ChecksumsSha256;
 	    }
 	    }
 	    else if (hs->HashType() == "SHA512")
 	    else if (hs->HashType() == "SHA512")
 	    {
 	    {
 	       fieldname = "Checksums-Sha512";
 	       fieldname = "Checksums-Sha512";
-	       out = &ostreamSha512;
+	       out = &ChecksumsSha512;
 	    }
 	    }
 	    else
 	    else
 	    {
 	    {
@@ -805,10 +790,12 @@ bool SourcesWriter::DoPackage(string FileName)
 	    }
 	    }
 	    if (Tags.Exists(fieldname) == true)
 	    if (Tags.Exists(fieldname) == true)
 	       continue;
 	       continue;
-	    (*out) << "\n " << hs->HashValue() << " " << Db.GetFileSize() << " " << ParseJnk;
+	    std::ostringstream streamout;
+	    streamout << "\n " << hs->HashValue() << " " << Db.GetFileSize() << " " << ParseJnk;
+	    out->append(streamout.str());
 	 }
 	 }
 
 
-	 // write back the GetFileInfo() stats data 
+	 // write back the GetFileInfo() stats data
 	 Db.Finish();
 	 Db.Finish();
       }
       }
 
 
@@ -829,54 +816,48 @@ bool SourcesWriter::DoPackage(string FileName)
    if (Directory.length() > 2)
    if (Directory.length() > 2)
       Directory.erase(Directory.end()-1);
       Directory.erase(Directory.end()-1);
 
 
-   string const ChecksumsSha1 = ostreamSha1.str();
-   string const ChecksumsSha256 = ostreamSha256.str();
-   string const ChecksumsSha512 = ostreamSha512.str();
-
    // This lists all the changes to the fields we are going to make.
    // This lists all the changes to the fields we are going to make.
    // (5 hardcoded + checksums + maintainer + end marker)
    // (5 hardcoded + checksums + maintainer + end marker)
-   std::vector<TFRewriteData> Changes;
+   std::vector<pkgTagSection::Tag> Changes;
 
 
-   Changes.push_back(SetTFRewriteData("Source", 0));
-   Changes.push_back(SetTFRewriteData("Package",Package.c_str()));
+   Changes.push_back(pkgTagSection::Tag::Remove("Source"));
+   Changes.push_back(pkgTagSection::Tag::Rewrite("Package", Package));
    if (Files.empty() == false)
    if (Files.empty() == false)
-      Changes.push_back(SetTFRewriteData("Files",Files.c_str()));
+      Changes.push_back(pkgTagSection::Tag::Rewrite("Files", Files));
    if (ChecksumsSha1.empty() == false)
    if (ChecksumsSha1.empty() == false)
-      Changes.push_back(SetTFRewriteData("Checksums-Sha1",ChecksumsSha1.c_str()));
+      Changes.push_back(pkgTagSection::Tag::Rewrite("Checksums-Sha1", ChecksumsSha1));
    if (ChecksumsSha256.empty() == false)
    if (ChecksumsSha256.empty() == false)
-      Changes.push_back(SetTFRewriteData("Checksums-Sha256",ChecksumsSha256.c_str()));
+      Changes.push_back(pkgTagSection::Tag::Rewrite("Checksums-Sha256", ChecksumsSha256));
    if (ChecksumsSha512.empty() == false)
    if (ChecksumsSha512.empty() == false)
-      Changes.push_back(SetTFRewriteData("Checksums-Sha512",ChecksumsSha512.c_str()));
+      Changes.push_back(pkgTagSection::Tag::Rewrite("Checksums-Sha512", ChecksumsSha512));
    if (Directory != "./")
    if (Directory != "./")
-      Changes.push_back(SetTFRewriteData("Directory",Directory.c_str()));
-   Changes.push_back(SetTFRewriteData("Priority",BestPrio.c_str()));
-   Changes.push_back(SetTFRewriteData("Status",0));
+      Changes.push_back(pkgTagSection::Tag::Rewrite("Directory", Directory));
+   Changes.push_back(pkgTagSection::Tag::Rewrite("Priority", BestPrio));
+   Changes.push_back(pkgTagSection::Tag::Remove("Status"));
 
 
    // Rewrite the maintainer field if necessary
    // Rewrite the maintainer field if necessary
    bool MaintFailed;
    bool MaintFailed;
-   string NewMaint = OverItem->SwapMaint(Tags.FindS("Maintainer"),MaintFailed);
+   string NewMaint = OverItem->SwapMaint(Tags.FindS("Maintainer"), MaintFailed);
    if (MaintFailed == true)
    if (MaintFailed == true)
    {
    {
       if (NoOverride == false)
       if (NoOverride == false)
       {
       {
-	 NewLine(1);	 
+	 NewLine(1);
 	 ioprintf(c1out, _("  %s maintainer is %s not %s\n"), Package.c_str(),
 	 ioprintf(c1out, _("  %s maintainer is %s not %s\n"), Package.c_str(),
 	       Tags.FindS("Maintainer").c_str(), OverItem->OldMaint.c_str());
 	       Tags.FindS("Maintainer").c_str(), OverItem->OldMaint.c_str());
-      }      
+      }
    }
    }
    if (NewMaint.empty() == false)
    if (NewMaint.empty() == false)
-      Changes.push_back(SetTFRewriteData("Maintainer", NewMaint.c_str()));
-   
-   for (map<string,string>::const_iterator I = SOverItem->FieldOverride.begin(); 
+      Changes.push_back(pkgTagSection::Tag::Rewrite("Maintainer", NewMaint.c_str()));
+
+   for (map<string,string>::const_iterator I = SOverItem->FieldOverride.begin();
         I != SOverItem->FieldOverride.end(); ++I)
         I != SOverItem->FieldOverride.end(); ++I)
-      Changes.push_back(SetTFRewriteData(I->first.c_str(),I->second.c_str()));
+      Changes.push_back(pkgTagSection::Tag::Rewrite(I->first, I->second));
 
 
-   Changes.push_back(SetTFRewriteData(0, 0));
-      
    // Rewrite and store the fields.
    // Rewrite and store the fields.
-   if (TFRewrite(Output,Tags,TFRewriteSourceOrder,Changes.data()) == false)
+   if (Tags.Write(*Output, TFRewriteSourceOrder, Changes) == false ||
+	 Output->Write("\n", 1) == false)
       return false;
       return false;
-   fprintf(Output,"\n");
 
 
    Stats.Packages++;
    Stats.Packages++;
    
    
@@ -887,12 +868,11 @@ bool SourcesWriter::DoPackage(string FileName)
 // ContentsWriter::ContentsWriter - Constructor				/*{{{*/
 // ContentsWriter::ContentsWriter - Constructor				/*{{{*/
 // ---------------------------------------------------------------------
 // ---------------------------------------------------------------------
 /* */
 /* */
-ContentsWriter::ContentsWriter(string const &DB, string const &Arch) :
-		    FTWScanner(Arch), Db(DB), Stats(Db.Stats)
+ContentsWriter::ContentsWriter(FileFd * const GivenOutput, string const &DB, string const &Arch) :
+		    FTWScanner(GivenOutput, Arch), Db(DB), Stats(Db.Stats)
 
 
 {
 {
    SetExts(".deb");
    SetExts(".deb");
-   Output = stdout;
 }
 }
 									/*}}}*/
 									/*}}}*/
 // ContentsWriter::DoPackage - Process a single package			/*{{{*/
 // ContentsWriter::DoPackage - Process a single package			/*{{{*/
@@ -974,7 +954,7 @@ bool ContentsWriter::ReadFromPkgs(string const &PkgFile,string const &PkgCompres
 // ReleaseWriter::ReleaseWriter - Constructor				/*{{{*/
 // ReleaseWriter::ReleaseWriter - Constructor				/*{{{*/
 // ---------------------------------------------------------------------
 // ---------------------------------------------------------------------
 /* */
 /* */
-ReleaseWriter::ReleaseWriter(string const &/*DB*/)
+ReleaseWriter::ReleaseWriter(FileFd * const GivenOutput, string const &/*DB*/) : FTWScanner(GivenOutput)
 {
 {
    if (_config->FindB("APT::FTPArchive::Release::Default-Patterns", true) == true)
    if (_config->FindB("APT::FTPArchive::Release::Default-Patterns", true) == true)
    {
    {
@@ -996,7 +976,6 @@ ReleaseWriter::ReleaseWriter(string const &/*DB*/)
    }
    }
    AddPatterns(_config->FindVector("APT::FTPArchive::Release::Patterns"));
    AddPatterns(_config->FindVector("APT::FTPArchive::Release::Patterns"));
 
 
-   Output = stdout;
    time_t const now = time(NULL);
    time_t const now = time(NULL);
 
 
    setlocale(LC_TIME, "C");
    setlocale(LC_TIME, "C");
@@ -1040,7 +1019,8 @@ ReleaseWriter::ReleaseWriter(string const &/*DB*/)
       if (Value == "")
       if (Value == "")
          continue;
          continue;
 
 
-      fprintf(Output, "%s: %s\n", (*I).first.c_str(), Value.c_str());
+      std::string const out = I->first + ": " + Value + "\n";
+      Output->Write(out.c_str(), out.length());
    }
    }
 
 
    ConfigToDoHashes(DoHashes, "APT::FTPArchive::Release");
    ConfigToDoHashes(DoHashes, "APT::FTPArchive::Release");
@@ -1087,29 +1067,35 @@ bool ReleaseWriter::DoPackage(string FileName)
 									/*}}}*/
 									/*}}}*/
 // ReleaseWriter::Finish - Output the checksums				/*{{{*/
 // ReleaseWriter::Finish - Output the checksums				/*{{{*/
 // ---------------------------------------------------------------------
 // ---------------------------------------------------------------------
-static void printChecksumTypeRecord(FILE * const Output, char const * const Type, map<string, ReleaseWriter::CheckSum> const &CheckSums)
+static void printChecksumTypeRecord(FileFd &Output, char const * const Type, map<string, ReleaseWriter::CheckSum> const &CheckSums)
 {
 {
-      fprintf(Output, "%s:\n", Type);
-      for(map<string,ReleaseWriter::CheckSum>::const_iterator I = CheckSums.begin();
-	  I != CheckSums.end(); ++I)
-      {
-	 HashString const * const hs = I->second.Hashes.find(Type);
-	 if (hs == NULL)
-	    continue;
-	 fprintf(Output, " %s %16llu %s\n",
-		 hs->HashValue().c_str(),
-		 (*I).second.size,
-		 (*I).first.c_str());
-      }
+   {
+      std::string out;
+      strprintf(out, "%s:\n", Type);
+      Output.Write(out.c_str(), out.length());
+   }
+   for(map<string,ReleaseWriter::CheckSum>::const_iterator I = CheckSums.begin();
+	 I != CheckSums.end(); ++I)
+   {
+      HashString const * const hs = I->second.Hashes.find(Type);
+      if (hs == NULL)
+	 continue;
+      std::string out;
+      strprintf(out, " %s %16llu %s\n",
+	    hs->HashValue().c_str(),
+	    (*I).second.size,
+	    (*I).first.c_str());
+      Output.Write(out.c_str(), out.length());
+   }
 }
 }
 void ReleaseWriter::Finish()
 void ReleaseWriter::Finish()
 {
 {
    if ((DoHashes & Hashes::MD5SUM) == Hashes::MD5SUM)
    if ((DoHashes & Hashes::MD5SUM) == Hashes::MD5SUM)
-      printChecksumTypeRecord(Output, "MD5Sum", CheckSums);
+      printChecksumTypeRecord(*Output, "MD5Sum", CheckSums);
    if ((DoHashes & Hashes::SHA1SUM) == Hashes::SHA1SUM)
    if ((DoHashes & Hashes::SHA1SUM) == Hashes::SHA1SUM)
-      printChecksumTypeRecord(Output, "SHA1", CheckSums);
+      printChecksumTypeRecord(*Output, "SHA1", CheckSums);
    if ((DoHashes & Hashes::SHA256SUM) == Hashes::SHA256SUM)
    if ((DoHashes & Hashes::SHA256SUM) == Hashes::SHA256SUM)
-      printChecksumTypeRecord(Output, "SHA256", CheckSums);
+      printChecksumTypeRecord(*Output, "SHA256", CheckSums);
    if ((DoHashes & Hashes::SHA512SUM) == Hashes::SHA512SUM)
    if ((DoHashes & Hashes::SHA512SUM) == Hashes::SHA512SUM)
-      printChecksumTypeRecord(Output, "SHA512", CheckSums);
+      printChecksumTypeRecord(*Output, "SHA512", CheckSums);
 }
 }

+ 21 - 24
ftparchive/writer.h

@@ -42,10 +42,10 @@ class FTWScanner
    string Arch;
    string Arch;
    const char *OriginalPath;
    const char *OriginalPath;
    bool ErrorPrinted;
    bool ErrorPrinted;
-   
+
    // Stuff for the delinker
    // Stuff for the delinker
    bool NoLinkAct;
    bool NoLinkAct;
-   
+
    static FTWScanner *Owner;
    static FTWScanner *Owner;
    static int ScannerFTW(const char *File,const struct stat *sb,int Flag);
    static int ScannerFTW(const char *File,const struct stat *sb,int Flag);
    static int ScannerFile(const char *File, bool const &ReadLink);
    static int ScannerFile(const char *File, bool const &ReadLink);
@@ -59,10 +59,11 @@ class FTWScanner
       {
       {
 	 c1out << endl;
 	 c1out << endl;
 	 ErrorPrinted = true;
 	 ErrorPrinted = true;
-      }	 
+      }
    }
    }
-   
+
    public:
    public:
+   FileFd *Output;
    unsigned int DoHashes;
    unsigned int DoHashes;
 
 
    unsigned long DeLinkLimit;
    unsigned long DeLinkLimit;
@@ -76,8 +77,8 @@ class FTWScanner
    void AddPattern(char const *Pattern) { Patterns.push_back(Pattern); };
    void AddPattern(char const *Pattern) { Patterns.push_back(Pattern); };
    void AddPatterns(std::vector<std::string> const &patterns) { Patterns.insert(Patterns.end(), patterns.begin(), patterns.end()); };
    void AddPatterns(std::vector<std::string> const &patterns) { Patterns.insert(Patterns.end(), patterns.begin(), patterns.end()); };
    bool SetExts(string const &Vals);
    bool SetExts(string const &Vals);
-      
-   FTWScanner(string const &Arch = string());
+
+   FTWScanner(FileFd * const Output, string const &Arch = string());
    virtual ~FTWScanner() {};
    virtual ~FTWScanner() {};
 };
 };
 
 
@@ -86,9 +87,9 @@ class MultiCompress;
 class TranslationWriter
 class TranslationWriter
 {
 {
    MultiCompress *Comp;
    MultiCompress *Comp;
-   FILE *Output;
    std::set<string> Included;
    std::set<string> Included;
    unsigned short RefCounter;
    unsigned short RefCounter;
+   FileFd *Output;
 
 
    public:
    public:
    void IncreaseRefCounter() { ++RefCounter; };
    void IncreaseRefCounter() { ++RefCounter; };
@@ -97,7 +98,7 @@ class TranslationWriter
    bool DoPackage(string const &Pkg, string const &Desc, string const &MD5);
    bool DoPackage(string const &Pkg, string const &Desc, string const &MD5);
 
 
    TranslationWriter(string const &File, string const &TransCompress, mode_t const &Permissions);
    TranslationWriter(string const &File, string const &TransCompress, mode_t const &Permissions);
-   TranslationWriter() : Comp(NULL), Output(NULL), RefCounter(0) {};
+   TranslationWriter() : Comp(NULL), RefCounter(0) {};
    ~TranslationWriter();
    ~TranslationWriter();
 };
 };
 
 
@@ -105,7 +106,7 @@ class PackagesWriter : public FTWScanner
 {
 {
    Override Over;
    Override Over;
    CacheDB Db;
    CacheDB Db;
-      
+
    public:
    public:
 
 
    // Some flags
    // Some flags
@@ -117,7 +118,6 @@ class PackagesWriter : public FTWScanner
    // General options
    // General options
    string PathPrefix;
    string PathPrefix;
    string DirStrip;
    string DirStrip;
-   FILE *Output;
    struct CacheDB::Stats &Stats;
    struct CacheDB::Stats &Stats;
    TranslationWriter *TransWriter;
    TranslationWriter *TransWriter;
 
 
@@ -126,7 +126,7 @@ class PackagesWriter : public FTWScanner
       {return Over.ReadExtraOverride(File);};
       {return Over.ReadExtraOverride(File);};
    virtual bool DoPackage(string FileName);
    virtual bool DoPackage(string FileName);
 
 
-   PackagesWriter(string const &DB,
+   PackagesWriter(FileFd * const Output, string const &DB,
                   string const &Overrides,
                   string const &Overrides,
                   string const &ExtOverrides = "",
                   string const &ExtOverrides = "",
 		  string const &Arch = "");
 		  string const &Arch = "");
@@ -136,25 +136,24 @@ class PackagesWriter : public FTWScanner
 class ContentsWriter : public FTWScanner
 class ContentsWriter : public FTWScanner
 {
 {
    CacheDB Db;
    CacheDB Db;
-   
+
    GenContents Gen;
    GenContents Gen;
-   
+
    public:
    public:
 
 
    // General options
    // General options
-   FILE *Output;
    struct CacheDB::Stats &Stats;
    struct CacheDB::Stats &Stats;
    string Prefix;
    string Prefix;
-   
+
    bool DoPackage(string FileName,string Package);
    bool DoPackage(string FileName,string Package);
    virtual bool DoPackage(string FileName) 
    virtual bool DoPackage(string FileName) 
              {return DoPackage(FileName,string());};
              {return DoPackage(FileName,string());};
    bool ReadFromPkgs(string const &PkgFile,string const &PkgCompress);
    bool ReadFromPkgs(string const &PkgFile,string const &PkgCompress);
 
 
-   void Finish() {Gen.Print(Output);};
+   void Finish() {Gen.Print(*Output);};
    inline bool ReadyDB(string const &DB) {return Db.ReadyDB(DB);};
    inline bool ReadyDB(string const &DB) {return Db.ReadyDB(DB);};
-   
-   ContentsWriter(string const &DB, string const &Arch = string());
+
+   ContentsWriter(FileFd * const Output, string const &DB, string const &Arch = string());
    virtual ~ContentsWriter() {};
    virtual ~ContentsWriter() {};
 };
 };
 
 
@@ -165,21 +164,20 @@ class SourcesWriter : public FTWScanner
    Override SOver;
    Override SOver;
    char *Buffer;
    char *Buffer;
    unsigned long long BufSize;
    unsigned long long BufSize;
-   
+
    public:
    public:
 
 
    bool NoOverride;
    bool NoOverride;
    bool DoAlwaysStat;
    bool DoAlwaysStat;
-   
+
    // General options
    // General options
    string PathPrefix;
    string PathPrefix;
    string DirStrip;
    string DirStrip;
-   FILE *Output;
    struct CacheDB::Stats &Stats;
    struct CacheDB::Stats &Stats;
 
 
    virtual bool DoPackage(string FileName);
    virtual bool DoPackage(string FileName);
 
 
-   SourcesWriter(string const &DB,string const &BOverrides,string const &SOverrides,
+   SourcesWriter(FileFd * const Output, string const &DB,string const &BOverrides,string const &SOverrides,
 		 string const &ExtOverrides=string());
 		 string const &ExtOverrides=string());
    virtual ~SourcesWriter() {free(Buffer);};
    virtual ~SourcesWriter() {free(Buffer);};
 };
 };
@@ -187,11 +185,10 @@ class SourcesWriter : public FTWScanner
 class ReleaseWriter : public FTWScanner
 class ReleaseWriter : public FTWScanner
 {
 {
 public:
 public:
-   ReleaseWriter(string const &DB);
+   ReleaseWriter(FileFd * const Output, string const &DB);
    virtual bool DoPackage(string FileName);
    virtual bool DoPackage(string FileName);
    void Finish();
    void Finish();
 
 
-   FILE *Output;
    // General options
    // General options
    string PathPrefix;
    string PathPrefix;
    string DirStrip;
    string DirStrip;

+ 2 - 2
test/integration/test-apt-cli-show

@@ -25,11 +25,11 @@ APTARCHIVE=$(readlink -f ./aptarchive)
 # note that we do not display Description-md5 with the "apt" cmd
 # note that we do not display Description-md5 with the "apt" cmd
 # and also show some additional fields that are calculated
 # and also show some additional fields that are calculated
 testsuccessequal "Package: foo
 testsuccessequal "Package: foo
+Version: 1.0
 Priority: optional
 Priority: optional
 Section: other
 Section: other
-Installed-Size: 43.0 kB
 Maintainer: Joe Sixpack <joe@example.org>
 Maintainer: Joe Sixpack <joe@example.org>
-Version: 1.0
+Installed-Size: 43.0 kB
 Download-Size: unknown
 Download-Size: unknown
 APT-Manual-Installed: yes
 APT-Manual-Installed: yes
 APT-Sources: file:$APTARCHIVE/ unstable/main i386 Packages
 APT-Sources: file:$APTARCHIVE/ unstable/main i386 Packages

+ 1 - 1
test/libapt/indexcopytosourcelist_test.cc

@@ -16,7 +16,7 @@ class NoCopy : public IndexCopy {
 	 return Path;
 	 return Path;
       }
       }
       bool GetFile(std::string &/*Filename*/, unsigned long long &/*Size*/) { return false; }
       bool GetFile(std::string &/*Filename*/, unsigned long long &/*Size*/) { return false; }
-      bool RewriteEntry(FILE * /*Target*/, std::string /*File*/) { return false; }
+      bool RewriteEntry(FileFd & /*Target*/, std::string const &/*File*/) { return false; }
       const char *GetFileName() { return NULL; }
       const char *GetFileName() { return NULL; }
       const char *Type() { return NULL; }
       const char *Type() { return NULL; }
 
 

+ 270 - 0
test/libapt/tagsection_test.cc

@@ -0,0 +1,270 @@
+#include <config.h>
+
+#include <apt-pkg/fileutl.h>
+#include <apt-pkg/tagfile.h>
+
+#include <string>
+#include <sstream>
+
+#include <gtest/gtest.h>
+
+#include "file-helpers.h"
+
+std::string packageValue = "aaaa";
+std::string typoValue = "aa\n"
+   " .\n"
+   " cc";
+std::string typoRawValue = "\n " + typoValue;
+std::string overrideValue = "1";
+/*
+   std::cerr << "FILECONTENT: »";
+   char buffer[3000];
+   while (fd.ReadLine(buffer, sizeof(buffer)))
+      std::cerr << buffer;
+   std::cerr << "«" << std::endl;;
+*/
+
+void setupTestcaseStart(FileFd &fd, pkgTagSection &section, std::string &content)
+{
+   createTemporaryFile("writesection", fd, NULL, NULL);
+   content = "Package: " + packageValue + "\n"
+      "TypoA:\n " + typoValue + "\n"
+      "Override: " + overrideValue + "\n"
+      "Override-Backup: " + overrideValue + "\n"
+      "\n";
+   EXPECT_TRUE(section.Scan(content.c_str(), content.length(), true));
+   EXPECT_TRUE(section.Exists("Package"));
+   EXPECT_TRUE(section.Exists("TypoA"));
+   EXPECT_TRUE(section.Exists("Override"));
+   EXPECT_TRUE(section.Exists("Override-Backup"));
+   EXPECT_FALSE(section.Exists("TypoB"));
+   EXPECT_EQ(packageValue, section.FindS("Package"));
+   EXPECT_EQ(typoValue, section.FindS("TypoA"));
+   EXPECT_EQ(typoRawValue, section.FindRawS("TypoA"));
+   EXPECT_EQ(1, section.FindI("Override"));
+   EXPECT_EQ(1, section.FindI("Override-Backup"));
+   EXPECT_EQ(4, section.Count());
+}
+TEST(TagSectionTest,WriteUnmodified)
+{
+   FileFd fd;
+   pkgTagSection section;
+   std::string content;
+   setupTestcaseStart(fd, section, content);
+   EXPECT_TRUE(section.Write(fd));
+   EXPECT_TRUE(fd.Seek(0));
+   pkgTagFile tfile(&fd);
+   ASSERT_TRUE(tfile.Step(section));
+   EXPECT_TRUE(section.Exists("Package"));
+   EXPECT_TRUE(section.Exists("TypoA"));
+   EXPECT_TRUE(section.Exists("Override"));
+   EXPECT_TRUE(section.Exists("Override-Backup"));
+   EXPECT_FALSE(section.Exists("TypoB"));
+   EXPECT_EQ(packageValue, section.FindS("Package"));
+   EXPECT_EQ(typoValue, section.FindS("TypoA"));
+   EXPECT_EQ(1, section.FindI("Override"));
+   EXPECT_EQ(1, section.FindI("Override-Backup"));
+   EXPECT_EQ(4, section.Count());
+}
+TEST(TagSectionTest,WriteUnmodifiedOrder)
+{
+   FileFd fd;
+   pkgTagSection section;
+   std::string content;
+   setupTestcaseStart(fd, section, content);
+   char const * const order[] = { "Package", "TypoA", "Override", NULL };
+   EXPECT_TRUE(section.Write(fd, order));
+   EXPECT_TRUE(fd.Seek(0));
+   pkgTagFile tfile(&fd);
+   ASSERT_TRUE(tfile.Step(section));
+   EXPECT_TRUE(section.Exists("Package"));
+   EXPECT_TRUE(section.Exists("TypoA"));
+   EXPECT_TRUE(section.Exists("Override"));
+   EXPECT_TRUE(section.Exists("Override-Backup"));
+   EXPECT_FALSE(section.Exists("TypoB"));
+   EXPECT_EQ(packageValue, section.FindS("Package"));
+   EXPECT_EQ(typoValue, section.FindS("TypoA"));
+   EXPECT_EQ(1, section.FindI("Override"));
+   EXPECT_EQ(1, section.FindI("Override-Backup"));
+   EXPECT_EQ(4, section.Count());
+}
+TEST(TagSectionTest,WriteUnmodifiedOrderReversed)
+{
+   FileFd fd;
+   pkgTagSection section;
+   std::string content;
+   setupTestcaseStart(fd, section, content);
+   char const * const order[] = { "Override", "TypoA", "Package", NULL };
+   EXPECT_TRUE(section.Write(fd, order));
+   EXPECT_TRUE(fd.Seek(0));
+   pkgTagFile tfile(&fd);
+   ASSERT_TRUE(tfile.Step(section));
+   EXPECT_TRUE(section.Exists("Package"));
+   EXPECT_TRUE(section.Exists("TypoA"));
+   EXPECT_TRUE(section.Exists("Override"));
+   EXPECT_TRUE(section.Exists("Override-Backup"));
+   EXPECT_FALSE(section.Exists("TypoB"));
+   EXPECT_EQ(packageValue, section.FindS("Package"));
+   EXPECT_EQ(typoValue, section.FindS("TypoA"));
+   EXPECT_EQ(1, section.FindI("Override"));
+   EXPECT_EQ(1, section.FindI("Override-Backup"));
+   EXPECT_EQ(4, section.Count());
+}
+TEST(TagSectionTest,WriteUnmodifiedOrderNotAll)
+{
+   FileFd fd;
+   pkgTagSection section;
+   std::string content;
+   setupTestcaseStart(fd, section, content);
+   char const * const order[] = { "Override", NULL };
+   EXPECT_TRUE(section.Write(fd, order));
+   EXPECT_TRUE(fd.Seek(0));
+   pkgTagFile tfile(&fd);
+   ASSERT_TRUE(tfile.Step(section));
+   EXPECT_TRUE(section.Exists("Package"));
+   EXPECT_TRUE(section.Exists("TypoA"));
+   EXPECT_TRUE(section.Exists("Override"));
+   EXPECT_TRUE(section.Exists("Override-Backup"));
+   EXPECT_FALSE(section.Exists("TypoB"));
+   EXPECT_EQ(packageValue, section.FindS("Package"));
+   EXPECT_EQ(typoValue, section.FindS("TypoA"));
+   EXPECT_EQ(1, section.FindI("Override"));
+   EXPECT_EQ(1, section.FindI("Override-Backup"));
+   EXPECT_EQ(4, section.Count());
+}
+TEST(TagSectionTest,WriteNoOrderRename)
+{
+   FileFd fd;
+   pkgTagSection section;
+   std::string content;
+   setupTestcaseStart(fd, section, content);
+   std::vector<pkgTagSection::Tag> rewrite;
+   rewrite.push_back(pkgTagSection::Tag::Rename("TypoA", "TypoB"));
+   EXPECT_TRUE(section.Write(fd, NULL, rewrite));
+   EXPECT_TRUE(fd.Seek(0));
+   pkgTagFile tfile(&fd);
+   ASSERT_TRUE(tfile.Step(section));
+   EXPECT_TRUE(section.Exists("Package"));
+   EXPECT_FALSE(section.Exists("TypoA"));
+   EXPECT_TRUE(section.Exists("TypoB"));
+   EXPECT_TRUE(section.Exists("Override"));
+   EXPECT_TRUE(section.Exists("Override-Backup"));
+   EXPECT_EQ(packageValue, section.FindS("Package"));
+   EXPECT_EQ(typoValue, section.FindS("TypoB"));
+   EXPECT_EQ(1, section.FindI("Override"));
+   EXPECT_EQ(1, section.FindI("Override-Backup"));
+   EXPECT_EQ(4, section.Count());
+}
+TEST(TagSectionTest,WriteNoOrderRemove)
+{
+   FileFd fd;
+   pkgTagSection section;
+   std::string content;
+   setupTestcaseStart(fd, section, content);
+   std::vector<pkgTagSection::Tag> rewrite;
+   rewrite.push_back(pkgTagSection::Tag::Remove("TypoA"));
+   rewrite.push_back(pkgTagSection::Tag::Rewrite("Override", ""));
+   EXPECT_TRUE(section.Write(fd, NULL, rewrite));
+   EXPECT_TRUE(fd.Seek(0));
+   pkgTagFile tfile(&fd);
+   ASSERT_TRUE(tfile.Step(section));
+   EXPECT_TRUE(section.Exists("Package"));
+   EXPECT_FALSE(section.Exists("TypoA"));
+   EXPECT_FALSE(section.Exists("TypoB"));
+   EXPECT_FALSE(section.Exists("Override"));
+   EXPECT_TRUE(section.Exists("Override-Backup"));
+   EXPECT_EQ(packageValue, section.FindS("Package"));
+   EXPECT_EQ(2, section.Count());
+}
+TEST(TagSectionTest,WriteNoOrderRewrite)
+{
+   FileFd fd;
+   pkgTagSection section;
+   std::string content;
+   setupTestcaseStart(fd, section, content);
+   std::vector<pkgTagSection::Tag> rewrite;
+   rewrite.push_back(pkgTagSection::Tag::Rewrite("Override", "42"));
+   EXPECT_TRUE(section.Write(fd, NULL, rewrite));
+   EXPECT_TRUE(fd.Seek(0));
+   pkgTagFile tfile(&fd);
+   ASSERT_TRUE(tfile.Step(section));
+   EXPECT_TRUE(section.Exists("Package"));
+   EXPECT_TRUE(section.Exists("TypoA"));
+   EXPECT_FALSE(section.Exists("TypoB"));
+   EXPECT_TRUE(section.Exists("Override"));
+   EXPECT_TRUE(section.Exists("Override-Backup"));
+   EXPECT_EQ(packageValue, section.FindS("Package"));
+   EXPECT_EQ(42, section.FindI("Override"));
+   EXPECT_EQ(1, section.FindI("Override-Backup"));
+   EXPECT_EQ(4, section.Count());
+}
+TEST(TagSectionTest,WriteOrderRename)
+{
+   FileFd fd;
+   pkgTagSection section;
+   std::string content;
+   setupTestcaseStart(fd, section, content);
+   std::vector<pkgTagSection::Tag> rewrite;
+   rewrite.push_back(pkgTagSection::Tag::Rename("TypoA", "TypoB"));
+   char const * const order[] = { "Package", "TypoA", "Override", NULL };
+   EXPECT_TRUE(section.Write(fd, order, rewrite));
+   EXPECT_TRUE(fd.Seek(0));
+   pkgTagFile tfile(&fd);
+   ASSERT_TRUE(tfile.Step(section));
+   EXPECT_TRUE(section.Exists("Package"));
+   EXPECT_FALSE(section.Exists("TypoA"));
+   EXPECT_TRUE(section.Exists("TypoB"));
+   EXPECT_TRUE(section.Exists("Override"));
+   EXPECT_TRUE(section.Exists("Override-Backup"));
+   EXPECT_EQ(packageValue, section.FindS("Package"));
+   EXPECT_EQ(typoValue, section.FindS("TypoB"));
+   EXPECT_EQ(1, section.FindI("Override"));
+   EXPECT_EQ(1, section.FindI("Override-Backup"));
+   EXPECT_EQ(4, section.Count());
+}
+TEST(TagSectionTest,WriteOrderRemove)
+{
+   FileFd fd;
+   pkgTagSection section;
+   std::string content;
+   setupTestcaseStart(fd, section, content);
+   std::vector<pkgTagSection::Tag> rewrite;
+   rewrite.push_back(pkgTagSection::Tag::Remove("TypoA"));
+   rewrite.push_back(pkgTagSection::Tag::Rewrite("Override", ""));
+   char const * const order[] = { "Package", "TypoA", "Override", NULL };
+   EXPECT_TRUE(section.Write(fd, order, rewrite));
+   EXPECT_TRUE(fd.Seek(0));
+   pkgTagFile tfile(&fd);
+   ASSERT_TRUE(tfile.Step(section));
+   EXPECT_TRUE(section.Exists("Package"));
+   EXPECT_FALSE(section.Exists("TypoA"));
+   EXPECT_FALSE(section.Exists("TypoB"));
+   EXPECT_FALSE(section.Exists("Override"));
+   EXPECT_TRUE(section.Exists("Override-Backup"));
+   EXPECT_EQ(packageValue, section.FindS("Package"));
+   EXPECT_EQ(1, section.FindI("Override-Backup"));
+   EXPECT_EQ(2, section.Count());
+}
+TEST(TagSectionTest,WriteOrderRewrite)
+{
+   FileFd fd;
+   pkgTagSection section;
+   std::string content;
+   setupTestcaseStart(fd, section, content);
+   std::vector<pkgTagSection::Tag> rewrite;
+   rewrite.push_back(pkgTagSection::Tag::Rewrite("Override", "42"));
+   char const * const order[] = { "Package", "TypoA", "Override", NULL };
+   EXPECT_TRUE(section.Write(fd, order, rewrite));
+   EXPECT_TRUE(fd.Seek(0));
+   pkgTagFile tfile(&fd);
+   ASSERT_TRUE(tfile.Step(section));
+   EXPECT_TRUE(section.Exists("Package"));
+   EXPECT_TRUE(section.Exists("TypoA"));
+   EXPECT_FALSE(section.Exists("TypoB"));
+   EXPECT_TRUE(section.Exists("Override"));
+   EXPECT_TRUE(section.Exists("Override-Backup"));
+   EXPECT_EQ(packageValue, section.FindS("Package"));
+   EXPECT_EQ(42, section.FindI("Override"));
+   EXPECT_EQ(1, section.FindI("Override-Backup"));
+   EXPECT_EQ(4, section.Count());
+}