]> git.saurik.com Git - apt.git/commitdiff
Merge branch 'feature/abspath' into feature/apt-install-deb
authorMichael Vogt <mvo@ubuntu.com>
Mon, 28 Apr 2014 15:45:07 +0000 (17:45 +0200)
committerMichael Vogt <mvo@ubuntu.com>
Mon, 28 Apr 2014 15:45:07 +0000 (17:45 +0200)
13 files changed:
apt-pkg/acquire-item.cc
apt-pkg/contrib/fileutl.cc
apt-pkg/contrib/fileutl.h
apt-pkg/deb/debindexfile.cc
apt-pkg/deb/debindexfile.h
apt-pkg/deb/deblistparser.cc
apt-pkg/deb/deblistparser.h
apt-pkg/deb/debmetaindex.cc
apt-pkg/deb/debmetaindex.h
apt-pkg/deb/debrecords.h
apt-pkg/sourcelist.h
apt-private/private-install.cc
test/libapt/fileutl_test.cc

index 30743addf0a85a0e1b8319b190f6ff10e818d2f4..22b77cbda310eda13c6d4f01eca272c5114c8318 100644 (file)
@@ -2084,7 +2084,8 @@ void pkgAcqArchive::Done(string Message,unsigned long long Size,string CalcHash,
    }
    
    // Check the hash
