Browse Source

AK: Make MappedFile heap-allocated and ref-counted

Let's adapt this class a bit better to how it's actually being used.

Instead of having valid/invalid states and storing an error in case
it's invalid, a MappedFile is now always valid, and the factory
function that creates it will return an OSError if mapping fails.
Andreas Kling 4 năm trước cách đây
mục cha
commit
2f3b901f7f

+ 23 - 47
AK/MappedFile.cpp

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org>
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -25,6 +25,7 @@
  */
 
 #include <AK/MappedFile.h>
+#include <AK/ScopeGuard.h>
 #include <AK/String.h>
 #include <fcntl.h>
 #include <stdio.h>
@@ -32,68 +33,43 @@
 #include <sys/stat.h>
 #include <unistd.h>
 
-//#define DEBUG_MAPPED_FILE
-
 namespace AK {
 
-MappedFile::MappedFile(const StringView& file_name)
+Result<NonnullRefPtr<MappedFile>, OSError> MappedFile::map(const StringView& path)
 {
-    int fd = open_with_path_length(file_name.characters_without_null_termination(), file_name.length(), O_RDONLY | O_CLOEXEC, 0);
+    int fd = open_with_path_length(path.characters_without_null_termination(), path.length(), O_RDONLY | O_CLOEXEC, 0);
+    if (fd < 0)
+        return OSError(errno);
 
-    if (fd == -1) {
-        m_errno = errno;
-        perror("open");
-        return;
-    }
+    ScopeGuard fd_close_guard = [fd] {
+        close(fd);
+    };
 
     struct stat st;
-    fstat(fd, &st);
-    m_size = st.st_size;
-    m_map = mmap(nullptr, m_size, PROT_READ, MAP_SHARED, fd, 0);
-
-    if (m_map == MAP_FAILED) {
-        m_errno = errno;
-        perror("mmap");
+    if (fstat(fd, &st) < 0) {
+        auto saved_errno = errno;
+        return OSError(saved_errno);
     }
 
-#ifdef DEBUG_MAPPED_FILE
-    dbgln("MappedFile(\"{}\") := ( fd={}, m_size={}, m_map={} )", file_name, fd, m_size, m_map);
-#endif
+    auto size = st.st_size;
+    auto* ptr = mmap(nullptr, size, PROT_READ, MAP_SHARED, fd, 0);
 
-    close(fd);
-}
-
-MappedFile::~MappedFile()
-{
-    unmap();
-}
+    if (ptr == MAP_FAILED)
+        return OSError(errno);
 
-void MappedFile::unmap()
-{
-    if (!is_valid())
-        return;
-    int rc = munmap(m_map, m_size);
-    ASSERT(rc == 0);
-    m_size = 0;
-    m_map = (void*)-1;
+    return adopt(*new MappedFile(ptr, size));
 }
 
-MappedFile::MappedFile(MappedFile&& other)
-    : m_size(other.m_size)
-    , m_map(other.m_map)
+MappedFile::MappedFile(void* ptr, size_t size)
+    : m_data(ptr)
+    , m_size(size)
 {
-    other.m_size = 0;
-    other.m_map = (void*)-1;
 }
 
-MappedFile& MappedFile::operator=(MappedFile&& other)
+MappedFile::~MappedFile()
 {
-    if (this == &other)
-        return *this;
-    unmap();
-    swap(m_size, other.m_size);
-    swap(m_map, other.m_map);
-    return *this;
+    auto rc = munmap(m_data, m_size);
+    ASSERT(rc == 0);
 }
 
 }

+ 14 - 18
AK/MappedFile.h

@@ -27,37 +27,33 @@
 #pragma once
 
 #include <AK/Noncopyable.h>
-#include <AK/StringView.h>
+#include <AK/NonnullRefPtr.h>
+#include <AK/OSError.h>
+#include <AK/RefCounted.h>
+#include <AK/Result.h>
 
 namespace AK {
 
-class MappedFile {
+class MappedFile : public RefCounted<MappedFile> {
     AK_MAKE_NONCOPYABLE(MappedFile);
+    AK_MAKE_NONMOVABLE(MappedFile);
 
 public:
-    MappedFile() { }
-    explicit MappedFile(const StringView& file_name);
-    MappedFile(MappedFile&&);
+    static Result<NonnullRefPtr<MappedFile>, OSError> map(const StringView& path);
     ~MappedFile();
 
-    MappedFile& operator=(MappedFile&&);
+    void* data() { return m_data; }
+    const void* data() const { return m_data; }
 
-    bool is_valid() const { return m_map != (void*)-1; }
-    int errno_if_invalid() const
-    {
-        ASSERT(!is_valid());
-        return m_errno;
-    }
-    void unmap();
-
-    void* data() { return m_map; }
-    const void* data() const { return m_map; }
     size_t size() const { return m_size; }
 
+    ReadonlyBytes bytes() const { return { m_data, m_size }; }
+
 private:
+    explicit MappedFile(void*, size_t);
+
+    void* m_data { nullptr };
     size_t m_size { 0 };
-    void* m_map { (void*)-1 };
-    int m_errno { 0 };
 };
 
 }

+ 12 - 10
Applications/Help/ManualModel.cpp

@@ -79,22 +79,24 @@ String ManualModel::page_path(const GUI::ModelIndex& index) const
     return page->path();
 }
 
-Result<StringView, int> ManualModel::page_view(const String& path) const
+Result<StringView, OSError> ManualModel::page_view(const String& path) const
 {
     if (path.is_empty())
         return StringView {};
 
-    auto mapped_file = m_mapped_files.get(path);
-    if (mapped_file.has_value())
-        return StringView { (const char*)mapped_file.value()->data(), mapped_file.value()->size() };
-
-    auto map = make<MappedFile>(path);
-    if (!map->is_valid())
-        return map->errno_if_invalid();
+    {
+        // Check if we've got it cached already.
+        auto mapped_file = m_mapped_files.get(path);
+        if (mapped_file.has_value())
+            return StringView { mapped_file.value()->bytes() };
+    }
 
-    StringView view { (const char*)map->data(), map->size() };
-    m_mapped_files.set(path, move(map));
+    auto file_or_error = MappedFile::map(path);
+    if (file_or_error.is_error())
+        return file_or_error.error();
 
+    StringView view { file_or_error.value()->bytes() };
+    m_mapped_files.set(path, file_or_error.release_value());
     return view;
 }
 

+ 2 - 2
Applications/Help/ManualModel.h

@@ -45,7 +45,7 @@ public:
 
     String page_path(const GUI::ModelIndex&) const;
     String page_and_section(const GUI::ModelIndex&) const;
-    Result<StringView, int> page_view(const String& path) const;
+    Result<StringView, OSError> page_view(const String& path) const;
 
     void update_section_node_on_toggle(const GUI::ModelIndex&, const bool);
     virtual int row_count(const GUI::ModelIndex& = GUI::ModelIndex()) const override;
@@ -62,5 +62,5 @@ private:
     GUI::Icon m_section_open_icon;
     GUI::Icon m_section_icon;
     GUI::Icon m_page_icon;
-    mutable HashMap<String, OwnPtr<MappedFile>> m_mapped_files;
+    mutable HashMap<String, NonnullRefPtr<MappedFile>> m_mapped_files;
 };

