X-Git-Url: https://git.saurik.com/apt.git/blobdiff_plain/36b8ebbb4a5db4909c3cf739d8ea472f70703662..cc0a4c82b3c132abba9b9ec35fd61bc8b45a1b80:/apt-pkg/cdrom.cc

diff --git a/apt-pkg/cdrom.cc b/apt-pkg/cdrom.cc
index 2a914c665..d83d05f9e 100644
--- a/apt-pkg/cdrom.cc
+++ b/apt-pkg/cdrom.cc
@@ -1,26 +1,32 @@
 /*
  */
-
-#include<apt-pkg/init.h>
-#include<apt-pkg/error.h>
-#include<apt-pkg/cdromutl.h>
-#include<apt-pkg/strutl.h>
-#include<apt-pkg/cdrom.h>
-#include<apt-pkg/aptconfiguration.h>
-
-#include<sstream>
-#include<fstream>
-#include<config.h>
-#include<apti18n.h>
+#include <config.h>
+
+#include <apt-pkg/error.h>
+#include <apt-pkg/cdromutl.h>
+#include <apt-pkg/strutl.h>
+#include <apt-pkg/cdrom.h>
+#include <apt-pkg/aptconfiguration.h>
+#include <apt-pkg/configuration.h>
+#include <apt-pkg/fileutl.h>
+#include <apt-pkg/indexcopy.h>
+
+
+#include <string.h>
+#include <iostream>
+#include <string>
+#include <vector>
 #include <sys/stat.h>
-#include <fcntl.h>
 #include <dirent.h>
 #include <unistd.h>
 #include <stdio.h>
 #include <algorithm>
 #include <dlfcn.h>
+#include <iostream>
+#include <sstream>
+#include <fstream>
 
-#include "indexcopy.h"
+#include<apti18n.h>
 
 using namespace std;
 
@@ -55,66 +61,91 @@ bool pkgCdrom::FindPackages(string CD,
       return _error->Errno("chdir","Unable to change to %s",CD.c_str());
 
    // Look for a .disk subdirectory
-   struct stat Buf;
-   if (stat(".disk",&Buf) == 0)
+   if (InfoDir.empty() == true)
    {
-      if (InfoDir.empty() == true)
-	 InfoDir = CD + ".disk/";
+      if (DirectoryExists(".disk") == true)
+	 InfoDir = InfoDir + CD + ".disk/";
    }
 
    // Don't look into directories that have been marked to ingore.
-   if (stat(".aptignr",&Buf) == 0)
+   if (RealFileExists(".aptignr") == true)
       return true;
 
-
    /* Check _first_ for a signature file as apt-cdrom assumes that all files
       under a Packages/Source file are in control of that file and stops 
       the scanning
    */
-   if (stat("Release.gpg",&Buf) == 0)
+   if (RealFileExists("Release.gpg") == true || RealFileExists("InRelease") == true)
    {
       SigList.push_back(CD);
    }
+
    /* Aha! We found some package files. We assume that everything under 
       this dir is controlled by those package files so we don't look down
       anymore */
-   if (stat("Packages",&Buf) == 0 || stat("Packages.gz",&Buf) == 0)
+   std::vector<APT::Configuration::Compressor> const compressor = APT::Configuration::getCompressors();
+   for (std::vector<APT::Configuration::Compressor>::const_iterator c = compressor.begin();
+	c != compressor.end(); ++c)
    {
+      if (RealFileExists(std::string("Packages").append(c->Extension).c_str()) == false)
+	 continue;
+
+      if (_config->FindB("Debug::aptcdrom",false) == true)
+	 std::clog << "Found Packages in " << CD << std::endl;
       List.push_back(CD);
-      
+
       // Continue down if thorough is given
       if (_config->FindB("APT::CDROM::Thorough",false) == false)
 	 return true;
+      break;
    }
-   if (stat("Sources.gz",&Buf) == 0 || stat("Sources",&Buf) == 0)
+   for (std::vector<APT::Configuration::Compressor>::const_iterator c = compressor.begin();
+	c != compressor.end(); ++c)
    {
+      if (RealFileExists(std::string("Sources").append(c->Extension).c_str()) == false)
+	 continue;
+
+      if (_config->FindB("Debug::aptcdrom",false) == true)
+	 std::clog << "Found Sources in " << CD << std::endl;
       SList.push_back(CD);
-      
+
       // Continue down if thorough is given
       if (_config->FindB("APT::CDROM::Thorough",false) == false)
 	 return true;
+      break;
    }
 
-   // see if we find translatin indexes
-   if (stat("i18n",&Buf) == 0)
+   // see if we find translation indices
+   if (DirectoryExists("i18n") == true)
    {
       D = opendir("i18n");
       for (struct dirent *Dir = readdir(D); Dir != 0; Dir = readdir(D))
       {
-	 if(strstr(Dir->d_name,"Translation") != NULL) 
+	 if(strncmp(Dir->d_name, "Translation-", strlen("Translation-")) != 0)
+	    continue;
+	 string file = Dir->d_name;
+	 for (std::vector<APT::Configuration::Compressor>::const_iterator c = compressor.begin();
+	      c != compressor.end(); ++c)
 	 {
-	    if (_config->FindB("Debug::aptcdrom",false) == true)
-	       std::clog << "found translations: " << Dir->d_name << "\n";
-	    string file = Dir->d_name;
-	    if(file.substr(file.size()-3,file.size()) == ".gz")
-	       file = file.substr(0,file.size()-3);
-	    TransList.push_back(CD+"i18n/"+ file);
+	    string fileext = flExtension(file);
+	    if (file == fileext)
+	       fileext.clear();
+	    else if (fileext.empty() == false)
+	       fileext = "." + fileext;
+
+	    if (c->Extension == fileext)
+	    {
+	       if (_config->FindB("Debug::aptcdrom",false) == true)
+		  std::clog << "Found translation " << Dir->d_name << " in " << CD << "i18n/" << std::endl;
+	       file.erase(file.size() - fileext.size());
+	       TransList.push_back(CD + "i18n/" + file);
+	       break;
+	    }
 	 }
       }
       closedir(D);
    }
 
-   
    D = opendir(".");
    if (D == 0)
       return _error->Errno("opendir","Unable to read %s",CD.c_str());
@@ -125,10 +156,7 @@ bool pkgCdrom::FindPackages(string CD,
       // Skip some files..
       if (strcmp(Dir->d_name,".") == 0 ||
 	  strcmp(Dir->d_name,"..") == 0 ||
-	  //strcmp(Dir->d_name,"source") == 0 ||
 	  strcmp(Dir->d_name,".disk") == 0 ||
-	  strcmp(Dir->d_name,"experimental") == 0 ||
-	  strcmp(Dir->d_name,"binary-all") == 0 ||
           strcmp(Dir->d_name,"debian-installer") == 0)
 	 continue;
 
@@ -241,6 +269,29 @@ bool pkgCdrom::DropBinaryArch(vector<string> &List)
       --I; // the next entry is at the same index after the erase
    }
    
+   return true;
+}
+									/*}}}*/
+// DropTranslation - Dump unwanted Translation-<lang> files		/*{{{*/
+// ---------------------------------------------------------------------
+/* Here we drop everything that is not configured in Acquire::Languages */
+bool pkgCdrom::DropTranslation(vector<string> &List)
+{
+   for (unsigned int I = 0; I < List.size(); I++)
+   {
+      const char *Start;
+      if ((Start = strstr(List[I].c_str(), "/Translation-")) == NULL)
+	 continue;
+      Start += strlen("/Translation-");
+
+      if (APT::Configuration::checkLanguage(Start, true) == true)
+	 continue;
+
+      // not accepted -> Erase it
+      List.erase(List.begin() + I);
+      --I; // the next entry is at the same index after the erase
+   }
+
    return true;
 }
 									/*}}}*/