-   if(ExpectedHash.toStr() != CalcHash)
+   // FIXME: could this empty() check impose *any* sort of security issue?
+   if(ExpectedHash.empty() == false && ExpectedHash.toStr() != CalcHash)
    {
       RenameOnError(HashSumMismatch);
       return;
index abc0a5fb2294e826e48f5c648392a43c8beab7cf..c7c60e00eca6c70ccd0864d9d27da4ac0ece4923 100644 (file)
@@ -1936,7 +1936,6 @@ bool FileFd::Close()
    {
       if ((Flags & Compressed) != Compressed && iFd > 0 && close(iFd) != 0)
         Res &= _error->Errno("close",_("Problem closing the file %s"), FileName.c_str());
-
       if (d != NULL)
       {
         Res &= d->CloseDown(FileName);
@@ -2063,6 +2062,31 @@ std::string GetTempDir()
    return string(tmpdir);
 }
 
+FileFd* GetTempFile(std::string const &Prefix, bool ImmediateUnlink)
+{
+   char fn[512];
+   FileFd *Fd = new FileFd();
+
+   std::string tempdir = GetTempDir();
+   snprintf(fn, sizeof(fn), "%s/%s.XXXXXX", 
+            tempdir.c_str(), Prefix.c_str());
+   int fd = mkstemp(fn);
+   if(ImmediateUnlink)
+      unlink(fn);
+   if (fd < 0) 
+   {
+      _error->Errno("GetTempFile",_("Unable to mkstemp %s"), fn);
+      return NULL;
+   }
+   if (!Fd->OpenDescriptor(fd, FileFd::WriteOnly, FileFd::None, true))
+   {
+      _error->Errno("GetTempFile",_("Unable to write to %s"),fn);
+      return NULL;
+   }
+
+   return Fd;
+}
+
 bool Rename(std::string From, std::string To)
 {
    if (rename(From.c_str(),To.c_str()) != 0)
@@ -2073,3 +2097,58 @@ bool Rename(std::string From, std::string To)
    }   
    return true;
 }
+
+bool Popen(const char* Args[], FileFd &Fd, pid_t &Child, FileFd::OpenMode Mode)
+{
+   int fd;
+   if (Mode != FileFd::ReadOnly && Mode != FileFd::WriteOnly)
+      return _error->Error("Popen supports ReadOnly (x)or WriteOnly mode only");
+
+   int Pipe[2] = {-1, -1};
+   if(pipe(Pipe) != 0)
+   {
+      return _error->Errno("pipe", _("Failed to create subprocess IPC"));
+      return NULL;
+   }
+   std::set<int> keep_fds;
+   keep_fds.insert(Pipe[0]);
+   keep_fds.insert(Pipe[1]);
+   Child = ExecFork(keep_fds);
+   if(Child < 0)
+      return _error->Errno("fork", "Failed to fork");
+   if(Child == 0)
+   {
+      if(Mode == FileFd::ReadOnly)
+      {
+         close(Pipe[0]);
+         fd = Pipe[1];
+      }
+      else if(Mode == FileFd::WriteOnly)
+      {
+         close(Pipe[1]);
+         fd = Pipe[0];
+      }
+
+      if(Mode == FileFd::ReadOnly)
+      {
+         dup2(fd, 1);
+         dup2(fd, 2);
+      } else if(Mode == FileFd::WriteOnly)
+         dup2(fd, 0);
+
+      execv(Args[0], (char**)Args);
+      _exit(100);
+   }
+   if(Mode == FileFd::ReadOnly)
+   {
+      close(Pipe[1]);
+      fd = Pipe[0];
+   } else if(Mode == FileFd::WriteOnly)
+   {
+      close(Pipe[0]);
+      fd = Pipe[1];
+   }
+   Fd.OpenDescriptor(fd, Mode, FileFd::None, true);
+
+   return true;
+}
index ab944071ac7fafa294ebc967bf47b119ff1f86b4..452e5fcc281e30905d417bc01c795b7b44c96602 100644 (file)
@@ -168,6 +168,8 @@ time_t GetModificationTime(std::string const &Path);
 bool Rename(std::string From, std::string To);
 
 std::string GetTempDir();
+FileFd* GetTempFile(std::string const &Prefix = "", 
+                    bool ImmediateUnlink = true);
 
 /** \brief Ensure the existence of the given Path
  *
@@ -205,4 +207,16 @@ std::string flAbsPath(std::string File);
 // simple c++ glob
 std::vector<std::string> Glob(std::string const &pattern, int flags=0);
 
+/** \brief Popen() implementation that execv() instead of using a shell
+ *
+ * \param Args the execv style command to run
+ * \param FileFd is a referenz to the FileFd to use for input or output
+ * \param Child a reference to the integer that stores the child pid
+ *        Note that you must call ExecWait() or similar to cleanup
+ * \param Mode is either FileFd::ReadOnly or FileFd::WriteOnly
+ * \return true on success, false on failure with _error set
+ */
+bool Popen(const char* Args[], FileFd &Fd, pid_t &Child, FileFd::OpenMode Mode);
+
+
 #endif
index eee758b7a124d388ac1d1fe1c9cb84c38d6fe806..86ef92bfbc681b6a9a643ea010e943aa2eb4466b 100644 (file)
@@ -30,6 +30,7 @@
 #include <apt-pkg/pkgcachegen.h>
 #include <apt-pkg/pkgrecords.h>
 #include <apt-pkg/srcrecords.h>
+#include <apt-pkg/sptr.h>
 
 #include <stdio.h>
 #include <iostream>
@@ -667,6 +668,97 @@ APT_CONST bool debStatusIndex::Exists() const
 }
                                                                        /*}}}*/
 