+ 1 - 1
Applications/Help/main.cpp

@@ -159,7 +159,7 @@ int main(int argc, char* argv[])
 
         auto source_result = model->page_view(path);
         if (source_result.is_error()) {
-            GUI::MessageBox::show(window, strerror(source_result.error()), "Failed to open man page", GUI::MessageBox::Type::Error);
+            GUI::MessageBox::show(window, source_result.error().string(), "Failed to open man page", GUI::MessageBox::Type::Error);
             return;
         }
 

+ 3 - 3
DevTools/HackStudio/Debugger/DisassemblyModel.cpp

@@ -51,10 +51,10 @@ DisassemblyModel::DisassemblyModel(const Debug::DebugSession& debug_session, con
     const ELF::Image* elf = nullptr;
 
     if (containing_function.value().address_low >= 0xc0000000) {
-        auto kernel_file = make<MappedFile>("/boot/Kernel");
-        if (!kernel_file->is_valid())
+        auto file_or_error = MappedFile::map("/boot/Kernel");
+        if (file_or_error.is_error())
             return;
-        kernel_elf = make<ELF::Image>((const u8*)kernel_file->data(), kernel_file->size());
+        kernel_elf = make<ELF::Image>(file_or_error.value()->bytes());
         elf = kernel_elf.ptr();
     } else {
         elf = &lib->debug_info->elf();

+ 3 - 2
DevTools/Profiler/DisassemblyModel.cpp

@@ -60,9 +60,10 @@ DisassemblyModel::DisassemblyModel(Profile& profile, ProfileNode& node)
     FlatPtr base_address = 0;
     if (m_node.address() >= 0xc0000000) {
         if (!m_kernel_file) {
-            m_kernel_file = new MappedFile("/boot/Kernel");
-            if (!m_kernel_file->is_valid())
+            auto file_or_error = MappedFile::map("/boot/Kernel");
+            if (file_or_error.is_error())
                 return;
+            m_kernel_file = file_or_error.release_value();
         }
         kernel_elf = make<ELF::Image>((const u8*)m_kernel_file->data(), m_kernel_file->size());
         elf = kernel_elf.ptr();

+ 1 - 1
DevTools/Profiler/DisassemblyModel.h

@@ -69,7 +69,7 @@ private:
 
     Profile& m_profile;
     ProfileNode& m_node;
-    OwnPtr<MappedFile> m_kernel_file;
+    RefPtr<MappedFile> m_kernel_file;
 
     Vector<InstructionData> m_instructions;
 };

+ 3 - 3
DevTools/Profiler/Profile.cpp

@@ -230,10 +230,10 @@ Result<NonnullOwnPtr<Profile>, String> Profile::load_from_perfcore_file(const St
     if (!coredump)
         return String { "Could not open coredump" };
 
-    MappedFile kernel_elf_file("/boot/Kernel");
+    auto file_or_error = MappedFile::map("/boot/Kernel");
     OwnPtr<ELF::Image> kernel_elf;
-    if (kernel_elf_file.is_valid())
-        kernel_elf = make<ELF::Image>(static_cast<const u8*>(kernel_elf_file.data()), kernel_elf_file.size());
+    if (!file_or_error.is_error())
+        kernel_elf = make<ELF::Image>(file_or_error.value()->bytes());
 
     auto events_value = object.get("events");
     if (!events_value.is_array())

+ 18 - 16
DevTools/UserspaceEmulator/Emulator.cpp

@@ -167,13 +167,14 @@ void Emulator::setup_stack(Vector<ELF::AuxiliaryValue> aux_vector)
 
 bool Emulator::load_elf()
 {
-    MappedFile mapped_executable(m_executable_path);
-    if (!mapped_executable.is_valid()) {
-        reportln("Unable to map {}", m_executable_path);
+    auto file_or_error = MappedFile::map(m_executable_path);
+    if (file_or_error.is_error()) {
+        reportln("Unable to map {}: {}", m_executable_path, file_or_error.error());
         return false;
     }
 
-    ELF::Image executable_elf((const u8*)mapped_executable.data(), mapped_executable.size());
+    auto elf_image_data = file_or_error.value()->bytes();
+    ELF::Image executable_elf(elf_image_data);
 
     if (!executable_elf.is_dynamic()) {
         // FIXME: Support static objects
@@ -181,7 +182,7 @@ bool Emulator::load_elf()
     }
 
     String interpreter_path;
-    if (!ELF::validate_program_headers(*(Elf32_Ehdr*)mapped_executable.data(), mapped_executable.size(), (u8*)mapped_executable.data(), mapped_executable.size(), &interpreter_path)) {
+    if (!ELF::validate_program_headers(*(const Elf32_Ehdr*)elf_image_data.data(), elf_image_data.size(), (const u8*)elf_image_data.data(), elf_image_data.size(), &interpreter_path)) {
         reportln("failed to validate ELF file");
         return false;
     }
@@ -189,9 +190,10 @@ bool Emulator::load_elf()
     ASSERT(!interpreter_path.is_null());
     dbgln("interpreter: {}", interpreter_path);
 
-    auto interpreter_file = make<MappedFile>(interpreter_path);
-    ASSERT(interpreter_file->is_valid());
-    ELF::Image interpreter_image((const u8*)interpreter_file->data(), interpreter_file->size());
+    auto interpreter_file_or_error = MappedFile::map(interpreter_path);
+    ASSERT(!interpreter_file_or_error.is_error());
+    auto interpreter_image_data = interpreter_file_or_error.value()->bytes();
+    ELF::Image interpreter_image(interpreter_image_data);
 
     constexpr FlatPtr interpreter_load_offset = 0x08000000;
     interpreter_image.for_each_program_header([&](const ELF::Image::ProgramHeader& program_header) {
@@ -308,12 +310,12 @@ String Emulator::create_backtrace_line(FlatPtr address)
         lib_path = String::formatted("/usr/lib/{}", lib_path);
 
     if (!m_dynamic_library_cache.contains(lib_path)) {
-        MappedFile mapped_file { lib_path };
-        if (!mapped_file.is_valid())
+        auto file_or_error = MappedFile::map(lib_path);
+        if (file_or_error.is_error())
             return minimal;
 
-        auto debug_info = make<Debug::DebugInfo>(make<ELF::Image>((const u8*)mapped_file.data(), mapped_file.size()));
-        m_dynamic_library_cache.set(lib_path, CachedELF { move(mapped_file), move(debug_info) });
+        auto debug_info = make<Debug::DebugInfo>(make<ELF::Image>(file_or_error.value()->bytes()));
+        m_dynamic_library_cache.set(lib_path, CachedELF { file_or_error.release_value(), move(debug_info) });
     }
 
     auto it = m_dynamic_library_cache.find(lib_path);
@@ -1765,11 +1767,11 @@ int Emulator::virt$beep()
 
 bool Emulator::find_malloc_symbols(const MmapRegion& libc_text)
 {
-    auto mapped_file = make<MappedFile>("/usr/lib/libc.so");
-    if (!mapped_file->is_valid())
-        return {};
+    auto file_or_error = MappedFile::map("/usr/lib/libc.so");
+    if (file_or_error.is_error())
+        return false;
 
-    ELF::Image image((const u8*)mapped_file->data(), mapped_file->size());
+    ELF::Image image(file_or_error.value()->bytes());
     auto malloc_symbol = image.find_demangled_function("malloc");
     auto free_symbol = image.find_demangled_function("free");
     auto realloc_symbol = image.find_demangled_function("realloc");

+ 1 - 1
DevTools/UserspaceEmulator/Emulator.h

@@ -207,7 +207,7 @@ private:
     Optional<size_t> m_loader_text_size;
 
     struct CachedELF {
-        MappedFile mapped_file;
+        NonnullRefPtr<MappedFile> mapped_file;
         NonnullOwnPtr<Debug::DebugInfo> debug_info;
     };
 

+ 4 - 3
Libraries/LibCoreDump/Backtrace.cpp

@@ -57,11 +57,12 @@ static const ELFObjectInfo* object_info_for_region(const ELF::Core::MemoryRegion
     if (!Core::File::exists(path.characters()))
         return nullptr;
 
-    MappedFile object_file(path);
-    if (!object_file.is_valid())
+    auto file_or_error = MappedFile::map(path);
+    if (file_or_error.is_error())
         return nullptr;
 
-    auto info = make<ELFObjectInfo>(move(object_file), Debug::DebugInfo { make<ELF::Image>((const u8*)object_file.data(), object_file.size()) });
+    auto image = make<ELF::Image>(file_or_error.value()->bytes());
+    auto info = make<ELFObjectInfo>(file_or_error.release_value(), Debug::DebugInfo { move(image) });
     auto* info_ptr = info.ptr();
     s_debug_info_cache.set(path, move(info));
     return info_ptr;

+ 2 - 2
Libraries/LibCoreDump/Backtrace.h

@@ -33,13 +33,13 @@
 namespace CoreDump {
 
 struct ELFObjectInfo {
-    ELFObjectInfo(MappedFile&& file, Debug::DebugInfo&& debug_info)
+    ELFObjectInfo(NonnullRefPtr<MappedFile> file, Debug::DebugInfo&& debug_info)
         : file(move(file))
         , debug_info(move(debug_info))
     {
     }
 
-    MappedFile file;
+    NonnullRefPtr<MappedFile> file;
     Debug::DebugInfo debug_info;
 };
 

+ 9 - 9
Libraries/LibCoreDump/Reader.cpp

@@ -35,15 +35,15 @@ namespace CoreDump {
 
 OwnPtr<Reader> Reader::create(const String& path)
 {
-    auto mapped_file = make<MappedFile>(path);
-    if (!mapped_file->is_valid())
+    auto file_or_error = MappedFile::map(path);
+    if (file_or_error.is_error())
         return nullptr;
-    return make<Reader>(move(mapped_file));
+    return adopt_own(*new Reader(file_or_error.release_value()));
 }
 
-Reader::Reader(OwnPtr<MappedFile>&& coredump_file)
+Reader::Reader(NonnullRefPtr<MappedFile> coredump_file)
     : m_coredump_file(move(coredump_file))
-    , m_coredump_image((u8*)m_coredump_file->data(), m_coredump_file->size())
+    , m_coredump_image(m_coredump_file->bytes())
 {
     size_t index = 0;
     m_coredump_image.for_each_program_header([this, &index](auto pheader) {
@@ -201,11 +201,11 @@ const Reader::LibraryData* Reader::library_containing(FlatPtr address) const
     }
 
     if (!cached_libs.contains(path)) {
-        auto lib_file = make<MappedFile>(path);
-        if (!lib_file->is_valid())
+        auto file_or_error = MappedFile::map(path);
+        if (file_or_error.is_error())
             return {};
-        auto image = ELF::Image((const u8*)lib_file->data(), lib_file->size());
-        cached_libs.set(path, make<LibraryData>(name, region->region_start, move(lib_file), move(image)));
+        auto image = ELF::Image(file_or_error.value()->bytes());
+        cached_libs.set(path, make<LibraryData>(name, region->region_start, file_or_error.release_value(), move(image)));
     }
 
     auto lib_data = cached_libs.get(path).value();

+ 5 - 4
Libraries/LibCoreDump/Reader.h

@@ -38,13 +38,12 @@ namespace CoreDump {
 
 class Reader {
     AK_MAKE_NONCOPYABLE(Reader);
+    AK_MAKE_NONMOVABLE(Reader);
 
 public:
     static OwnPtr<Reader> create(const String&);
     ~Reader();
 
-    Reader(OwnPtr<MappedFile>&&);
-
     const ELF::Core::ProcessInfo& process_info() const;
 
     template<typename Func>
@@ -61,7 +60,7 @@ public:
     struct LibraryData {
         String name;
         FlatPtr base_address { 0 };
-        OwnPtr<MappedFile> file;
+        NonnullRefPtr<MappedFile> file;
         ELF::Image lib_elf;
     };
     const LibraryData* library_containing(FlatPtr address) const;
@@ -70,6 +69,8 @@ public:
     const HashMap<String, String> metadata() const;
 
 private:
+    Reader(NonnullRefPtr<MappedFile>);
+
     class NotesEntryIterator {
     public:
         NotesEntryIterator(const u8* notes_data);
@@ -85,7 +86,7 @@ private:
         const u8* start { nullptr };
     };
 
-    OwnPtr<MappedFile> m_coredump_file;
+    NonnullRefPtr<MappedFile> m_coredump_file;
     ELF::Image m_coredump_image;
     ssize_t m_notes_segment_index { -1 };
 };

+ 4 - 11
Libraries/LibDebug/DebugSession.cpp

@@ -42,13 +42,6 @@ DebugSession::DebugSession(pid_t pid, String source_root)
 {
 }
 
-MappedFile DebugSession::map_executable_for_process(pid_t pid)
-{
-    MappedFile executable(String::formatted("/proc/{}/exe", pid));
-    ASSERT(executable.is_valid());
-    return executable;
-}
-
 DebugSession::~DebugSession()
 {
     if (m_is_debuggee_dead)
@@ -373,13 +366,13 @@ void DebugSession::update_loaded_libs()
         if (m_loaded_libraries.contains(lib_name))
             return IterationDecision::Continue;
 
-        MappedFile lib_file(object_path.value());
-        if (!lib_file.is_valid())
+        auto file_or_error = MappedFile ::map(object_path.value());
+        if (file_or_error.is_error())
             return IterationDecision::Continue;
 
         FlatPtr base_address = entry.as_object().get("address").as_u32();
-        auto debug_info = make<DebugInfo>(make<ELF::Image>(reinterpret_cast<const u8*>(lib_file.data()), lib_file.size()), m_source_root, base_address);
-        auto lib = make<LoadedLibrary>(lib_name, move(lib_file), move(debug_info), base_address);
+        auto debug_info = make<DebugInfo>(make<ELF::Image>(file_or_error.value()->bytes()), m_source_root, base_address);
+        auto lib = make<LoadedLibrary>(lib_name, file_or_error.release_value(), move(debug_info), base_address);
         m_loaded_libraries.set(lib_name, move(lib));
 
         return IterationDecision::Continue;

+ 2 - 4
Libraries/LibDebug/DebugSession.h

@@ -134,11 +134,11 @@ public:
 
     struct LoadedLibrary {
         String name;
-        MappedFile file;
+        NonnullRefPtr<MappedFile> file;
         NonnullOwnPtr<DebugInfo> debug_info;
         FlatPtr base_address;
 
-        LoadedLibrary(const String& name, MappedFile&& file, NonnullOwnPtr<DebugInfo>&& debug_info, FlatPtr base_address)
+        LoadedLibrary(const String& name, NonnullRefPtr<MappedFile> file, NonnullOwnPtr<DebugInfo>&& debug_info, FlatPtr base_address)
             : name(name)
             , file(move(file))
             , debug_info(move(debug_info))
@@ -175,8 +175,6 @@ private:
     // x86 breakpoint instruction "int3"
     static constexpr u8 BREAKPOINT_INSTRUCTION = 0xcc;
 
-    static MappedFile map_executable_for_process(pid_t);
-
     void update_loaded_libs();
 
     int m_debuggee_pid { -1 };

+ 8 - 3
Libraries/LibELF/Image.cpp

@@ -36,14 +36,19 @@
 
 namespace ELF {
 
-Image::Image(const u8* buffer, size_t size, bool verbose_logging)
-    : m_buffer(buffer)
-    , m_size(size)
+Image::Image(ReadonlyBytes bytes, bool verbose_logging)
+    : m_buffer(bytes.data())
+    , m_size(bytes.size())
     , m_verbose_logging(verbose_logging)
 {
     parse();
 }
 
+Image::Image(const u8* buffer, size_t size, bool verbose_logging)
+    : Image(ReadonlyBytes { buffer, size }, verbose_logging)
+{
+}
+
 Image::~Image()
 {
 }

+ 2 - 0
Libraries/LibELF/Image.h

@@ -37,7 +37,9 @@ namespace ELF {
 
 class Image {
 public:
+    explicit Image(ReadonlyBytes, bool verbose_logging = true);
     explicit Image(const u8*, size_t, bool verbose_logging = true);
+
     ~Image();
     void dump() const;
     bool is_valid() const { return m_valid; }

+ 4 - 2
Libraries/LibGUI/FileIconProvider.cpp

@@ -150,12 +150,14 @@ Icon FileIconProvider::icon_for_executable(const String& path)
     // If the icon for an app isn't in the cache we attempt to load the file as an ELF image and extract
     // the serenity_app_icon_* sections which should contain the icons as raw PNG data. In the future it would
     // be better if the binary signalled the image format being used or we deduced it, e.g. using magic bytes.
-    auto mapped_file = make<MappedFile>(path);
-    if (!mapped_file->is_valid()) {
+    auto file_or_error = MappedFile::map(path);
+    if (file_or_error.is_error()) {
         app_icon_cache.set(path, s_executable_icon);
         return s_executable_icon;
     }
 
+    auto& mapped_file = file_or_error.value();
+
     if (mapped_file->size() < SELFMAG) {
         app_icon_cache.set(path, s_executable_icon);
         return s_executable_icon;

+ 3 - 2
Libraries/LibGUI/ImageWidget.cpp

@@ -92,10 +92,11 @@ void ImageWidget::animate()
 
 void ImageWidget::load_from_file(const StringView& path)
 {
-    MappedFile mapped_file(path);
-    if (!mapped_file.is_valid())
+    auto file_or_error = MappedFile::map(path);
+    if (file_or_error.is_error())
         return;
 
+    auto& mapped_file = *file_or_error.value();
     m_image_decoder = Gfx::ImageDecoder::create((const u8*)mapped_file.data(), mapped_file.size());
     auto bitmap = m_image_decoder->bitmap();
     ASSERT(bitmap);

+ 3 - 3
Libraries/LibGfx/BMPLoader.cpp

@@ -179,10 +179,10 @@ static RefPtr<Bitmap> load_bmp_impl(const u8*, size_t);
 
 RefPtr<Gfx::Bitmap> load_bmp(const StringView& path)
 {
-    MappedFile mapped_file(path);
-    if (!mapped_file.is_valid())
+    auto file_or_error = MappedFile::map(path);
+    if (file_or_error.is_error())
         return nullptr;
-    auto bitmap = load_bmp_impl((const u8*)mapped_file.data(), mapped_file.size());
+    auto bitmap = load_bmp_impl((const u8*)file_or_error.value()->data(), file_or_error.value()->size());
     if (bitmap)
         bitmap->set_mmap_name(String::formatted("Gfx::Bitmap [{}] - Decoded BMP: {}", bitmap->size(), LexicalPath::canonicalized_path(path)));
     return bitmap;

+ 4 - 5
Libraries/LibGfx/BitmapFont.cpp

@@ -27,7 +27,6 @@
 #include "BitmapFont.h"
 #include "Bitmap.h"
 #include "Emoji.h"
-#include <AK/MappedFile.h>
 #include <AK/StdLibExtras.h>
 #include <AK/StringBuilder.h>
 #include <AK/Utf32View.h>
@@ -174,15 +173,15 @@ size_t BitmapFont::glyph_count_by_type(FontTypes type)
 
 RefPtr<BitmapFont> BitmapFont::load_from_file(const StringView& path)
 {
-    MappedFile mapped_file(path);
-    if (!mapped_file.is_valid())
+    auto file_or_error = MappedFile::map(path);
+    if (file_or_error.is_error())
         return nullptr;
 
-    auto font = load_from_memory((const u8*)mapped_file.data());
+    auto font = load_from_memory((const u8*)file_or_error.value()->data());
     if (!font)
         return nullptr;
 
-    font->m_mapped_file = move(mapped_file);
+    font->m_mapped_file = file_or_error.release_value();
     return font;
 }
 

+ 1 - 1
Libraries/LibGfx/BitmapFont.h

@@ -128,7 +128,7 @@ private:
 
     unsigned* m_rows { nullptr };
     u8* m_glyph_widths { nullptr };
-    MappedFile m_mapped_file;
+    RefPtr<MappedFile> m_mapped_file;
 
     u8 m_glyph_width { 0 };
     u8 m_glyph_height { 0 };

+ 3 - 3
Libraries/LibGfx/GIFLoader.cpp

@@ -107,10 +107,10 @@ struct GIFLoadingContext {
 
 RefPtr<Gfx::Bitmap> load_gif(const StringView& path)
 {
-    MappedFile mapped_file(path);
-    if (!mapped_file.is_valid())
+    auto file_or_error = MappedFile::map(path);
+    if (file_or_error.is_error())
         return nullptr;
-    GIFImageDecoderPlugin gif_decoder((const u8*)mapped_file.data(), mapped_file.size());
+    GIFImageDecoderPlugin gif_decoder((const u8*)file_or_error.value()->data(), file_or_error.value()->size());
     auto bitmap = gif_decoder.bitmap();
     if (bitmap)
         bitmap->set_mmap_name(String::formatted("Gfx::Bitmap [{}] - Decoded GIF: {}", bitmap->size(), LexicalPath::canonicalized_path(path)));

+ 3 - 3
Libraries/LibGfx/ICOLoader.cpp

@@ -116,10 +116,10 @@ struct ICOLoadingContext {
 
 RefPtr<Gfx::Bitmap> load_ico(const StringView& path)
 {
-    MappedFile mapped_file(path);
-    if (!mapped_file.is_valid())
+    auto file_or_error = MappedFile::map(path);
+    if (file_or_error.is_error())
         return nullptr;
-    ICOImageDecoderPlugin decoder((const u8*)mapped_file.data(), mapped_file.size());
+    ICOImageDecoderPlugin decoder((const u8*)file_or_error.value()->data(), file_or_error.value()->size());
     auto bitmap = decoder.bitmap();
     if (bitmap)
         bitmap->set_mmap_name(String::formatted("Gfx::Bitmap [{}] - Decoded ICO: {}", bitmap->size(), LexicalPath::canonicalized_path(path)));

+ 3 - 5
Libraries/LibGfx/JPGLoader.cpp

@@ -1320,12 +1320,10 @@ static RefPtr<Gfx::Bitmap> load_jpg_impl(const u8* data, size_t data_size)
 
 RefPtr<Gfx::Bitmap> load_jpg(const StringView& path)
 {
-    MappedFile mapped_file(path);
-    if (!mapped_file.is_valid()) {
+    auto file_or_error = MappedFile::map(path);
+    if (file_or_error.is_error())
         return nullptr;
-    }
-
-    auto bitmap = load_jpg_impl((const u8*)mapped_file.data(), mapped_file.size());
+    auto bitmap = load_jpg_impl((const u8*)file_or_error.value()->data(), file_or_error.value()->size());
     if (bitmap)
         bitmap->set_mmap_name(String::formatted("Gfx::Bitmap [{}] - Decoded JPG: {}", bitmap->size(), LexicalPath::canonicalized_path(path)));
     return bitmap;

+ 3 - 3
Libraries/LibGfx/PNGLoader.cpp

@@ -193,10 +193,10 @@ static bool process_chunk(Streamer&, PNGLoadingContext& context);
 
 RefPtr<Gfx::Bitmap> load_png(const StringView& path)
 {
-    MappedFile mapped_file(path);
-    if (!mapped_file.is_valid())
+    auto file_or_error = MappedFile::map(path);
+    if (file_or_error.is_error())
         return nullptr;
-    auto bitmap = load_png_impl((const u8*)mapped_file.data(), mapped_file.size());
+    auto bitmap = load_png_impl((const u8*)file_or_error.value()->data(), file_or_error.value()->size());
     if (bitmap)
         bitmap->set_mmap_name(String::formatted("Gfx::Bitmap [{}] - Decoded PNG: {}", bitmap->size(), LexicalPath::canonicalized_path(path)));
     return bitmap;

+ 3 - 5
Libraries/LibGfx/PortableImageLoaderCommon.h

@@ -294,12 +294,10 @@ static RefPtr<Gfx::Bitmap> load_impl(const u8* data, size_t data_size)
 template<typename TContext>
 static RefPtr<Gfx::Bitmap> load(const StringView& path)
 {
-    MappedFile mapped_file(path);
-    if (!mapped_file.is_valid()) {
+    auto file_or_error = MappedFile::map(path);
+    if (file_or_error.is_error())
         return nullptr;
-    }
-
-    auto bitmap = load_impl<TContext>((const u8*)mapped_file.data(), mapped_file.size());
+    auto bitmap = load_impl<TContext>((const u8*)file_or_error.value()->data(), file_or_error.value()->size());
     if (bitmap)
         bitmap->set_mmap_name(String::formatted("Gfx::Bitmap [{}] - Decoded {}: {}",
             bitmap->size(),

+ 5 - 5
Libraries/LibPCIDB/Database.cpp

@@ -34,7 +34,10 @@ namespace PCIDB {
 
 RefPtr<Database> Database::open(const StringView& file_name)
 {
-    auto res = adopt(*new Database(file_name));
+    auto file_or_error = MappedFile::map(file_name);
+    if (file_or_error.is_error())
+        return nullptr;
+    auto res = adopt(*new Database(file_or_error.release_value()));
     if (res->init() != 0)
         return nullptr;
     return res;
@@ -131,10 +134,7 @@ int Database::init()
     if (m_ready)
         return 0;
 
-    if (!m_file.is_valid())
-        return -1;
-
-    m_view = StringView((const char*)m_file.data(), m_file.size());
+    m_view = StringView { m_file->bytes() };
 
     ParseMode mode = ParseMode::UnknownMode;
 

+ 5 - 3
Libraries/LibPCIDB/Database.h

@@ -83,8 +83,10 @@ public:
     const StringView get_programming_interface(u8 class_id, u8 subclass_id, u8 programming_interface_id) const;
 
 private:
-    Database(const StringView& file_name)
-        : m_file(file_name) {};
+    explicit Database(NonnullRefPtr<MappedFile> file)
+        : m_file(move(file))
+    {
+    }
 
     int init();
 
@@ -94,7 +96,7 @@ private:
         ClassMode,
     };
 
-    MappedFile m_file {};
+    NonnullRefPtr<MappedFile> m_file;
     StringView m_view {};
     HashMap<int, NonnullOwnPtr<Vendor>> m_vendors;
     HashMap<int, NonnullOwnPtr<Class>> m_classes;

+ 6 - 4
Services/WebServer/Client.cpp

@@ -162,8 +162,9 @@ static String folder_image_data()
 {
     static String cache;
     if (cache.is_empty()) {
-        MappedFile image("/res/icons/16x16/filetype-folder.png");
-        cache = encode_base64({ image.data(), image.size() });
+        auto file_or_error = MappedFile::map("/res/icons/16x16/filetype-folder.png");
+        ASSERT(!file_or_error.is_error());
+        cache = encode_base64(file_or_error.value()->bytes());
     }
     return cache;
 }
@@ -172,8 +173,9 @@ static String file_image_data()
 {
     static String cache;
     if (cache.is_empty()) {
-        MappedFile image("/res/icons/16x16/filetype-unknown.png");
-        cache = encode_base64({ image.data(), image.size() });
+        auto file_or_error = MappedFile::map("/res/icons/16x16/filetype-unknown.png");
+        ASSERT(!file_or_error.is_error());
+        cache = encode_base64(file_or_error.value()->bytes());
     }
     return cache;
 }

+ 5 - 3
Userland/disasm.cpp

@@ -48,12 +48,14 @@ int main(int argc, char** argv)
     args_parser.add_positional_argument(path, "Path to i386 binary file", "path");
     args_parser.parse(argc, argv);
 
-    MappedFile file(path);
-    if (!file.is_valid()) {
-        // Already printed some error message.
+    auto file_or_error = MappedFile::map(path);
+    if (file_or_error.is_error()) {
+        warnln("Could not map file: {}", file_or_error.error().string());
         return 1;
     }
 
+    auto& file = *file_or_error.value();
+
     struct Symbol {
         size_t value;
         size_t size;

+ 1 - 1
Userland/functrace.cpp

@@ -90,7 +90,7 @@ static NonnullOwnPtr<HashMap<void*, X86::Instruction>> instrument_code()
             if (section.name() != ".text")
                 return IterationDecision::Continue;
 
-            X86::SimpleInstructionStream stream((const u8*)((u32)lib.file.data() + section.offset()), section.size());
+            X86::SimpleInstructionStream stream((const u8*)((u32)lib.file->data() + section.offset()), section.size());
             X86::Disassembler disassembler(stream);
             for (;;) {
                 auto offset = stream.offset();

+ 8 - 7
Userland/readelf.cpp

@@ -284,14 +284,15 @@ int main(int argc, char** argv)
         display_symbol_table = true;
     }
 
-    MappedFile mapped_executable(path);
+    auto file_or_error = MappedFile::map(path);
 
-    if (!mapped_executable.is_valid()) {
-        fprintf(stderr, "Unable to map file %s\n", path);
+    if (file_or_error.is_error()) {
+        warnln("Unable to map file {}: {}", path, file_or_error.error());
         return -1;
     }
 
-    ELF::Image executable_elf((const u8*)mapped_executable.data(), mapped_executable.size());
+    auto elf_image_data = file_or_error.value()->bytes();
+    ELF::Image executable_elf(elf_image_data);
 
     if (!executable_elf.is_valid()) {
         fprintf(stderr, "File is not a valid ELF object\n");
@@ -300,7 +301,7 @@ int main(int argc, char** argv)
 
     String interpreter_path;
 
-    if (!ELF::validate_program_headers(*(Elf32_Ehdr*)mapped_executable.data(), mapped_executable.size(), (u8*)mapped_executable.data(), mapped_executable.size(), &interpreter_path)) {
+    if (!ELF::validate_program_headers(*(const Elf32_Ehdr*)elf_image_data.data(), elf_image_data.size(), (const u8*)elf_image_data.data(), elf_image_data.size(), &interpreter_path)) {
         fprintf(stderr, "Invalid ELF headers\n");
         return -1;
     }
@@ -309,14 +310,14 @@ int main(int argc, char** argv)
         fprintf(stderr, "Warning: Dynamic ELF object has no interpreter path\n");
     }
 
-    ELF::Image interpreter_image((const u8*)mapped_executable.data(), mapped_executable.size());
+    ELF::Image interpreter_image(elf_image_data);
 
     if (!interpreter_image.is_valid()) {
         fprintf(stderr, "ELF image is invalid\n");
         return -1;
     }
 
-    auto header = *reinterpret_cast<const Elf32_Ehdr*>(mapped_executable.data());
+    auto& header = *reinterpret_cast<const Elf32_Ehdr*>(elf_image_data.data());
 
     if (display_elf_header) {
         printf("ELF header:\n");

+ 5 - 2
Userland/unzip.cpp

@@ -181,9 +181,12 @@ int main(int argc, char** argv)
         return 1;
     }
 
-    MappedFile mapped_file { zip_file_path };
-    if (!mapped_file.is_valid())
+    auto file_or_error = MappedFile ::map(zip_file_path);
+    if (file_or_error.is_error()) {
+        warnln("Failed to open {}: {}", zip_file_path, file_or_error.error());
         return 1;
+    }
+    auto& mapped_file = *file_or_error.value();
 
     printf("Archive: %s\n", zip_file_path.characters());