Просмотр исходного кода

* apt-pkg/contrib/mmap.{h,cc}:
- add char[] fallback for filesystems without shared writable
mmap() like JFFS2. Thanks to Marius Vollmer for writing
and to Loïc Minier for pointing to the patch! (Closes: #314334)

David Kalnischkies лет назад: 16
Родитель
Сommit
06afffcc24
3 измененных файлов с 68 добавлено и 11 удалено
  1. 59 11
      apt-pkg/contrib/mmap.cc
  2. 5 0
      apt-pkg/contrib/mmap.h
  3. 4 0
      debian/changelog

+ 59 - 11
apt-pkg/contrib/mmap.cc

@@ -27,6 +27,7 @@
 #include <unistd.h>
 #include <fcntl.h>
 #include <stdlib.h>
+#include <errno.h>
 
 #include <cstring>
    									/*}}}*/
@@ -35,7 +36,7 @@
 // ---------------------------------------------------------------------
 /* */
 MMap::MMap(FileFd &F,unsigned long Flags) : Flags(Flags), iSize(0),
-                     Base(0)
+                     Base(0), SyncToFd(NULL)
 {
    if ((Flags & NoImmMap) != NoImmMap)
       Map(F);
@@ -45,7 +46,7 @@ MMap::MMap(FileFd &F,unsigned long Flags) : Flags(Flags), iSize(0),
 // ---------------------------------------------------------------------
 /* */
 MMap::MMap(unsigned long Flags) : Flags(Flags), iSize(0),
-                     Base(0)
+                     Base(0), SyncToFd(NULL)
 {
 }
 									/*}}}*/
@@ -78,7 +79,24 @@ bool MMap::Map(FileFd &Fd)
    // Map it.
    Base = mmap(0,iSize,Prot,Map,Fd.Fd(),0);
    if (Base == (void *)-1)
-      return _error->Errno("mmap",_("Couldn't make mmap of %lu bytes"),iSize);
+   {
+      if (errno == ENODEV || errno == EINVAL)
+      {
+	 // The filesystem doesn't support this particular kind of mmap.
+	 // So we allocate a buffer and read the whole file into it.
+	 int const dupped_fd = dup(Fd.Fd());
+	 if (dupped_fd == -1)
+	    return _error->Errno("mmap", _("Couldn't duplicate file descriptor %i"), Fd.Fd());
+
+	 Base = new unsigned char[iSize];
+	 SyncToFd = new FileFd (dupped_fd);
+	 if (!SyncToFd->Seek(0L) || !SyncToFd->Read(Base, iSize))
+	    return false;
+      }
+      else
+	 return _error->Errno("mmap",_("Couldn't make mmap of %lu bytes"),
+	                      iSize);
+     }
 
    return true;
 }
@@ -93,10 +111,19 @@ bool MMap::Close(bool DoSync)
    
    if (DoSync == true)
       Sync();
-   
-   if (munmap((char *)Base,iSize) != 0)
-      _error->Warning("Unable to munmap");
-   
+
+   if (SyncToFd != NULL)
+   {
+      delete[] (char *)Base;
+      delete SyncToFd;
+      SyncToFd = NULL;
+   }
+   else
+   {
+      if (munmap((char *)Base, iSize) != 0)
+	 _error->WarningE("mmap", _("Unable to close mmap"));
+   }
+
    iSize = 0;
    Base = 0;
    return true;
@@ -113,8 +140,18 @@ bool MMap::Sync()
    
 #ifdef _POSIX_SYNCHRONIZED_IO   
    if ((Flags & ReadOnly) != ReadOnly)
-      if (msync((char *)Base,iSize,MS_SYNC) < 0)
-	 return _error->Errno("msync","Unable to write mmap");
+   {
+      if (SyncToFd != NULL)
+      {
+	 if (!SyncToFd->Seek(0) || !SyncToFd->Write(Base, iSize))
+	    return false;
+      }
+      else
+      {
+	 if (msync((char *)Base, iSize, MS_SYNC) < 0)
+	    return _error->Errno("msync", _("Unable to synchronize mmap"));
+      }
+   }
 #endif   
    return true;
 }
@@ -130,8 +167,19 @@ bool MMap::Sync(unsigned long Start,unsigned long Stop)
 #ifdef _POSIX_SYNCHRONIZED_IO
    unsigned long PSize = sysconf(_SC_PAGESIZE);
    if ((Flags & ReadOnly) != ReadOnly)
-      if (msync((char *)Base+(int)(Start/PSize)*PSize,Stop - Start,MS_SYNC) < 0)
-	 return _error->Errno("msync","Unable to write mmap");
+   {
+      if (SyncToFd != 0)
+      {
+	 if (!SyncToFd->Seek(0) ||
+	     !SyncToFd->Write (((char *)Base)+Start, Stop-Start))
+	    return false;
+      }
+      else
+      {
+	 if (msync((char *)Base+(int)(Start/PSize)*PSize,Stop - Start,MS_SYNC) < 0)
+	    return _error->Errno("msync", _("Unable to synchronize mmap"));
+      }
+   }
 #endif   
    return true;
 }

+ 5 - 0
apt-pkg/contrib/mmap.h

@@ -44,6 +44,11 @@ class MMap
    unsigned long iSize;
    void *Base;
 
+   // In case mmap can not be used, we keep a dup of the file
+   // descriptor that should have been mmaped so that we can write to
+   // the file in Sync().
+   FileFd *SyncToFd;
+
    bool Map(FileFd &Fd);
    bool Close(bool DoSync = true);
    

+ 4 - 0
debian/changelog

@@ -5,6 +5,10 @@ apt (0.7.26) UNRELEASED; urgency=low
     - don't crash if no arguments are given (Closes: #570962)
   * debian/control:
     - remove some years old and obsolete Replaces
+  * apt-pkg/contrib/mmap.{h,cc}:
+    - add char[] fallback for filesystems without shared writable
+      mmap() like JFFS2. Thanks to Marius Vollmer for writing
+      and to Loïc Minier for pointing to the patch! (Closes: #314334)
 
  -- David Kalnischkies <kalnischkies@gmail.com>  Fri, 19 Feb 2010 21:21:43 +0100