+// debDebPkgFile - Single .deb file                                    /*{{{*/
+// ---------------------------------------------------------------------
+debDebPkgFileIndex::debDebPkgFileIndex(std::string DebFile)
+   : pkgIndexFile(true), DebFile(DebFile)
+{
+   DebFileFullPath = flAbsPath(DebFile);
+}
+
+std::string debDebPkgFileIndex::ArchiveURI(std::string /*File*/) const
+{
+   return "file:" + DebFileFullPath;
+}
+
+bool debDebPkgFileIndex::Exists() const
+{
+   return FileExists(DebFile);
+}
+bool debDebPkgFileIndex::Merge(pkgCacheGenerator& Gen, OpProgress* Prog) const
+{
+   if(Prog)
+      Prog->SubProgress(0, "Reading deb file");
+
+   // get the control data out of the deb file vid dpkg -I
+   // ... can I haz libdpkg?
+   const char *Args[5] = {"/usr/bin/dpkg",
+                          "-I",
+                          DebFile.c_str(),
+                          "control",
+                          NULL};
+   FileFd PipeFd;
+   pid_t Child;
+   if(Popen(Args, PipeFd, Child, FileFd::ReadOnly) == false)
+      return _error->Error("Popen failed");
+   // FIXME: static buffer
+   char buf[8*1024];
+   unsigned long long n = 0;
+   if(PipeFd.Read(buf, sizeof(buf)-1, &n) == false)
+      return _error->Errno("read", "Failed to read dpkg pipe");
+   ExecWait(Child, "Popen");
+
+   // now write the control data to a tempfile
+   SPtr<FileFd> DebControl = GetTempFile("deb-file-" + DebFile);
+   if(DebControl == NULL)
+      return false;
+   DebControl->Write(buf, n);
+   // append size of the file
+   FileFd Fd(DebFile, FileFd::ReadOnly);
+   string Size;
+   strprintf(Size, "Size: %llu\n", Fd.Size());
+   DebControl->Write(Size.c_str(), Size.size());
+   // and rewind for the listparser
+   DebControl->Seek(0);
+
+   // and give it to the list parser
+   debDebFileParser Parser(DebControl, DebFile);
+   if(Gen.SelectFile(DebFile, "local", *this) == false)
+      return _error->Error("Problem with SelectFile %s", DebFile.c_str());
+
+   pkgCache::PkgFileIterator File = Gen.GetCurFile();
+   File->Size = DebControl->Size();
+   File->mtime = DebControl->ModificationTime();
+   
+   if (Gen.MergeList(Parser) == false)
+      return _error->Error("Problem with MergeLister for %s", DebFile.c_str());
+
+   return true;
+}
+pkgCache::PkgFileIterator debDebPkgFileIndex::FindInCache(pkgCache &Cache) const
+{
+   // FIXME: we could simply always return pkgCache::PkgFileIterator(Cache);
+   //        to indicate its never in the cache which will force a Merge()
+   pkgCache::PkgFileIterator File = Cache.FileBegin();
+   for (; File.end() == false; ++File)
+   {
+       if (File.FileName() == NULL || DebFile != File.FileName())
+        continue;
+
+       return File;
+   }
+   
+   return File;
+}
+unsigned long debDebPkgFileIndex::Size() const
+{
+   struct stat buf;
+   if(stat(DebFile.c_str(), &buf) != 0)
+      return 0;
+   return buf.st_size;
+}
+                                                                       /*}}}*/
+
 // Index File types for Debian                                         /*{{{*/
 class debIFTypeSrc : public pkgIndexFile::Type
 {
@@ -699,10 +791,20 @@ class debIFTypeStatus : public pkgIndexFile::Type
    };
    debIFTypeStatus() {Label = "Debian dpkg status file";};
 };
+class debIFTypeDebPkgFile : public pkgIndexFile::Type
+{
+   public:
+   virtual pkgRecords::Parser *CreatePkgParser(pkgCache::PkgFileIterator File) const 
+   {
+      return new debDebFileRecordParser(File.FileName(),*File.Cache());
+   };
+   debIFTypeDebPkgFile() {Label = "deb Package file";};
+};
 static debIFTypeSrc _apt_Src;
 static debIFTypePkg _apt_Pkg;
 static debIFTypeTrans _apt_Trans;
 static debIFTypeStatus _apt_Status;
+static debIFTypeDebPkgFile _apt_DebPkgFile;
 
 const pkgIndexFile::Type *debSourcesIndex::GetType() const
 {
@@ -720,5 +822,8 @@ const pkgIndexFile::Type *debStatusIndex::GetType() const
 {
    return &_apt_Status;
 }
-
+const pkgIndexFile::Type *debDebPkgFileIndex::GetType() const
+{
+   return &_apt_DebPkgFile;
+}
                                                                        /*}}}*/
index 017c69a0a907c67c36ad35f66128945dd1beef5a..69754e79d469490a3fee43eca7dc35014ce98f03 100644 (file)
@@ -164,4 +164,35 @@ class debSourcesIndex : public pkgIndexFile
    virtual ~debSourcesIndex() {};
 };
 
