X-Git-Url: https://git.saurik.com/apt.git/blobdiff_plain/06afffcc24f339e8735acd4698af6e5995ad24aa..b49068c566d749130e023536d54588c948c16edf:/apt-pkg/contrib/mmap.cc diff --git a/apt-pkg/contrib/mmap.cc b/apt-pkg/contrib/mmap.cc index b3f29032c..8e169027e 100644 --- a/apt-pkg/contrib/mmap.cc +++ b/apt-pkg/contrib/mmap.cc @@ -17,20 +17,22 @@ /*}}}*/ // Include Files /*{{{*/ #define _BSD_SOURCE +#include + #include #include +#include +#include -#include - +#include #include -#include #include -#include #include #include - #include - /*}}}*/ + +#include + /*}}}*/ // MMap::MMap - Constructor /*{{{*/ // --------------------------------------------------------------------- @@ -64,7 +66,7 @@ MMap::~MMap() bool MMap::Map(FileFd &Fd) { iSize = Fd.Size(); - + // Set the permissions. int Prot = PROT_READ; int Map = MAP_SHARED; @@ -75,26 +77,46 @@ bool MMap::Map(FileFd &Fd) if (iSize == 0) return _error->Error(_("Can't mmap an empty file")); - + + // We can't mmap compressed fd's directly, so we need to read it completely + if (Fd.IsCompressed() == true) + { + if ((Flags & ReadOnly) != ReadOnly) + return _error->Error("Compressed file %s can only be mapped readonly", Fd.Name().c_str()); + Base = malloc(iSize); + SyncToFd = new FileFd(); + if (Fd.Seek(0L) == false || Fd.Read(Base, iSize) == false) + return _error->Error("Compressed file %s can't be read into mmap", Fd.Name().c_str()); + return true; + } + // Map it. - Base = mmap(0,iSize,Prot,Map,Fd.Fd(),0); + Base = (Flags & Fallback) ? MAP_FAILED : mmap(0,iSize,Prot,Map,Fd.Fd(),0); if (Base == (void *)-1) { - if (errno == ENODEV || errno == EINVAL) + if (errno == ENODEV || errno == EINVAL || (Flags & Fallback)) { // The filesystem doesn't support this particular kind of mmap. // So we allocate a buffer and read the whole file into it. + if ((Flags & ReadOnly) == ReadOnly) + { + // for readonly, we don't need sync, so make it simple + Base = malloc(iSize); + SyncToFd = new FileFd(); + return Fd.Read(Base, iSize); + } + // FIXME: Writing to compressed fd's ? 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]; + Base = calloc(iSize, 1); 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"), + return _error->Errno("mmap",_("Couldn't make mmap of %llu bytes"), iSize); } @@ -106,7 +128,7 @@ bool MMap::Map(FileFd &Fd) /* */ bool MMap::Close(bool DoSync) { - if ((Flags & UnMapped) == UnMapped || Base == 0 || iSize == 0) + if ((Flags & UnMapped) == UnMapped || validData() == false || iSize == 0) return true; if (DoSync == true) @@ -114,7 +136,7 @@ bool MMap::Close(bool DoSync) if (SyncToFd != NULL) { - delete[] (char *)Base; + free(Base); delete SyncToFd; SyncToFd = NULL; } @@ -134,11 +156,10 @@ bool MMap::Close(bool DoSync) /* This is done in syncronous mode - the docs indicate that this will not return till all IO is complete */ bool MMap::Sync() -{ +{ if ((Flags & UnMapped) == UnMapped) return true; - -#ifdef _POSIX_SYNCHRONIZED_IO + if ((Flags & ReadOnly) != ReadOnly) { if (SyncToFd != NULL) @@ -148,11 +169,12 @@ bool MMap::Sync() } else { +#ifdef _POSIX_SYNCHRONIZED_IO if (msync((char *)Base, iSize, MS_SYNC) < 0) return _error->Errno("msync", _("Unable to synchronize mmap")); +#endif } } -#endif return true; } /*}}}*/ @@ -163,9 +185,7 @@ bool MMap::Sync(unsigned long Start,unsigned long Stop) { if ((Flags & UnMapped) == UnMapped) return true; - -#ifdef _POSIX_SYNCHRONIZED_IO - unsigned long PSize = sysconf(_SC_PAGESIZE); + if ((Flags & ReadOnly) != ReadOnly) { if (SyncToFd != 0) @@ -176,11 +196,13 @@ bool MMap::Sync(unsigned long Start,unsigned long Stop) } else { - if (msync((char *)Base+(int)(Start/PSize)*PSize,Stop - Start,MS_SYNC) < 0) +#ifdef _POSIX_SYNCHRONIZED_IO + unsigned long long const PSize = sysconf(_SC_PAGESIZE); + if (msync((char *)Base+(Start/PSize)*PSize, Stop - Start, MS_SYNC) < 0) return _error->Errno("msync", _("Unable to synchronize mmap")); +#endif } } -#endif return true; } /*}}}*/ @@ -193,10 +215,17 @@ DynamicMMap::DynamicMMap(FileFd &F,unsigned long Flags,unsigned long const &Work MMap(F,Flags | NoImmMap), Fd(&F), WorkSpace(Workspace), GrowFactor(Grow), Limit(Limit) { - if (_error->PendingError() == true) - return; - - unsigned long EndOfFile = Fd->Size(); + // disable Moveable if we don't grow + if (Grow == 0) + this->Flags &= ~Moveable; + +#ifndef __linux__ + // kfreebsd doesn't have mremap, so we use the fallback + if ((this->Flags & Moveable) == Moveable) + this->Flags |= Fallback; +#endif + + unsigned long long EndOfFile = Fd->Size(); if (EndOfFile > WorkSpace) WorkSpace = EndOfFile; else if(WorkSpace > 0) @@ -220,28 +249,33 @@ DynamicMMap::DynamicMMap(unsigned long Flags,unsigned long const &WorkSpace, MMap(Flags | NoImmMap | UnMapped), Fd(0), WorkSpace(WorkSpace), GrowFactor(Grow), Limit(Limit) { - if (_error->PendingError() == true) - return; - // disable Moveable if we don't grow if (Grow == 0) - Flags &= ~Moveable; + this->Flags &= ~Moveable; #ifndef __linux__ // kfreebsd doesn't have mremap, so we use the fallback - if ((Flags & Moveable) == Moveable) - Flags |= Fallback; + if ((this->Flags & Moveable) == Moveable) + this->Flags |= Fallback; #endif #ifdef _POSIX_MAPPED_FILES - if ((Flags & Fallback) != Fallback) { + if ((this->Flags & Fallback) != Fallback) { // Set the permissions. int Prot = PROT_READ; +#ifdef MAP_ANONYMOUS int Map = MAP_PRIVATE | MAP_ANONYMOUS; - if ((Flags & ReadOnly) != ReadOnly) +#else + int Map = MAP_PRIVATE | MAP_ANON; +#endif + if ((this->Flags & ReadOnly) != ReadOnly) Prot |= PROT_WRITE; - if ((Flags & Public) == Public) + if ((this->Flags & Public) == Public) +#ifdef MAP_ANONYMOUS Map = MAP_SHARED | MAP_ANONYMOUS; +#else + Map = MAP_SHARED | MAP_ANON; +#endif // use anonymous mmap() to get the memory Base = (unsigned char*) mmap(0, WorkSpace, Prot, Map, -1, 0); @@ -254,8 +288,7 @@ DynamicMMap::DynamicMMap(unsigned long Flags,unsigned long const &WorkSpace, } #endif // fallback to a static allocated space - Base = new unsigned char[WorkSpace]; - memset(Base,0,WorkSpace); + Base = calloc(WorkSpace, 1); iSize = 0; } /*}}}*/ @@ -266,15 +299,17 @@ DynamicMMap::~DynamicMMap() { if (Fd == 0) { + if (validData() == false) + return; #ifdef _POSIX_MAPPED_FILES munmap(Base, WorkSpace); #else - delete [] (unsigned char *)Base; + free(Base); #endif return; } - unsigned long EndOfFile = iSize; + unsigned long long EndOfFile = iSize; iSize = WorkSpace; Close(false); if(ftruncate(Fd->Fd(),EndOfFile) < 0) @@ -284,9 +319,9 @@ DynamicMMap::~DynamicMMap() // DynamicMMap::RawAllocate - Allocate a raw chunk of unaligned space /*{{{*/ // --------------------------------------------------------------------- /* This allocates a block of memory aligned to the given size */ -unsigned long DynamicMMap::RawAllocate(unsigned long Size,unsigned long Aln) +unsigned long DynamicMMap::RawAllocate(unsigned long long Size,unsigned long Aln) { - unsigned long Result = iSize; + unsigned long long Result = iSize; if (Aln != 0) Result += Aln - (iSize%Aln); @@ -297,8 +332,8 @@ unsigned long DynamicMMap::RawAllocate(unsigned long Size,unsigned long Aln) { if(!Grow()) { - _error->Error(_("Dynamic MMap ran out of room. Please increase the size " - "of APT::Cache-Limit. Current value: %lu. (man 5 apt.conf)"), WorkSpace); + _error->Fatal(_("Dynamic MMap ran out of room. Please increase the size " + "of APT::Cache-Start. Current value: %lu. (man 5 apt.conf)"), WorkSpace); return 0; } } @@ -311,10 +346,16 @@ unsigned long DynamicMMap::RawAllocate(unsigned long Size,unsigned long Aln) size in the file. */ unsigned long DynamicMMap::Allocate(unsigned long ItemSize) { + if (unlikely(ItemSize == 0)) + { + _error->Fatal("Can't allocate an item of size zero"); + return 0; + } + // Look for a matching pool entry Pool *I; Pool *Empty = 0; - for (I = Pools; I != Pools + PoolCount; I++) + for (I = Pools; I != Pools + PoolCount; ++I) { if (I->ItemSize == 0) Empty = I; @@ -342,9 +383,16 @@ unsigned long DynamicMMap::Allocate(unsigned long ItemSize) { const unsigned long size = 20*1024; I->Count = size/ItemSize; + Pool* oldPools = Pools; + _error->PushToStack(); Result = RawAllocate(size,ItemSize); + bool const newError = _error->PendingError(); + _error->MergeWithStack(); + if (Pools != oldPools) + I += Pools - oldPools; + // Does the allocation failed ? - if (Result == 0 && _error->PendingError()) + if (Result == 0 && newError) return 0; I->Start = Result; } @@ -365,9 +413,12 @@ unsigned long DynamicMMap::WriteString(const char *String, if (Len == (unsigned long)-1) Len = strlen(String); - unsigned long Result = RawAllocate(Len+1,0); + _error->PushToStack(); + unsigned long const Result = RawAllocate(Len+1,0); + bool const newError = _error->PendingError(); + _error->MergeWithStack(); - if (Result == 0 && _error->PendingError()) + if (Base == NULL || (Result == 0 && newError)) return 0; memcpy((char *)Base + Result,String,Len); @@ -392,19 +443,25 @@ unsigned long DynamicMMap::WriteString(const char *String, the nearly impossible 4 to grow it before it finally give up: Never say never. */ bool DynamicMMap::Grow() { if (Limit != 0 && WorkSpace >= Limit) - return _error->Error(_("The size of a MMap has already reached the defined limit of %lu bytes," - "abort the try to grow the MMap."), Limit); + return _error->Error(_("Unable to increase the size of the MMap as the " + "limit of %lu bytes is already reached."), Limit); + if (GrowFactor <= 0) + return _error->Error(_("Unable to increase size of the MMap as automatic growing is disabled by user.")); - unsigned long const newSize = WorkSpace + 1024*1024; + unsigned long long const newSize = WorkSpace + GrowFactor; if(Fd != 0) { Fd->Seek(newSize - 1); char C = 0; Fd->Write(&C,sizeof(C)); } + + unsigned long const poolOffset = Pools - ((Pool*) Base); + if ((Flags & Fallback) != Fallback) { #if defined(_POSIX_MAPPED_FILES) && defined(__linux__) #ifdef MREMAP_MAYMOVE + if ((Flags & Moveable) == Moveable) Base = mremap(Base, WorkSpace, newSize, MREMAP_MAYMOVE); else @@ -423,8 +480,12 @@ bool DynamicMMap::Grow() { Base = realloc(Base, newSize); if (Base == NULL) return false; + else + /* Set new memory to 0 */ + memset((char*)Base + WorkSpace, 0, newSize - WorkSpace); } + Pools =(Pool*) Base + poolOffset; WorkSpace = newSize; return true; }