@@ -249,30 +300,43 @@ bool pkgCdrom::DropBinaryArch(vector<string> &List)
 /* Here we go and stat every file that we found and strip dup inodes. */
 bool pkgCdrom::DropRepeats(vector<string> &List,const char *Name)
 {
+   bool couldFindAllFiles = true;
    // Get a list of all the inodes
    ino_t *Inodes = new ino_t[List.size()];
-   for (unsigned int I = 0; I != List.size(); I++)
+   for (unsigned int I = 0; I != List.size(); ++I)
    {
       struct stat Buf;
-      if (stat((List[I] + Name).c_str(),&Buf) != 0 &&
-	  stat((List[I] + Name + ".gz").c_str(),&Buf) != 0)
-	 _error->Errno("stat","Failed to stat %s%s",List[I].c_str(),
-		       Name);
-      Inodes[I] = Buf.st_ino;
-   }
-   
-   if (_error->PendingError() == true) {
-      delete[] Inodes;
-      return false;
+      bool found = false;
+
+      std::vector<APT::Configuration::Compressor> const compressor = APT::Configuration::getCompressors();
+      for (std::vector<APT::Configuration::Compressor>::const_iterator c = compressor.begin();
+	   c != compressor.end(); ++c)
+      {
+	 std::string filename = std::string(List[I]).append(Name).append(c->Extension);
+         if (stat(filename.c_str(), &Buf) != 0)
+	    continue;
+	 Inodes[I] = Buf.st_ino;
+	 found = true;
+	 break;
+      }
+
+      if (found == false)
+      {
+	 _error->Errno("stat","Failed to stat %s%s",List[I].c_str(), Name);
+	 couldFindAllFiles = false;
+	 Inodes[I] = 0;
+      }
    }
-   
+
    // Look for dups
    for (unsigned int I = 0; I != List.size(); I++)
    {
+      if (Inodes[I] == 0)
+	 continue;
       for (unsigned int J = I+1; J < List.size(); J++)
       {
 	 // No match
-	 if (Inodes[J] != Inodes[I])
+	 if (Inodes[J] == 0 || Inodes[J] != Inodes[I])
 	    continue;
 	 
 	 // We score the two paths.. and erase one
@@ -298,19 +362,19 @@ bool pkgCdrom::DropRepeats(vector<string> &List,const char *Name)
 	 List.erase(List.begin()+I);
    }
    
-   return true;
+   return couldFindAllFiles;
 }
 									/*}}}*/
 // ReduceSourceList - Takes the path list and reduces it		/*{{{*/
 // ---------------------------------------------------------------------
-/* This takes the list of source list expressed entires and collects
+/* This takes the list of source list expressed entries and collects
    similar ones to form a single entry for each dist */
-void pkgCdrom::ReduceSourcelist(string CD,vector<string> &List)
+void pkgCdrom::ReduceSourcelist(string /*CD*/,vector<string> &List)
 {
    sort(List.begin(),List.end());
    
    // Collect similar entries
-   for (vector<string>::iterator I = List.begin(); I != List.end(); I++)
+   for (vector<string>::iterator I = List.begin(); I != List.end(); ++I)
    {
       // Find a space..
       string::size_type Space = (*I).find(' ');
@@ -322,7 +386,8 @@ void pkgCdrom::ReduceSourcelist(string CD,vector<string> &List)
 
       string Word1 = string(*I,Space,SSpace-Space);
       string Prefix = string(*I,0,Space);
-      for (vector<string>::iterator J = List.begin(); J != I; J++)
+      string Component = string(*I,SSpace);
+      for (vector<string>::iterator J = List.begin(); J != I; ++J)
       {
 	 // Find a space..
 	 string::size_type Space2 = (*J).find(' ');
@@ -336,9 +401,11 @@ void pkgCdrom::ReduceSourcelist(string CD,vector<string> &List)
 	    continue;
 	 if (string(*J,Space2,SSpace2-Space2) != Word1)
 	    continue;
-	 
-	 *J += string(*I,SSpace);
-	 *I = string();
+
+	 string Component2 = string(*J, SSpace2) + " ";
+	 if (Component2.find(Component + " ") == std::string::npos)
+	    *J += Component;
+	 I->clear();
       }
    }   
 
@@ -359,8 +426,8 @@ bool pkgCdrom::WriteDatabase(Configuration &Cnf)
 {
    string DFile = _config->FindFile("Dir::State::cdroms");
    string NewFile = DFile + ".new";
-   
-   unlink(NewFile.c_str());
+
+   RemoveFile("WriteDatabase", NewFile);
    ofstream Out(NewFile.c_str());
    if (!Out)
       return _error->Errno("ofstream::ofstream",
@@ -368,28 +435,12 @@ bool pkgCdrom::WriteDatabase(Configuration &Cnf)
    
    /* Write out all of the configuration directives by walking the
       configuration tree */
-   const Configuration::Item *Top = Cnf.Tree(0);
-   for (; Top != 0;)
-   {
-      // Print the config entry
-      if (Top->Value.empty() == false)
-	 Out <<  Top->FullTag() + " \"" << Top->Value << "\";" << endl;
-      
-      if (Top->Child != 0)
-      {
-	 Top = Top->Child;
-	 continue;
-      }
-      
-      while (Top != 0 && Top->Next == 0)
-	 Top = Top->Parent;
-      if (Top != 0)
-	 Top = Top->Next;
-   }   
+   Cnf.Dump(Out, NULL, "%f \"%v\";\n", false);
 
    Out.close();
-   
-   link(DFile.c_str(),string(DFile + '~').c_str());
+
+   if (FileExists(DFile) == true)
+      rename(DFile.c_str(), (DFile + '~').c_str());
    if (rename(NewFile.c_str(),DFile.c_str()) != 0)
       return _error->Errno("rename","Failed to rename %s.new to %s",
 			   DFile.c_str(),DFile.c_str());
@@ -400,12 +451,12 @@ bool pkgCdrom::WriteDatabase(Configuration &Cnf)
 // WriteSourceList - Write an updated sourcelist			/*{{{*/
 // ---------------------------------------------------------------------
 /* This reads the old source list and copies it into the new one. It 
-   appends the new CDROM entires just after the first block of comments.
+   appends the new CDROM entries just after the first block of comments.
    This places them first in the file. It also removes any old entries
    that were the same. */
 bool pkgCdrom::WriteSourceList(string Name,vector<string> &List,bool Source)
 {
-   if (List.size() == 0)
+   if (List.empty() == true)
       return true;
 
    string File = _config->FindFile("Dir::Etc::sourcelist");
@@ -413,18 +464,18 @@ bool pkgCdrom::WriteSourceList(string Name,vector<string> &List,bool Source)
    // Open the stream for reading
    ifstream F((FileExists(File)?File.c_str():"/dev/null"),
 	      ios::in );
-   if (!F != 0)
+   if (F.fail() == true)
       return _error->Errno("ifstream::ifstream","Opening %s",File.c_str());
 
    string NewFile = File + ".new";
-   unlink(NewFile.c_str());
+   RemoveFile("WriteDatabase", NewFile);
    ofstream Out(NewFile.c_str());
    if (!Out)
       return _error->Errno("ofstream::ofstream",
 			   "Failed to open %s.new",File.c_str());
 
    // Create a short uri without the path
-   string ShortURI = "cdrom:[" + Name + "]/";   
+   string ShortURI = "cdrom:[" + Name + "]/";
    string ShortURI2 = "cdrom:" + Name + "/";     // For Compatibility
 
    string Type;
@@ -432,12 +483,12 @@ bool pkgCdrom::WriteSourceList(string Name,vector<string> &List,bool Source)
       Type = "deb-src";
    else
       Type = "deb";
-   
+
    char Buffer[300];
    int CurLine = 0;
    bool First = true;
    while (F.eof() == false)
-   {      
+   {
       F.getline(Buffer,sizeof(Buffer));
       CurLine++;
       if (F.fail() && !F.eof())
@@ -455,7 +506,7 @@ bool pkgCdrom::WriteSourceList(string Name,vector<string> &List,bool Source)
 
       if (First == true)
       {
-	 for (vector<string>::iterator I = List.begin(); I != List.end(); I++)
+	 for (vector<string>::iterator I = List.begin(); I != List.end(); ++I)
 	 {
 	    string::size_type Space = (*I).find(' ');
 	    if (Space == string::npos)
@@ -489,7 +540,7 @@ bool pkgCdrom::WriteSourceList(string Name,vector<string> &List,bool Source)
    // Just in case the file was empty
    if (First == true)
    {
-      for (vector<string>::iterator I = List.begin(); I != List.end(); I++)
+      for (vector<string>::iterator I = List.begin(); I != List.end(); ++I)
       {
 	 string::size_type Space = (*I).find(' ');
 	 if (Space == string::npos)
@@ -502,7 +553,7 @@ bool pkgCdrom::WriteSourceList(string Name,vector<string> &List,bool Source)
    
    Out.close();
 
-   rename(File.c_str(),string(File + '~').c_str());
+   rename(File.c_str(), (File + '~').c_str());
    if (rename(NewFile.c_str(),File.c_str()) != 0)
       return _error->Errno("rename","Failed to rename %s.new to %s",
 			   File.c_str(),File.c_str());
@@ -510,137 +561,121 @@ bool pkgCdrom::WriteSourceList(string Name,vector<string> &List,bool Source)
    return true;
 }
 									/*}}}*/
-bool pkgCdrom::Ident(string &ident, pkgCdromStatus *log)		/*{{{*/
+bool pkgCdrom::UnmountCDROM(std::string const &CDROM, pkgCdromStatus * const log)/*{{{*/
+{
+   if (_config->FindB("APT::CDROM::NoMount",false) == true)
+      return true;
+   if (log != NULL)
+      log->Update(_("Unmounting CD-ROM...\n"), STEP_LAST);
+   return UnmountCdrom(CDROM);
+}
+									/*}}}*/
+bool pkgCdrom::MountAndIdentCDROM(Configuration &Database, std::string &CDROM, std::string &ident, pkgCdromStatus * const log, bool const interactive)/*{{{*/
 {
-   stringstream msg;
-
    // Startup
-   string CDROM = _config->FindDir("Acquire::cdrom::mount");
+   CDROM = _config->FindDir("Acquire::cdrom::mount");
    if (CDROM[0] == '.')
       CDROM= SafeGetCWD() + '/' + CDROM;
 
    if (log != NULL)
    {
-      msg.str("");
-      ioprintf(msg, _("Using CD-ROM mount point %s\nMounting CD-ROM\n"),
-		      CDROM.c_str());
-      log->Update(msg.str());
+      string msg;
+      log->SetTotal(STEP_LAST);
+      strprintf(msg, _("Using CD-ROM mount point %s\n"), CDROM.c_str());
+      log->Update(msg, STEP_PREPARE);
+   }
+
+   // Unmount the CD and get the user to put in the one they want
+   if (_config->FindB("APT::CDROM::NoMount", false) == false)
+   {
+      if (interactive == true)
+      {
+	 UnmountCDROM(CDROM, log);
+
+	 if(log != NULL)
+	 {
+	    log->Update(_("Waiting for disc...\n"), STEP_WAIT);
+	    if(!log->ChangeCdrom()) {
+	       // user aborted
+	       return false;
+	    }
+	 }
+      }
+
+      // Mount the new CDROM
+      if(log != NULL)
+	 log->Update(_("Mounting CD-ROM...\n"), STEP_MOUNT);
+
+      if (MountCdrom(CDROM) == false)
+	 return _error->Error("Failed to mount the cdrom.");
    }
-   if (MountCdrom(CDROM) == false)
+
+   if (IsMounted(CDROM) == false)
       return _error->Error("Failed to mount the cdrom.");
 
    // Hash the CD to get an ID
    if (log != NULL)
-      log->Update(_("Identifying.. "));
-   
+      log->Update(_("Identifying... "), STEP_IDENT);
 
    if (IdentCdrom(CDROM,ident) == false)
    {
       ident = "";
+      if (log != NULL)
+	 log->Update("\n");
+      UnmountCDROM(CDROM, NULL);
       return false;
    }
 
    if (log != NULL)
    {
-      msg.str("");
-      ioprintf(msg, "[%s]\n",ident.c_str());
-      log->Update(msg.str());
+      string msg;
+      strprintf(msg, "[%s]\n", ident.c_str());
+      log->Update(msg);
    }
 
    // Read the database
-   Configuration Database;
    string DFile = _config->FindFile("Dir::State::cdroms");
    if (FileExists(DFile) == true)
    {
       if (ReadConfigFile(Database,DFile) == false)
+      {
+	 UnmountCDROM(CDROM, NULL);
 	 return _error->Error("Unable to read the cdrom database %s",
 			      DFile.c_str());
+      }
    }
+   return true;
+}
+									/*}}}*/
+bool pkgCdrom::Ident(string &ident, pkgCdromStatus *log)		/*{{{*/
+{
+   Configuration Database;
+   std::string CDROM;
+   if (MountAndIdentCDROM(Database, CDROM, ident, log, false) == false)
+      return false;
+
    if (log != NULL)
    {
-      msg.str("");
-      ioprintf(msg, _("Stored label: %s\n"),
-      Database.Find("CD::"+ident).c_str());
-      log->Update(msg.str());
+      string msg;
+      strprintf(msg, _("Stored label: %s\n"),
+	    Database.Find("CD::"+ident).c_str());
+      log->Update(msg);
    }
 
    // Unmount and finish
-   if (_config->FindB("APT::CDROM::NoMount",false) == false)
-   {
-      if (log != NULL)
-	 log->Update(_("Unmounting CD-ROM...\n"), STEP_LAST);
-      UnmountCdrom(CDROM);
-   }
-
+   UnmountCDROM(CDROM, log);
    return true;
 }
 									/*}}}*/
 bool pkgCdrom::Add(pkgCdromStatus *log)					/*{{{*/
 {
-   stringstream msg;
-
-   // Startup
-   string CDROM = _config->FindDir("Acquire::cdrom::mount");
-   if (CDROM[0] == '.')
-      CDROM= SafeGetCWD() + '/' + CDROM;
-   
-   if(log != NULL)
-   {
-      log->SetTotal(STEP_LAST);
-      msg.str("");
-      ioprintf(msg, _("Using CD-ROM mount point %s\n"), CDROM.c_str());
-      log->Update(msg.str(), STEP_PREPARE);
-   }
-
-   // Read the database
    Configuration Database;
-   string DFile = _config->FindFile("Dir::State::cdroms");
-   if (FileExists(DFile) == true)
-   {
-      if (ReadConfigFile(Database,DFile) == false) 
-	 return _error->Error("Unable to read the cdrom database %s",
-			      DFile.c_str());
-   }
-   
-   // Unmount the CD and get the user to put in the one they want
-   if (_config->FindB("APT::CDROM::NoMount",false) == false)
-   {
-      if(log != NULL)
-	 log->Update(_("Unmounting CD-ROM\n"), STEP_UNMOUNT);
-      UnmountCdrom(CDROM);
-
-      if(log != NULL)
-      {
-	 log->Update(_("Waiting for disc...\n"), STEP_WAIT);
-	 if(!log->ChangeCdrom()) {
-	    // user aborted
-	    return false; 
-	 }
-      }
-
-      // Mount the new CDROM
-      if(log != NULL)
-	 log->Update(_("Mounting CD-ROM...\n"), STEP_MOUNT);
-
-      if (MountCdrom(CDROM) == false)
-	 return _error->Error("Failed to mount the cdrom.");
-   }
-   
-   // Hash the CD to get an ID
-   if(log != NULL)
-      log->Update(_("Identifying.. "), STEP_IDENT);
-   string ID;
-   if (IdentCdrom(CDROM,ID) == false)
-   {
-      if (log != NULL)
-	 log->Update("\n");
+   std::string ID, CDROM;
+   if (MountAndIdentCDROM(Database, CDROM, ID, log, true) == false)
       return false;
-   }
+
    if(log != NULL)
-   {
-      log->Update("["+ID+"]\n");
-      log->Update(_("Scanning disc for index files..\n"),STEP_SCAN);
-   }
+      log->Update(_("Scanning disc for index files...\n"),STEP_SCAN);
 
    // Get the CD structure
    vector<string> List;
@@ -653,21 +688,26 @@ bool pkgCdrom::Add(pkgCdromStatus *log)					/*{{{*/
    {
       if (log != NULL)
 	 log->Update("\n");
+      UnmountCDROM(CDROM, NULL);
       return false;
    }
 
-   chdir(StartDir.c_str());
+   if (chdir(StartDir.c_str()) != 0)
+   {
+      UnmountCDROM(CDROM, NULL);
+      return _error->Errno("chdir","Unable to change to %s", StartDir.c_str());
+   }
 
    if (_config->FindB("Debug::aptcdrom",false) == true)
    {
       cout << "I found (binary):" << endl;
-      for (vector<string>::iterator I = List.begin(); I != List.end(); I++)
+      for (vector<string>::iterator I = List.begin(); I != List.end(); ++I)
 	 cout << *I << endl;
       cout << "I found (source):" << endl;
-      for (vector<string>::iterator I = SourceList.begin(); I != SourceList.end(); I++)
+      for (vector<string>::iterator I = SourceList.begin(); I != SourceList.end(); ++I)
 	 cout << *I << endl;
       cout << "I found (Signatures):" << endl;
-      for (vector<string>::iterator I = SigList.begin(); I != SigList.end(); I++)
+      for (vector<string>::iterator I = SigList.begin(); I != SigList.end(); ++I)
 	 cout << *I << endl;
    }   
 
@@ -677,21 +717,28 @@ bool pkgCdrom::Add(pkgCdromStatus *log)					/*{{{*/
    DropBinaryArch(List);
    DropRepeats(List,"Packages");
    DropRepeats(SourceList,"Sources");
+   // FIXME: We ignore stat() errors here as we usually have only one of those in use
+   // This has little potencial to drop 'valid' stat() errors as we know that one of these
+   // files need to exist, but it would be better if we would check it here
+   _error->PushToStack();
    DropRepeats(SigList,"Release.gpg");
+   DropRepeats(SigList,"InRelease");
+   _error->RevertToStack();
    DropRepeats(TransList,"");
+   if (_config->FindB("APT::CDROM::DropTranslation", true) == true)
+      DropTranslation(TransList);
    if(log != NULL) {
-      msg.str("");
-      ioprintf(msg, _("Found %zu package indexes, %zu source indexes, "
+      string msg;
+      strprintf(msg, _("Found %zu package indexes, %zu source indexes, "
 		      "%zu translation indexes and %zu signatures\n"), 
 	       List.size(), SourceList.size(), TransList.size(),
 	       SigList.size());
-      log->Update(msg.str(), STEP_SCAN);
+      log->Update(msg, STEP_SCAN);
    }
 
-   if (List.size() == 0 && SourceList.size() == 0) 
+   if (List.empty() == true && SourceList.empty() == true) 
    {
-      if (_config->FindB("APT::CDROM::NoMount",false) == false) 
-	 UnmountCdrom(CDROM);
+      UnmountCDROM(CDROM, NULL);
       return _error->Error(_("Unable to locate any package files, perhaps this is not a Debian Disc or the wrong architecture?"));
    }
 
@@ -704,23 +751,23 @@ bool pkgCdrom::Add(pkgCdromStatus *log)					/*{{{*/
       if (InfoDir.empty() == false &&
 	  FileExists(InfoDir + "/info") == true)
       {
-	 ifstream F(string(InfoDir + "/info").c_str());
-	 if (!F == 0)
+	 ifstream F((InfoDir + "/info").c_str());
+	 if (F.good() == true)
 	    getline(F,Name);
 
 	 if (Name.empty() == false)
 	 {
 	    // Escape special characters
 	    string::iterator J = Name.begin();
-	    for (; J != Name.end(); J++)
+	    for (; J != Name.end(); ++J)
 	       if (*J == '"' || *J == ']' || *J == '[')
 		  *J = '_';
 	    
 	    if(log != NULL)
 	    {
-	       msg.str("");
-	       ioprintf(msg, _("Found label '%s'\n"), Name.c_str());
-	       log->Update(msg.str());
+	       string msg;
+	       strprintf(msg, _("Found label '%s'\n"), Name.c_str());
+	       log->Update(msg);
 	    }
 	    Database.Set("CD::" + ID + "::Label",Name);
 	 }	 
@@ -731,14 +778,14 @@ bool pkgCdrom::Add(pkgCdromStatus *log)					/*{{{*/
       {
 	 if(log == NULL) 
          {
-	    if (_config->FindB("APT::CDROM::NoMount",false) == false) 
-	       UnmountCdrom(CDROM);
+	    UnmountCDROM(CDROM, NULL);
 	    return _error->Error("No disc name found and no way to ask for it");
 	 }
 
 	 while(true) {
 	    if(!log->AskCdromName(Name)) {
 	       // user canceld
+	       UnmountCDROM(CDROM, NULL);
 	       return false; 
 	    }
 	    cout << "Name: '" << Name << "'" << endl;
@@ -757,18 +804,32 @@ bool pkgCdrom::Add(pkgCdromStatus *log)					/*{{{*/
 
    // Escape special characters
    string::iterator J = Name.begin();
-   for (; J != Name.end(); J++)
+   for (; J != Name.end(); ++J)
       if (*J == '"' || *J == ']' || *J == '[')
 	 *J = '_';
    
    Database.Set("CD::" + ID,Name);
    if(log != NULL)
    {
-      msg.str("");
-      ioprintf(msg, _("This disc is called: \n'%s'\n"), Name.c_str());
-      log->Update(msg.str());
+      string msg;
+      strprintf(msg, _("This disc is called: \n'%s'\n"), Name.c_str());
+      log->Update(msg);
       log->Update(_("Copying package lists..."), STEP_COPY);
    }
+
+   // check for existence and possibly create state directory for copying
+   string const listDir = _config->FindDir("Dir::State::lists");
+   string const partialListDir = listDir + "partial/";
+   mode_t const mode = umask(S_IWGRP | S_IWOTH);
+   bool const creation_fail = (CreateAPTDirectoryIfNeeded(_config->FindDir("Dir::State"), partialListDir) == false &&
+	 CreateAPTDirectoryIfNeeded(listDir, partialListDir) == false);
+   umask(mode);
+   if (creation_fail == true)
+   {
+      UnmountCDROM(CDROM, NULL);
+      return _error->Errno("cdrom", _("List directory %spartial is missing."), listDir.c_str());
+   }
+
    // take care of the signatures and copy them if they are ok
    // (we do this before PackageCopy as it modifies "List" and "SourceList")
    SigVerify SignVerify;
@@ -781,7 +842,10 @@ bool pkgCdrom::Add(pkgCdromStatus *log)					/*{{{*/
    if (Copy.CopyPackages(CDROM,Name,List, log) == false ||
        SrcCopy.CopyPackages(CDROM,Name,SourceList, log) == false ||
        TransCopy.CopyTranslations(CDROM,Name,TransList, log) == false)
+   {
+      UnmountCDROM(CDROM, NULL);
       return false;
+   }
 
    // reduce the List so that it takes less space in sources.list
    ReduceSourcelist(CDROM,List);
@@ -791,50 +855,54 @@ bool pkgCdrom::Add(pkgCdromStatus *log)					/*{{{*/
    if (_config->FindB("APT::cdrom::NoAct",false) == false)
    {
       if (WriteDatabase(Database) == false)
+      {
+	 UnmountCDROM(CDROM, NULL);
 	 return false;
-      
+      }
+
       if(log != NULL)
 	 log->Update(_("Writing new source list\n"), STEP_WRITE);
       if (WriteSourceList(Name,List,false) == false ||
 	  WriteSourceList(Name,SourceList,true) == false)
+      {
+	 UnmountCDROM(CDROM, NULL);
 	 return false;
+      }
    }
 
    // Print the sourcelist entries
    if(log != NULL)
       log->Update(_("Source list entries for this disc are:\n"));
 
-   for (vector<string>::iterator I = List.begin(); I != List.end(); I++)
+   for (vector<string>::iterator I = List.begin(); I != List.end(); ++I)
    {
       string::size_type Space = (*I).find(' ');
       if (Space == string::npos)
       {
-	 if (_config->FindB("APT::CDROM::NoMount",false) == false) 
-	    UnmountCdrom(CDROM);
+	 UnmountCDROM(CDROM, NULL);
 	 return _error->Error("Internal error");
       }
 
       if(log != NULL)
       {
-	 msg.str("");
+	 stringstream msg;
 	 msg << "deb cdrom:[" << Name << "]/" << string(*I,0,Space) << 
 	    " " << string(*I,Space+1) << endl;
 	 log->Update(msg.str());
       }
    }
 
-   for (vector<string>::iterator I = SourceList.begin(); I != SourceList.end(); I++)
+   for (vector<string>::iterator I = SourceList.begin(); I != SourceList.end(); ++I)
    {
       string::size_type Space = (*I).find(' ');
       if (Space == string::npos)
       {
-	 if (_config->FindB("APT::CDROM::NoMount",false) == false) 
-	    UnmountCdrom(CDROM);
+	 UnmountCDROM(CDROM, NULL);
 	 return _error->Error("Internal error");
       }
 
       if(log != NULL) {
-	 msg.str("");
+	 stringstream msg;
 	 msg << "deb-src cdrom:[" << Name << "]/" << string(*I,0,Space) << 
 	    " " << string(*I,Space+1) << endl;
 	 log->Update(msg.str());
@@ -842,24 +910,22 @@ bool pkgCdrom::Add(pkgCdromStatus *log)					/*{{{*/
    }
 
    // Unmount and finish
-   if (_config->FindB("APT::CDROM::NoMount",false) == false) {
-      if (log != NULL)
-	 log->Update(_("Unmounting CD-ROM...\n"), STEP_LAST);
-      UnmountCdrom(CDROM);
-   }
-
+   UnmountCDROM(CDROM, log);
    return true;
 }
 									/*}}}*/
-pkgUdevCdromDevices::pkgUdevCdromDevices()                     		/*{{{*/
-   : libudev_handle(NULL)
+pkgUdevCdromDevices::pkgUdevCdromDevices()				/*{{{*/
+: d(NULL), libudev_handle(NULL), udev_new(NULL), udev_enumerate_add_match_property(NULL),
+   udev_enumerate_scan_devices(NULL), udev_enumerate_get_list_entry(NULL),
+   udev_device_new_from_syspath(NULL), udev_enumerate_get_udev(NULL),
+   udev_list_entry_get_name(NULL), udev_device_get_devnode(NULL),
+   udev_enumerate_new(NULL), udev_list_entry_get_next(NULL),
+   udev_device_get_property_value(NULL), udev_enumerate_add_match_sysattr(NULL)
 {
-
 }
 									/*}}}*/
 
-bool
-pkgUdevCdromDevices::Dlopen()                     		        /*{{{*/
+bool pkgUdevCdromDevices::Dlopen()					/*{{{*/
 {
    // alread open
    if(libudev_handle != NULL)
@@ -874,9 +940,7 @@ pkgUdevCdromDevices::Dlopen()                     		        /*{{{*/
    libudev_handle = h;
    udev_new = (udev* (*)(void)) dlsym(h, "udev_new");
    udev_enumerate_add_match_property = (int (*)(udev_enumerate*, const char*, const char*))dlsym(h, "udev_enumerate_add_match_property");
-#if 0 // FIXME: uncomment on next ABI break
    udev_enumerate_add_match_sysattr = (int (*)(udev_enumerate*, const char*, const char*))dlsym(h, "udev_enumerate_add_match_sysattr");
-#endif
    udev_enumerate_scan_devices = (int (*)(udev_enumerate*))dlsym(h, "udev_enumerate_scan_devices");
    udev_enumerate_get_list_entry = (udev_list_entry* (*)(udev_enumerate*))dlsym(h, "udev_enumerate_get_list_entry");
    udev_device_new_from_syspath = (udev_device* (*)(udev*, const char*))dlsym(h, "udev_device_new_from_syspath");
@@ -890,20 +954,14 @@ pkgUdevCdromDevices::Dlopen()                     		        /*{{{*/
    return true;
 }
 									/*}}}*/
-
-                                                                        /*{{{*/
-// compatiblity only with the old API/ABI, can be removed on the next
-// ABI break
-vector<CdromDevice>
-pkgUdevCdromDevices::Scan()
-{ 
+// convenience interface, this will just call ScanForRemovable		/*{{{*/
+vector<CdromDevice> pkgUdevCdromDevices::Scan()
+{
    bool CdromOnly = _config->FindB("APT::cdrom::CdromOnly", true);
-   return ScanForRemovable(CdromOnly); 
-};
+   return ScanForRemovable(CdromOnly);
+}
 									/*}}}*/
-                                                                        /*{{{*/
-vector<CdromDevice>
-pkgUdevCdromDevices::ScanForRemovable(bool CdromOnly)
+vector<CdromDevice> pkgUdevCdromDevices::ScanForRemovable(bool CdromOnly)/*{{{*/
 {
    vector<CdromDevice> cdrom_devices;
    struct udev_enumerate *enumerate;
@@ -918,10 +976,6 @@ pkgUdevCdromDevices::ScanForRemovable(bool CdromOnly)
    if (CdromOnly)
       udev_enumerate_add_match_property(enumerate, "ID_CDROM", "1");
    else {
-#if 1 // FIXME: remove the next two lines on the next ABI break
-      int (*udev_enumerate_add_match_sysattr)(struct udev_enumerate *udev_enumerate, const char *property, const char *value);
-      udev_enumerate_add_match_sysattr = (int (*)(udev_enumerate*, const char*, const char*))dlsym(libudev_handle, "udev_enumerate_add_match_sysattr");
-#endif
       udev_enumerate_add_match_sysattr(enumerate, "removable", "1");
    }
 
@@ -948,7 +1002,7 @@ pkgUdevCdromDevices::ScanForRemovable(bool CdromOnly)
       cdrom.DeviceName = string(devnode);
       if (mountpath != "") {
 	 cdrom.MountPath = mountpath;
-	 string s = string(mountpath);
+	 string s = mountpath;
 	 cdrom.Mounted = IsMounted(s);
       } else {
 	 cdrom.Mounted = false;
@@ -966,3 +1020,9 @@ pkgUdevCdromDevices::~pkgUdevCdromDevices()                             /*{{{*/
       dlclose(libudev_handle);
 }
 									/*}}}*/
+
+pkgCdromStatus::pkgCdromStatus() : d(NULL), totalSteps(0) {}
+pkgCdromStatus::~pkgCdromStatus() {}
+
+pkgCdrom::pkgCdrom() : d(NULL) {}
+pkgCdrom::~pkgCdrom() {}