+class debDebPkgFileIndex : public pkgIndexFile
+{
+ private:
+   void *d;
+   std::string DebFile;
+   std::string DebFileFullPath;
+
+ public:
+   virtual const Type *GetType() const APT_CONST;
+
+   virtual std::string Describe(bool /*Short*/) const {
+      return DebFile;
+   }
+
+   // Interface for the Cache Generator
+   virtual bool Exists() const;
+   virtual bool HasPackages() const {
+      return true;
+   };
+   virtual unsigned long Size() const;
+   virtual bool Merge(pkgCacheGenerator &Gen,OpProgress *Prog) const;
+   virtual pkgCache::PkgFileIterator FindInCache(pkgCache &Cache) const;
+
+   // Interface for acquire
+   virtual std::string ArchiveURI(std::string /*File*/) const;
+
+   debDebPkgFileIndex(std::string DebFile);
+   virtual ~debDebPkgFileIndex() {};
+   
+};
+
 #endif
index a1bcfb710432cc44facf49fd394cb231f8b4c319..d5e3ccb655db9cfccbfdb4da64350c9845d6f5c7 100644 (file)
@@ -959,3 +959,23 @@ bool debListParser::SameVersion(unsigned short const Hash,         /*{{{*/
 }
                                                                        /*}}}*/
 #endif
+
+
+debDebFileParser::debDebFileParser(FileFd *File, std::string const &DebFile)
+   : debListParser(File, ""), DebFile(DebFile)
+{
+}
+
+bool debDebFileParser::UsePackage(pkgCache::PkgIterator &Pkg,
+                                  pkgCache::VerIterator &Ver)
+{
+   bool res = debListParser::UsePackage(Pkg, Ver);
+   // we use the full file path as a provides so that the file is found
+   // by its name
+   if(NewProvidesAllArch(Ver, DebFile, Ver.VerStr()) == false)
+      return false;
+   return res;
+}
+
+
+
index baace79fe1f632f5bb25f565afba015a3e4061fb..92ec048b1086fa727a6fcdb1237a972197456435 100644 (file)
@@ -56,7 +56,8 @@ class debListParser : public pkgCacheGenerator::ListParser
    bool ParseProvides(pkgCache::VerIterator &Ver);
    bool NewProvidesAllArch(pkgCache::VerIterator &Ver, std::string const &Package, std::string const &Version);
    static bool GrabWord(std::string Word,WordList *List,unsigned char &Out);
-   
+   APT_HIDDEN unsigned char ParseMultiArch(bool const showErrors);
+
    public:
 
    static unsigned char GetPrio(std::string Str);
@@ -101,9 +102,17 @@ class debListParser : public pkgCacheGenerator::ListParser
 
    debListParser(FileFd *File, std::string const &Arch = "");
    virtual ~debListParser() {};
+};
 
-   private:
-   APT_HIDDEN unsigned char ParseMultiArch(bool const showErrors);
+class debDebFileParser : public debListParser
+{
+ private:
+   std::string DebFile;
+
+ public:
+   debDebFileParser(FileFd *File, std::string const &DebFile);
+   virtual bool UsePackage(pkgCache::PkgIterator &Pkg,
+                          pkgCache::VerIterator &Ver);
 };
 
 #endif
index 6fd12add8f3589cf02fdb1fd84b596e70f7986b4..56eecdca11c201fa14efdac74557fdeead141619 100644 (file)
@@ -471,6 +471,15 @@ class debSLTypeDebian : public pkgSourceList::Type
    }
 };
 
+debDebFileMetaIndex::debDebFileMetaIndex(std::string const &DebFile)
+   : metaIndex(DebFile, "local-uri", "deb-dist"), DebFile(DebFile)
+{
+   DebIndex = new debDebPkgFileIndex(DebFile);
+   Indexes = new vector<pkgIndexFile *>();
+   Indexes->push_back(DebIndex);
+}
+
+
 class debSLTypeDeb : public debSLTypeDebian
 {
    public:
@@ -507,5 +516,25 @@ class debSLTypeDebSrc : public debSLTypeDebian
    }   
 };
 
