[Base] Android content URI file memory mapping
This commit is contained in:
parent
93a7918025
commit
624f2b2d9e
|
@ -12,7 +12,9 @@
|
||||||
|
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string_view>
|
||||||
|
|
||||||
|
#include "xenia/base/platform.h"
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
|
|
||||||
|
@ -26,21 +28,25 @@ class MappedMemory {
|
||||||
static std::unique_ptr<MappedMemory> Open(const std::filesystem::path& path,
|
static std::unique_ptr<MappedMemory> Open(const std::filesystem::path& path,
|
||||||
Mode mode, size_t offset = 0,
|
Mode mode, size_t offset = 0,
|
||||||
size_t length = 0);
|
size_t length = 0);
|
||||||
|
#if XE_PLATFORM_ANDROID
|
||||||
|
static std::unique_ptr<MappedMemory> OpenForAndroidContentUri(
|
||||||
|
const std::string_view uri, Mode mode, size_t offset = 0,
|
||||||
|
size_t length = 0);
|
||||||
|
#endif // XE_PLATFORM_ANDROID
|
||||||
|
|
||||||
MappedMemory(const std::filesystem::path& path, Mode mode)
|
MappedMemory() : data_(nullptr), size_(0) {}
|
||||||
: path_(path), mode_(mode), data_(nullptr), size_(0) {}
|
MappedMemory(void* data, size_t size) : data_(data), size_(size) {}
|
||||||
MappedMemory(const std::filesystem::path& path, Mode mode, void* data,
|
|
||||||
size_t size)
|
|
||||||
: path_(path), mode_(mode), data_(data), size_(size) {}
|
|
||||||
MappedMemory(const MappedMemory& mapped_memory) = delete;
|
MappedMemory(const MappedMemory& mapped_memory) = delete;
|
||||||
MappedMemory& operator=(const MappedMemory& mapped_memory) = delete;
|
MappedMemory& operator=(const MappedMemory& mapped_memory) = delete;
|
||||||
MappedMemory(MappedMemory&& mapped_memory) = delete;
|
MappedMemory(MappedMemory&& mapped_memory) = delete;
|
||||||
MappedMemory& operator=(MappedMemory&& mapped_memory) = delete;
|
MappedMemory& operator=(MappedMemory&& mapped_memory) = delete;
|
||||||
virtual ~MappedMemory() = default;
|
virtual ~MappedMemory() = default;
|
||||||
|
|
||||||
std::unique_ptr<MappedMemory> Slice(Mode mode, size_t offset, size_t length) {
|
// The mapping is still backed by the object the slice was created from, a
|
||||||
|
// slice is not owning.
|
||||||
|
std::unique_ptr<MappedMemory> Slice(size_t offset, size_t length) {
|
||||||
return std::unique_ptr<MappedMemory>(
|
return std::unique_ptr<MappedMemory>(
|
||||||
new MappedMemory(path_, mode, data() + offset, length));
|
new MappedMemory(data() + offset, length));
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t* data() const { return reinterpret_cast<uint8_t*>(data_); }
|
uint8_t* data() const { return reinterpret_cast<uint8_t*>(data_); }
|
||||||
|
@ -54,8 +60,6 @@ class MappedMemory {
|
||||||
virtual bool Remap(size_t offset, size_t length) { return false; }
|
virtual bool Remap(size_t offset, size_t length) { return false; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::filesystem::path path_;
|
|
||||||
Mode mode_;
|
|
||||||
void* data_;
|
void* data_;
|
||||||
size_t size_;
|
size_t size_;
|
||||||
};
|
};
|
||||||
|
|
|
@ -15,16 +15,15 @@
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include "xenia/base/string.h"
|
#include "xenia/base/filesystem.h"
|
||||||
|
#include "xenia/base/platform.h"
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
|
|
||||||
class PosixMappedMemory : public MappedMemory {
|
class PosixMappedMemory : public MappedMemory {
|
||||||
public:
|
public:
|
||||||
PosixMappedMemory(const std::filesystem::path& path, Mode mode, void* data,
|
PosixMappedMemory(void* data, size_t size, int file_descriptor)
|
||||||
size_t size, int file_descriptor)
|
: MappedMemory(data, size), file_descriptor_(file_descriptor) {}
|
||||||
: MappedMemory(path, mode, data, size),
|
|
||||||
file_descriptor_(file_descriptor) {}
|
|
||||||
|
|
||||||
~PosixMappedMemory() override {
|
~PosixMappedMemory() override {
|
||||||
if (data_) {
|
if (data_) {
|
||||||
|
@ -35,6 +34,39 @@ class PosixMappedMemory : public MappedMemory {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static std::unique_ptr<PosixMappedMemory> WrapFileDescriptor(
|
||||||
|
int file_descriptor, Mode mode, size_t offset = 0, size_t length = 0) {
|
||||||
|
int protection = 0;
|
||||||
|
switch (mode) {
|
||||||
|
case Mode::kRead:
|
||||||
|
protection |= PROT_READ;
|
||||||
|
break;
|
||||||
|
case Mode::kReadWrite:
|
||||||
|
protection |= PROT_READ | PROT_WRITE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t map_length = length;
|
||||||
|
if (!length) {
|
||||||
|
struct stat64 file_stat;
|
||||||
|
if (fstat64(file_descriptor, &file_stat)) {
|
||||||
|
close(file_descriptor);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
map_length = size_t(file_stat.st_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void* data =
|
||||||
|
mmap(0, map_length, protection, MAP_SHARED, file_descriptor, offset);
|
||||||
|
if (!data) {
|
||||||
|
close(file_descriptor);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::make_unique<PosixMappedMemory>(data, map_length,
|
||||||
|
file_descriptor);
|
||||||
|
}
|
||||||
|
|
||||||
void Close(uint64_t truncate_size) override {
|
void Close(uint64_t truncate_size) override {
|
||||||
if (data_) {
|
if (data_) {
|
||||||
munmap(data_, size());
|
munmap(data_, size());
|
||||||
|
@ -59,42 +91,43 @@ std::unique_ptr<MappedMemory> MappedMemory::Open(
|
||||||
const std::filesystem::path& path, Mode mode, size_t offset,
|
const std::filesystem::path& path, Mode mode, size_t offset,
|
||||||
size_t length) {
|
size_t length) {
|
||||||
int open_flags = 0;
|
int open_flags = 0;
|
||||||
int prot;
|
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case Mode::kRead:
|
case Mode::kRead:
|
||||||
open_flags |= O_RDONLY;
|
open_flags |= O_RDONLY;
|
||||||
prot = PROT_READ;
|
|
||||||
break;
|
break;
|
||||||
case Mode::kReadWrite:
|
case Mode::kReadWrite:
|
||||||
open_flags |= O_RDWR;
|
open_flags |= O_RDWR;
|
||||||
prot = PROT_READ | PROT_WRITE;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
int file_descriptor = open(path.c_str(), open_flags);
|
int file_descriptor = open(path.c_str(), open_flags);
|
||||||
if (file_descriptor < 0) {
|
if (file_descriptor < 0) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
return PosixMappedMemory::WrapFileDescriptor(file_descriptor, mode, offset,
|
||||||
|
length);
|
||||||
|
}
|
||||||
|
|
||||||
size_t map_length = length;
|
#if XE_PLATFORM_ANDROID
|
||||||
if (!length) {
|
std::unique_ptr<MappedMemory> MappedMemory::OpenForAndroidContentUri(
|
||||||
struct stat64 file_stat;
|
const std::string_view uri, Mode mode, size_t offset, size_t length) {
|
||||||
if (fstat64(file_descriptor, &file_stat)) {
|
const char* open_mode = nullptr;
|
||||||
close(file_descriptor);
|
switch (mode) {
|
||||||
return nullptr;
|
case Mode::kRead:
|
||||||
}
|
open_mode = "r";
|
||||||
map_length = size_t(file_stat.st_size);
|
break;
|
||||||
|
case Mode::kReadWrite:
|
||||||
|
open_mode = "rw";
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
int file_descriptor =
|
||||||
void* data = mmap(0, map_length, prot, MAP_SHARED, file_descriptor, offset);
|
xe::filesystem::OpenAndroidContentFileDescriptor(uri, open_mode);
|
||||||
if (!data) {
|
if (file_descriptor < 0) {
|
||||||
close(file_descriptor);
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
return PosixMappedMemory::WrapFileDescriptor(file_descriptor, mode, offset,
|
||||||
return std::unique_ptr<MappedMemory>(
|
length);
|
||||||
new PosixMappedMemory(path, mode, data, map_length, file_descriptor));
|
|
||||||
}
|
}
|
||||||
|
#endif // XE_PLATFORM_ANDROID
|
||||||
|
|
||||||
std::unique_ptr<ChunkedMappedMemoryWriter> ChunkedMappedMemoryWriter::Open(
|
std::unique_ptr<ChunkedMappedMemoryWriter> ChunkedMappedMemoryWriter::Open(
|
||||||
const std::filesystem::path& path, size_t chunk_size,
|
const std::filesystem::path& path, size_t chunk_size,
|
||||||
|
|
|
@ -32,9 +32,6 @@ class Win32MappedMemory : public MappedMemory {
|
||||||
// CreateFileMapping returns nullptr in case of failure.
|
// CreateFileMapping returns nullptr in case of failure.
|
||||||
static constexpr HANDLE kMappingHandleInvalid = nullptr;
|
static constexpr HANDLE kMappingHandleInvalid = nullptr;
|
||||||
|
|
||||||
Win32MappedMemory(const std::filesystem::path& path, Mode mode)
|
|
||||||
: MappedMemory(path, mode) {}
|
|
||||||
|
|
||||||
~Win32MappedMemory() override {
|
~Win32MappedMemory() override {
|
||||||
if (data_) {
|
if (data_) {
|
||||||
UnmapViewOfFile(data_);
|
UnmapViewOfFile(data_);
|
||||||
|
@ -135,7 +132,7 @@ std::unique_ptr<MappedMemory> MappedMemory::Open(
|
||||||
offset & ~static_cast<size_t>(system_info.dwAllocationGranularity - 1);
|
offset & ~static_cast<size_t>(system_info.dwAllocationGranularity - 1);
|
||||||
const size_t aligned_length = length + (offset - aligned_offset);
|
const size_t aligned_length = length + (offset - aligned_offset);
|
||||||
|
|
||||||
auto mm = std::make_unique<Win32MappedMemory>(path, mode);
|
auto mm = std::make_unique<Win32MappedMemory>();
|
||||||
mm->view_access_ = view_access;
|
mm->view_access_ = view_access;
|
||||||
|
|
||||||
mm->file_handle = CreateFile(path.c_str(), file_access, file_share, nullptr,
|
mm->file_handle = CreateFile(path.c_str(), file_access, file_share, nullptr,
|
||||||
|
|
|
@ -48,7 +48,7 @@ std::unique_ptr<MappedMemory> DiscImageEntry::OpenMapped(
|
||||||
|
|
||||||
size_t real_offset = data_offset_ + offset;
|
size_t real_offset = data_offset_ + offset;
|
||||||
size_t real_length = length ? std::min(length, data_size_) : data_size_;
|
size_t real_length = length ? std::min(length, data_size_) : data_size_;
|
||||||
return mmap_->Slice(mode, real_offset, real_length);
|
return mmap_->Slice(real_offset, real_length);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace vfs
|
} // namespace vfs
|
||||||
|
|
Loading…
Reference in New Issue