mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 683127 part 8 - Allow to load Elf files from a Zip archive. r=tglek,r=sewardj
This commit is contained in:
parent
372473a08a
commit
c1f8abcc72
@ -83,6 +83,10 @@ LIBS += \
|
||||
$(XPCOM_STANDALONE_GLUE_LDOPTS) \
|
||||
$(NULL)
|
||||
|
||||
ifdef MOZ_LINKER
|
||||
LIBS += $(ZLIB_LIBS)
|
||||
endif
|
||||
|
||||
ifndef MOZ_WINCONSOLE
|
||||
ifdef MOZ_DEBUG
|
||||
MOZ_WINCONSOLE = 1
|
||||
|
@ -7159,6 +7159,9 @@ else
|
||||
dnl And we need mozglue symbols to be exported.
|
||||
MOZ_GLUE_PROGRAM_LDFLAGS="$MOZ_GLUE_PROGRAM_LDFLAGS -rdynamic"
|
||||
fi
|
||||
if test "$MOZ_LINKER" = 1; then
|
||||
MOZ_GLUE_PROGRAM_LDFLAGS="$MOZ_GLUE_PROGRAM_LDFLAGS $ZLIB_LIBS"
|
||||
fi
|
||||
fi
|
||||
|
||||
if test -z "$MOZ_MEMORY"; then
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include <vector>
|
||||
#include <dlfcn.h>
|
||||
#include "CustomElf.h"
|
||||
#include "Mappable.h"
|
||||
#include "Logging.h"
|
||||
|
||||
using namespace Elf;
|
||||
@ -73,18 +74,37 @@ void debug_phdr(const char *type, const Phdr *phdr)
|
||||
|
||||
} /* anonymous namespace */
|
||||
|
||||
/**
|
||||
* RAII wrapper for a mapping of the first page off a Mappable object.
|
||||
* This calls Mappable::munmap instead of system munmap.
|
||||
*/
|
||||
class Mappable1stPagePtr: public GenericMappedPtr<Mappable1stPagePtr> {
|
||||
public:
|
||||
Mappable1stPagePtr(Mappable *mappable)
|
||||
: GenericMappedPtr<Mappable1stPagePtr>(
|
||||
mappable->mmap(NULL, PAGE_SIZE, PROT_READ, MAP_PRIVATE, 0), PAGE_SIZE)
|
||||
, mappable(mappable)
|
||||
{ }
|
||||
|
||||
void munmap(void *buf, size_t length) {
|
||||
mappable->munmap(buf, length);
|
||||
}
|
||||
private:
|
||||
Mappable *mappable;
|
||||
};
|
||||
|
||||
|
||||
TemporaryRef<LibHandle>
|
||||
CustomElf::Load(int fd, const char *path, int flags)
|
||||
CustomElf::Load(Mappable *mappable, const char *path, int flags)
|
||||
{
|
||||
debug("CustomElf::Load(\"%s\", %x) = ...", path, flags);
|
||||
if (fd == -1)
|
||||
if (!mappable)
|
||||
return NULL;
|
||||
/* Keeping a RefPtr of the CustomElf is going to free the appropriate
|
||||
* resources when returning NULL */
|
||||
RefPtr<CustomElf> elf = new CustomElf(fd, path);
|
||||
RefPtr<CustomElf> elf = new CustomElf(mappable, path);
|
||||
/* Map the first page of the Elf object to access Elf and program headers */
|
||||
MappedPtr ehdr_raw(mmap(NULL, PAGE_SIZE, PROT_READ, MAP_PRIVATE, fd, 0),
|
||||
PAGE_SIZE);
|
||||
Mappable1stPagePtr ehdr_raw(mappable);
|
||||
if (ehdr_raw == MAP_FAILED)
|
||||
return NULL;
|
||||
|
||||
@ -169,6 +189,9 @@ CustomElf::Load(int fd, const char *path, int flags)
|
||||
if (!elf->LoadSegment(*it))
|
||||
return NULL;
|
||||
|
||||
/* We're not going to mmap anymore */
|
||||
mappable->finalize();
|
||||
|
||||
report_mapping(const_cast<char *>(elf->GetName()), elf->base,
|
||||
(max_vaddr + PAGE_SIZE - 1) & PAGE_MASK, 0);
|
||||
|
||||
@ -189,6 +212,7 @@ CustomElf::~CustomElf()
|
||||
* Android NDK before r6b doesn't do that. Our wrapped cxa_finalize only
|
||||
* calls destructors once, so call it in all cases. */
|
||||
ElfLoader::__wrap_cxa_finalize(this);
|
||||
delete mappable;
|
||||
}
|
||||
|
||||
namespace {
|
||||
@ -339,9 +363,9 @@ CustomElf::LoadSegment(const Phdr *pt_load) const
|
||||
prot & PROT_READ ? 'r' : '-',
|
||||
prot & PROT_WRITE ? 'w' : '-',
|
||||
prot & PROT_EXEC ? 'x' : '-');
|
||||
void *mapped = mmap(where, pt_load->p_filesz + page_offset,
|
||||
prot, MAP_PRIVATE | MAP_FIXED, fd,
|
||||
pt_load->p_offset - page_offset);
|
||||
void *mapped = mappable->mmap(where, pt_load->p_filesz + page_offset,
|
||||
prot, MAP_PRIVATE | MAP_FIXED,
|
||||
pt_load->p_offset - page_offset);
|
||||
if (mapped != where) {
|
||||
if (mapped == MAP_FAILED) {
|
||||
log("%s: Failed to mmap", GetPath());
|
||||
@ -354,14 +378,9 @@ CustomElf::LoadSegment(const Phdr *pt_load) const
|
||||
|
||||
/* When p_memsz is greater than p_filesz, we need to have nulled out memory
|
||||
* after p_filesz and before p_memsz.
|
||||
* We first null out bytes after p_filesz and up to the end of the page
|
||||
* p_filesz is in. */
|
||||
Addr end_offset = pt_load->p_filesz + page_offset;
|
||||
if ((prot & PROT_WRITE) && (end_offset & ~PAGE_MASK)) {
|
||||
memset(reinterpret_cast<char *>(mapped) + end_offset,
|
||||
0, PAGE_SIZE - (end_offset & ~PAGE_MASK));
|
||||
}
|
||||
/* Above the end of that page, and up to p_memsz, we already have nulled out
|
||||
* Mappable::mmap already guarantees that after p_filesz and up to the end
|
||||
* of the page p_filesz is in, memory is nulled out.
|
||||
* Above the end of that page, and up to p_memsz, we already have nulled out
|
||||
* memory because we mapped anonymous memory on the whole library virtual
|
||||
* address space. We just need to adjust this anonymous memory protection
|
||||
* flags. */
|
||||
|
@ -202,6 +202,8 @@ struct Rela: public Elf_(Rela)
|
||||
|
||||
} /* namespace Elf */
|
||||
|
||||
class Mappable;
|
||||
|
||||
/**
|
||||
* Library Handle class for ELF libraries we don't let the system linker
|
||||
* handle.
|
||||
@ -218,7 +220,7 @@ public:
|
||||
* currently, none are supported and the behaviour is more or less that of
|
||||
* RTLD_GLOBAL | RTLD_BIND_NOW.
|
||||
*/
|
||||
static mozilla::TemporaryRef<LibHandle> Load(int fd,
|
||||
static mozilla::TemporaryRef<LibHandle> Load(Mappable *mappable,
|
||||
const char *path, int flags);
|
||||
|
||||
/**
|
||||
@ -251,8 +253,8 @@ private:
|
||||
/**
|
||||
* Private constructor
|
||||
*/
|
||||
CustomElf(int fd, const char *path)
|
||||
: LibHandle(path), fd(fd), init(0), fini(0), initialized(false)
|
||||
CustomElf(Mappable *mappable, const char *path)
|
||||
: LibHandle(path), mappable(mappable), init(0), fini(0), initialized(false)
|
||||
{ }
|
||||
|
||||
/**
|
||||
@ -333,8 +335,8 @@ private:
|
||||
return CallFunction(GetPtr(addr));
|
||||
}
|
||||
|
||||
/* Appropriated file descriptor */
|
||||
AutoCloseFD fd;
|
||||
/* Appropriated Mappable */
|
||||
Mappable *mappable;
|
||||
|
||||
/* Base address where the library is loaded */
|
||||
MappedPtr base;
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include <fcntl.h>
|
||||
#include "ElfLoader.h"
|
||||
#include "CustomElf.h"
|
||||
#include "Mappable.h"
|
||||
#include "Logging.h"
|
||||
|
||||
using namespace mozilla;
|
||||
@ -189,13 +190,32 @@ ElfLoader::Load(const char *path, int flags, LibHandle *parent)
|
||||
path = abs_path;
|
||||
}
|
||||
|
||||
/* Try loading the file with the custom linker, and fall back to the
|
||||
* system linker if that fails */
|
||||
AutoCloseFD fd = open(path, O_RDONLY);
|
||||
if (fd != -1) {
|
||||
handle = CustomElf::Load(fd, path, flags);
|
||||
fd.forget();
|
||||
/* Create a mappable object for the given path. Paths in the form
|
||||
* /foo/bar/baz/archive!/directory/lib.so
|
||||
* try to load the directory/lib.so in /foo/bar/baz/archive, provided
|
||||
* that file is a Zip archive. */
|
||||
Mappable *mappable = NULL;
|
||||
RefPtr<Zip> zip;
|
||||
const char *subpath;
|
||||
if ((subpath = strchr(path, '!'))) {
|
||||
char *zip_path = strndup(path, subpath - path);
|
||||
while (*(++subpath) == '/') { }
|
||||
zip = zips.GetZip(zip_path);
|
||||
Zip::Stream s;
|
||||
if (zip && zip->GetStream(subpath, &s)) {
|
||||
if (s.GetType() == Zip::Stream::DEFLATE)
|
||||
mappable = MappableDeflate::Create(name, zip, &s);
|
||||
}
|
||||
}
|
||||
/* If we couldn't load above, try with a MappableFile */
|
||||
if (!mappable && !zip)
|
||||
mappable = MappableFile::Create(path);
|
||||
|
||||
/* Try loading with the custom linker if we have a Mappable */
|
||||
if (mappable)
|
||||
handle = CustomElf::Load(mappable, path, flags);
|
||||
|
||||
/* Try loading with the system linker if everything above failed */
|
||||
if (!handle)
|
||||
handle = SystemElf::Load(path, flags);
|
||||
|
||||
|
@ -288,6 +288,9 @@ protected:
|
||||
private:
|
||||
/* Keep track of all registered destructors */
|
||||
std::vector<DestructorCaller> destructors;
|
||||
|
||||
/* Keep track of Zips used for library loading */
|
||||
ZipCollection zips;
|
||||
};
|
||||
|
||||
#endif /* ElfLoader_h */
|
||||
|
@ -22,6 +22,7 @@ ifndef MOZ_OLD_LINKER
|
||||
CPPSRCS += \
|
||||
ElfLoader.cpp \
|
||||
CustomElf.cpp \
|
||||
Mappable.cpp \
|
||||
$(NULL)
|
||||
endif
|
||||
|
||||
|
247
mozglue/linker/Mappable.cpp
Normal file
247
mozglue/linker/Mappable.cpp
Normal file
@ -0,0 +1,247 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
#include <cstring>
|
||||
#include <cstdlib>
|
||||
#include "Mappable.h"
|
||||
#ifdef ANDROID
|
||||
#include <linux/ashmem.h>
|
||||
#endif
|
||||
#include "Logging.h"
|
||||
|
||||
#ifndef PAGE_SIZE
|
||||
#define PAGE_SIZE 4096
|
||||
#endif
|
||||
|
||||
#ifndef PAGE_MASK
|
||||
#define PAGE_MASK (~ (PAGE_SIZE - 1))
|
||||
#endif
|
||||
|
||||
MappableFile *MappableFile::Create(const char *path)
|
||||
{
|
||||
int fd = open(path, O_RDONLY);
|
||||
if (fd != -1)
|
||||
return new MappableFile(fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *
|
||||
MappableFile::mmap(const void *addr, size_t length, int prot, int flags,
|
||||
off_t offset)
|
||||
{
|
||||
// ASSERT(fd != -1)
|
||||
// ASSERT(! flags & MAP_SHARED)
|
||||
flags |= MAP_PRIVATE;
|
||||
|
||||
void *mapped = ::mmap(const_cast<void *>(addr), length, prot, flags,
|
||||
fd, offset);
|
||||
if (mapped == MAP_FAILED)
|
||||
return mapped;
|
||||
|
||||
/* Fill the remainder of the last page with zeroes when the requested
|
||||
* protection has write bits. */
|
||||
if ((mapped != MAP_FAILED) && (prot & PROT_WRITE) &&
|
||||
(length & (PAGE_SIZE - 1))) {
|
||||
memset(reinterpret_cast<char *>(mapped) + length, 0,
|
||||
PAGE_SIZE - (length & ~(PAGE_MASK)));
|
||||
}
|
||||
return mapped;
|
||||
}
|
||||
|
||||
void
|
||||
MappableFile::finalize()
|
||||
{
|
||||
/* Close file ; equivalent to close(fd.forget()) */
|
||||
fd = -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* _MappableBuffer is a buffer which content can be mapped at different
|
||||
* locations in the virtual address space.
|
||||
* On Linux, uses a (deleted) temporary file on a tmpfs for sharable content.
|
||||
* On Android, uses ashmem.
|
||||
*/
|
||||
class _MappableBuffer: public MappedPtr
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Returns a _MappableBuffer instance with the given name and the given
|
||||
* length.
|
||||
*/
|
||||
static _MappableBuffer *Create(const char *name, size_t length)
|
||||
{
|
||||
AutoCloseFD fd;
|
||||
#ifdef ANDROID
|
||||
/* On Android, initialize an ashmem region with the given length */
|
||||
fd = open("/" ASHMEM_NAME_DEF, O_RDWR, 0600);
|
||||
if (fd == -1)
|
||||
return NULL;
|
||||
char str[ASHMEM_NAME_LEN];
|
||||
strlcpy(str, name, sizeof(str));
|
||||
ioctl(fd, ASHMEM_SET_NAME, str);
|
||||
if (ioctl(fd, ASHMEM_SET_SIZE, length))
|
||||
return NULL;
|
||||
|
||||
/* The Gecko crash reporter is confused by adjacent memory mappings of
|
||||
* the same file. On Android, subsequent mappings are growing in memory
|
||||
* address, and chances are we're going to map from the same file
|
||||
* descriptor right away. Allocate one page more than requested so that
|
||||
* there is a gap between this mapping and the subsequent one. */
|
||||
void *buf = ::mmap(NULL, length + PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
if (buf != MAP_FAILED) {
|
||||
/* Actually create the gap with anonymous memory */
|
||||
::mmap(reinterpret_cast<char *>(buf) + ((length + PAGE_SIZE) & PAGE_MASK),
|
||||
PAGE_SIZE, PROT_NONE, MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS,
|
||||
-1, 0);
|
||||
debug("Decompression buffer of size %d in ashmem \"%s\", mapped @%p",
|
||||
length, str, buf);
|
||||
return new _MappableBuffer(fd.forget(), buf, length);
|
||||
}
|
||||
#else
|
||||
/* On Linux, use /dev/shm as base directory for temporary files, assuming
|
||||
* it's on tmpfs */
|
||||
/* TODO: check that /dev/shm is tmpfs */
|
||||
char path[256];
|
||||
sprintf(path, "/dev/shm/%s.XXXXXX", name);
|
||||
fd = mkstemp(path);
|
||||
if (fd == -1)
|
||||
return NULL;
|
||||
unlink(path);
|
||||
ftruncate(fd, length);
|
||||
|
||||
void *buf = ::mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
if (buf != MAP_FAILED) {
|
||||
debug("Decompression buffer of size %ld in \"%s\", mapped @%p",
|
||||
length, path, buf);
|
||||
return new _MappableBuffer(fd.forget(), buf, length);
|
||||
}
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *mmap(const void *addr, size_t length, int prot, int flags, off_t offset)
|
||||
{
|
||||
// ASSERT(fd != -1)
|
||||
#ifdef ANDROID
|
||||
/* Mapping ashmem MAP_PRIVATE is like mapping anonymous memory, even when
|
||||
* there is content in the ashmem */
|
||||
if (flags & MAP_PRIVATE) {
|
||||
flags &= ~MAP_PRIVATE;
|
||||
flags |= MAP_SHARED;
|
||||
}
|
||||
#endif
|
||||
return ::mmap(const_cast<void *>(addr), length, prot, flags, fd, offset);
|
||||
}
|
||||
|
||||
#ifdef ANDROID
|
||||
~_MappableBuffer() {
|
||||
/* Free the additional page we allocated. See _MappableBuffer::Create */
|
||||
munmap(this + ((GetLength() + PAGE_SIZE) & ~(PAGE_SIZE - 1)), PAGE_SIZE);
|
||||
}
|
||||
#endif
|
||||
|
||||
private:
|
||||
_MappableBuffer(int fd, void *buf, size_t length)
|
||||
: MappedPtr(buf, length), fd(fd) { }
|
||||
|
||||
/* File descriptor for the temporary file or ashmem */
|
||||
AutoCloseFD fd;
|
||||
};
|
||||
|
||||
|
||||
MappableDeflate *
|
||||
MappableDeflate::Create(const char *name, Zip *zip, Zip::Stream *stream)
|
||||
{
|
||||
// ASSERT(stream->GetType() == Zip::Stream::DEFLATE)
|
||||
_MappableBuffer *buf = _MappableBuffer::Create(name, stream->GetUncompressedSize());
|
||||
if (buf)
|
||||
return new MappableDeflate(buf, zip, stream);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
MappableDeflate::MappableDeflate(_MappableBuffer *buf, Zip *zip,
|
||||
Zip::Stream *stream)
|
||||
: zip(zip), buffer(buf)
|
||||
{
|
||||
/* Initialize Zlib data with zip stream info and decompression buffer */
|
||||
memset(&zStream, 0, sizeof(zStream));
|
||||
zStream.avail_in = stream->GetSize();
|
||||
zStream.next_in = const_cast<Bytef *>(
|
||||
reinterpret_cast<const Bytef *>(stream->GetBuffer()));
|
||||
zStream.total_in = 0;
|
||||
zStream.avail_out = stream->GetUncompressedSize();
|
||||
zStream.next_out = static_cast<Bytef*>(*buffer);
|
||||
zStream.total_out = 0;
|
||||
}
|
||||
|
||||
MappableDeflate::~MappableDeflate()
|
||||
{
|
||||
delete buffer;
|
||||
}
|
||||
|
||||
void *
|
||||
MappableDeflate::mmap(const void *addr, size_t length, int prot, int flags, off_t offset)
|
||||
{
|
||||
// ASSERT(buffer)
|
||||
// ASSERT(! flags & MAP_SHARED)
|
||||
flags |= MAP_PRIVATE;
|
||||
|
||||
/* The deflate stream is uncompressed up to the required offset + length, if
|
||||
* it hasn't previously been uncompressed */
|
||||
ssize_t missing = offset + length + zStream.avail_out - buffer->GetLength();
|
||||
if (missing > 0) {
|
||||
uInt avail_out = zStream.avail_out;
|
||||
zStream.avail_out = missing;
|
||||
if ((*buffer == zStream.next_out) &&
|
||||
(inflateInit2(&zStream, -MAX_WBITS) != Z_OK)) {
|
||||
log("inflateInit failed: %s", zStream.msg);
|
||||
return MAP_FAILED;
|
||||
}
|
||||
int ret = inflate(&zStream, Z_SYNC_FLUSH);
|
||||
if (ret < 0) {
|
||||
log("inflate failed: %s", zStream.msg);
|
||||
return MAP_FAILED;
|
||||
}
|
||||
if (ret == Z_NEED_DICT) {
|
||||
log("zstream requires a dictionary. %s", zStream.msg);
|
||||
return MAP_FAILED;
|
||||
}
|
||||
zStream.avail_out = avail_out - missing + zStream.avail_out;
|
||||
if (ret == Z_STREAM_END) {
|
||||
if (inflateEnd(&zStream) != Z_OK) {
|
||||
log("inflateEnd failed: %s", zStream.msg);
|
||||
return MAP_FAILED;
|
||||
}
|
||||
if (zStream.total_out != buffer->GetLength()) {
|
||||
log("File not fully uncompressed! %ld / %d", zStream.total_out,
|
||||
static_cast<unsigned int>(buffer->GetLength()));
|
||||
return MAP_FAILED;
|
||||
}
|
||||
}
|
||||
}
|
||||
#if defined(ANDROID) && defined(__arm__)
|
||||
if (prot & PROT_EXEC) {
|
||||
/* We just extracted data that may be executed in the future.
|
||||
* We thus need to ensure Instruction and Data cache coherency. */
|
||||
debug("cacheflush(%p, %p)", *buffer + offset, *buffer + (offset + length));
|
||||
cacheflush(reinterpret_cast<uintptr_t>(*buffer + offset),
|
||||
reinterpret_cast<uintptr_t>(*buffer + (offset + length)), 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
return buffer->mmap(addr, length, prot, flags, offset);
|
||||
}
|
||||
|
||||
void
|
||||
MappableDeflate::finalize()
|
||||
{
|
||||
/* Free decompression buffer */
|
||||
delete buffer;
|
||||
buffer = NULL;
|
||||
/* Remove reference to Zip archive */
|
||||
zip = NULL;
|
||||
}
|
96
mozglue/linker/Mappable.h
Normal file
96
mozglue/linker/Mappable.h
Normal file
@ -0,0 +1,96 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef Mappable_h
|
||||
#define Mappable_h
|
||||
|
||||
#include "Zip.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "zlib.h"
|
||||
|
||||
/**
|
||||
* Abstract class to handle mmap()ing from various kind of entities, such as
|
||||
* plain files or Zip entries. The virtual members are meant to act as the
|
||||
* equivalent system functions, with a few differences:
|
||||
* - mapped memory is always MAP_PRIVATE, even though a given implementation
|
||||
* may use something different internally.
|
||||
* - memory after length and up to the end of the corresponding page is nulled
|
||||
* out.
|
||||
*/
|
||||
class Mappable
|
||||
{
|
||||
public:
|
||||
virtual ~Mappable() { }
|
||||
|
||||
virtual void *mmap(const void *addr, size_t length, int prot, int flags,
|
||||
off_t offset) = 0;
|
||||
virtual void munmap(void *addr, size_t length) {
|
||||
::munmap(addr, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate to a Mappable instance that no further mmap is going to happen.
|
||||
*/
|
||||
virtual void finalize() = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Mappable implementation for plain files
|
||||
*/
|
||||
class MappableFile: public Mappable
|
||||
{
|
||||
public:
|
||||
~MappableFile() { }
|
||||
|
||||
/**
|
||||
* Create a MappableFile instance for the given file path.
|
||||
*/
|
||||
static MappableFile *Create(const char *path);
|
||||
|
||||
/* Inherited from Mappable */
|
||||
virtual void *mmap(const void *addr, size_t length, int prot, int flags, off_t offset);
|
||||
virtual void finalize();
|
||||
|
||||
private:
|
||||
MappableFile(int fd): fd(fd) { }
|
||||
|
||||
/* File descriptor */
|
||||
AutoCloseFD fd;
|
||||
};
|
||||
|
||||
class _MappableBuffer;
|
||||
|
||||
/**
|
||||
* Mappable implementation for deflated stream in a Zip archive
|
||||
*/
|
||||
class MappableDeflate: public Mappable
|
||||
{
|
||||
public:
|
||||
~MappableDeflate();
|
||||
|
||||
/**
|
||||
* Create a MappableDeflate instance for the given Zip stream. The name
|
||||
* argument is used for an appropriately named temporary file, and the Zip
|
||||
* instance is given for the MappableDeflate to keep a reference of it.
|
||||
*/
|
||||
static MappableDeflate *Create(const char *name, Zip *zip, Zip::Stream *stream);
|
||||
|
||||
/* Inherited from Mappable */
|
||||
virtual void *mmap(const void *addr, size_t length, int prot, int flags, off_t offset);
|
||||
virtual void finalize();
|
||||
|
||||
private:
|
||||
MappableDeflate(_MappableBuffer *buf, Zip *zip, Zip::Stream *stream);
|
||||
|
||||
/* Zip reference */
|
||||
mozilla::RefPtr<Zip> zip;
|
||||
|
||||
/* Decompression buffer */
|
||||
_MappableBuffer *buffer;
|
||||
|
||||
/* Zlib data */
|
||||
z_stream zStream;
|
||||
};
|
||||
|
||||
#endif /* Mappable_h */
|
@ -96,22 +96,26 @@ private:
|
||||
/**
|
||||
* MappedPtr is a RAII wrapper for mmap()ed memory. It can be used as
|
||||
* a simple void * or unsigned char *.
|
||||
*
|
||||
* It is defined as a derivative of a template that allows to use a
|
||||
* different unmapping strategy.
|
||||
*/
|
||||
class MappedPtr
|
||||
template <typename T>
|
||||
class GenericMappedPtr
|
||||
{
|
||||
public:
|
||||
MappedPtr(void *buf, size_t length): buf(buf), length(length) { }
|
||||
MappedPtr(): buf(MAP_FAILED), length(0) { }
|
||||
GenericMappedPtr(void *buf, size_t length): buf(buf), length(length) { }
|
||||
GenericMappedPtr(): buf(MAP_FAILED), length(0) { }
|
||||
|
||||
void Init(void *b, size_t len) {
|
||||
buf = b;
|
||||
length = len;
|
||||
}
|
||||
|
||||
~MappedPtr()
|
||||
~GenericMappedPtr()
|
||||
{
|
||||
if (buf != MAP_FAILED)
|
||||
munmap(buf, length);
|
||||
static_cast<T *>(this)->munmap(buf, length);
|
||||
}
|
||||
|
||||
operator void *() const
|
||||
@ -145,11 +149,31 @@ public:
|
||||
return (ptr >= buf) && (ptr < reinterpret_cast<char *>(buf) + length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the length of the mapped range
|
||||
*/
|
||||
size_t GetLength() const
|
||||
{
|
||||
return length;
|
||||
}
|
||||
|
||||
private:
|
||||
void *buf;
|
||||
size_t length;
|
||||
};
|
||||
|
||||
struct MappedPtr: public GenericMappedPtr<MappedPtr>
|
||||
{
|
||||
MappedPtr(void *buf, size_t length)
|
||||
: GenericMappedPtr<MappedPtr>(buf, length) { }
|
||||
MappedPtr(): GenericMappedPtr<MappedPtr>() { }
|
||||
|
||||
void munmap(void *buf, size_t length)
|
||||
{
|
||||
::munmap(buf, length);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* UnsizedArray is a way to access raw arrays of data in memory.
|
||||
*
|
||||
|
@ -23,6 +23,8 @@ LOCAL_INCLUDES += -I$(srcdir)/../linker
|
||||
MOZ_GLUE_PROGRAM_LDFLAGS =
|
||||
MOZ_GLUE_LDFLAGS =
|
||||
LIBS += $(call EXPAND_LIBNAME_PATH,linker,../linker)
|
||||
|
||||
EXTRA_LIBS = $(ZLIB_LIBS)
|
||||
endif
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
Loading…
Reference in New Issue
Block a user