+class debSLTypeDebFile : public pkgSourceList::Type
+{
+   public:
+
+   bool CreateItem(vector<metaIndex *> &List, string const &URI,
+                  string const &Dist, string const &Section,
+                  std::map<string, string> const &Options) const
+   {
+      metaIndex *mi = new debDebFileMetaIndex(URI);
+      List.push_back(mi);
+      return true;
+   }
+   
+   debSLTypeDebFile()
+   {
+      Name = "deb-file";
+      Label = "Debian Deb File";
+   }   
+};
 debSLTypeDeb _apt_DebType;
 debSLTypeDebSrc _apt_DebSrcType;
+debSLTypeDebFile _apt_DebFileType;
index 2286fa8b2c88e63bb376e7eeb4ca783464432545..0e70bba87d0986da01a067fec374fdfb7f166abf 100644 (file)
@@ -18,6 +18,7 @@
 
 class pkgAcquire;
 class pkgIndexFile;
+class debDebPkgFileIndex;
 
 class debReleaseIndex : public metaIndex {
    public:
@@ -71,4 +72,27 @@ class debReleaseIndex : public metaIndex {
    void PushSectionEntry(const debSectionEntry *Entry);
 };
 
+class debDebFileMetaIndex : public metaIndex
+{
+ private:
+   std::string DebFile;
+   debDebPkgFileIndex *DebIndex;
+ public:
+   virtual std::string ArchiveURI(std::string const& /*File*/) const {
+      return DebFile;
+   }
+   virtual bool GetIndexes(pkgAcquire* /*Owner*/, const bool& /*GetAll=false*/) const {
+      return true;
+   }
+   virtual std::vector<pkgIndexFile *> *GetIndexFiles() {
+      return Indexes;
+   }
+   virtual bool IsTrusted() const {
+      return true;
+   }
+   debDebFileMetaIndex(std::string const &DebFile);
+   virtual ~debDebFileMetaIndex() {};
+
+};
+
 #endif
index bdac6c90b8c8883f779e68f8d78780a56bf573c1..d572bc5c20b5605cafc775dfb99aabad2a1771a3 100644 (file)
@@ -29,17 +29,16 @@ class debRecordParser : public pkgRecords::Parser
 {
    /** \brief dpointer placeholder (for later in case we need it) */
    void *d;
-
+   
+ protected:
    FileFd File;
    pkgTagFile Tags;
    pkgTagSection Section;
    
-   protected:
-   
    virtual bool Jump(pkgCache::VerFileIterator const &Ver);
    virtual bool Jump(pkgCache::DescFileIterator const &Desc);
    
  public:
+ public:
 
    // These refer to the archive file for the Version
    virtual std::string FileName();
@@ -66,4 +65,15 @@ class debRecordParser : public pkgRecords::Parser
    virtual ~debRecordParser() {};
 };
 
+// custom record parser that reads deb files directly
+class debDebFileRecordParser : public debRecordParser
+{
+ public:
+   virtual std::string FileName() {
+      return File.Name();
+   }
+   debDebFileRecordParser(std::string FileName,pkgCache &Cache)
+      : debRecordParser(FileName, Cache) {};
+};
+
 #endif
index 9df0c1d7419c3fbd46e38fef1d113fbd8e06b067..4943dd32acb93f50ca075f3de6fd184b745a22b9 100644 (file)
@@ -116,6 +116,11 @@ class pkgSourceList
    // query last-modified time
    time_t GetLastModifiedTime();
 
+   // Add custom metaIndex (e.g. local files)
+   void Add(metaIndex *mi) {
+      SrcList.push_back(mi);
+   }
+
    pkgSourceList();
    pkgSourceList(std::string File);
    ~pkgSourceList();      
index 107ed398e30f6a9dbe7a639d636fa5b9b927a967..4a68bb9d167940e764bd21647659968432e3309b 100644 (file)
@@ -19,6 +19,7 @@
 #include <apt-pkg/macros.h>
 #include <apt-pkg/packagemanager.h>
 #include <apt-pkg/pkgcache.h>
+#include <apt-pkg/sourcelist.h>
 
 #include <errno.h>
 #include <stdlib.h>
@@ -29,6 +30,7 @@
 #include <iostream>
 #include <set>
 #include <vector>
+#include <map>
 
 #include <apt-private/acqprogress.h>
 #include <apt-private/private-install.h>
@@ -669,10 +671,32 @@ bool DoCacheManipulationFromCommandLine(CommandLine &CmdL, CacheFile &Cache,
 bool DoInstall(CommandLine &CmdL)
 {
    CacheFile Cache;
+   // first check for local pkgs and add them to the cache
+   for (const char **I = CmdL.FileList; *I != 0; I++)
+   {
+      if(FileExists(*I))
+      {
+         // FIXME: make this more elegant
+         std::string TypeStr = flExtension(*I) + "-file";
+         pkgSourceList::Type *Type = pkgSourceList::Type::GetType(TypeStr.c_str());
+         if(Type != 0)
+         {
+            std::vector<metaIndex *> List;
+            std::map<std::string, std::string> Options;
+            if(Type->CreateItem(List, *I, "", "", Options))
+            {
+               pkgSourceList *sources = Cache.GetSourceList();
+               sources->Add(List[0]);
+            }
+         }
+      }
+   }
+
+   // then open the cache
    if (Cache.OpenForInstall() == false || 
        Cache.CheckDeps(CmdL.FileSize() != 1) == false)
       return false;
-
+   
    std::map<unsigned short, APT::VersionSet> verset;
 
    if(!DoCacheManipulationFromCommandLine(CmdL, Cache, verset))
index 15b57983beaef51b79560eb2ea5d387c4e4b3c68..cdf7ea479a75bf276ce3f58237c4fa859d464b30 100644 (file)
@@ -224,6 +224,53 @@ TEST(FileUtlTest, GetTempDir)
    if (old_tmpdir.empty() == false)
       setenv("TMPDIR", old_tmpdir.c_str(), 1);
 }
+TEST(FileUtlTest, Popen)
+{
+   FileFd Fd;
+   pid_t Child;
+   char buf[1024];
+   std::string s;
+   unsigned long long n = 0;
+   std::vector<std::string> OpenFds;
+
+   // count Fds to ensure we don't have a resource leak
+   if(FileExists("/proc/self/fd"))
+      OpenFds = Glob("/proc/self/fd/*");
+
+   // output something
+   const char* Args[10] = {"/bin/echo", "meepmeep", NULL};
+   bool res = Popen(Args, Fd, Child, FileFd::ReadOnly);
+   Fd.Read(buf, sizeof(buf)-1, &n);
+   buf[n] = 0;
+   EXPECT_NE(n, 0);
+   EXPECT_EQ(res, true);
+   EXPECT_STREQ(buf, "meepmeep\n");
+
+   // wait for the child to exit and cleanup
+   ExecWait(Child, "PopenRead");
+   Fd.Close();
+
+   // ensure that after a close all is good again
+   if(FileExists("/proc/self/fd"))
+      EXPECT_EQ(Glob("/proc/self/fd/*").size(), OpenFds.size());
+
+
+   // ReadWrite is not supported
+   res = Popen(Args, Fd, Child, FileFd::ReadWrite);
+   EXPECT_EQ(res, false);
+   _error->Discard();
+
+   // write something
+   Args[0] = "/bin/bash";
+   Args[1] = "-c";
+   Args[2] = "read";
+   Args[3] = NULL;
+   res = Popen(Args, Fd, Child, FileFd::WriteOnly);
+   s = "\n";
+   Fd.Write(s.c_str(), s.size());
+   Fd.Close();
+   ExecWait(Child, "PopenWrite");
+}
 TEST(FileUtlTest, flAbsPath)
 {
    std::string cwd = SafeGetCWD();