From c4ca802b9dc7f0d3f3aed5aa937240bf85370c15 Mon Sep 17 00:00:00 2001
From: Subv <subv2112@gmail.com>
Date: Mon, 19 Mar 2018 21:17:15 -0500
Subject: [PATCH 01/10] FS: Added an SDMC archive factory and registered it to
 the SDMC archive on startup.

---
 src/core/CMakeLists.txt                       |  2 +
 src/core/file_sys/sdmc_factory.cpp            | 40 +++++++++++++++++++
 src/core/file_sys/sdmc_factory.h              | 31 ++++++++++++++
 .../hle/service/filesystem/filesystem.cpp     |  5 +++
 src/core/hle/service/filesystem/filesystem.h  |  1 +
 5 files changed, 79 insertions(+)
 create mode 100644 src/core/file_sys/sdmc_factory.cpp
 create mode 100644 src/core/file_sys/sdmc_factory.h

diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index faaa50e4d..d2275d9a9 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -22,6 +22,8 @@ add_library(core STATIC
     file_sys/romfs_filesystem.h
     file_sys/savedata_factory.cpp
     file_sys/savedata_factory.h
+    file_sys/sdmc_factory.cpp
+    file_sys/sdmc_factory.h
     file_sys/storage.h
     frontend/emu_window.cpp
     frontend/emu_window.h
diff --git a/src/core/file_sys/sdmc_factory.cpp b/src/core/file_sys/sdmc_factory.cpp
new file mode 100644
index 000000000..00e80d2a7
--- /dev/null
+++ b/src/core/file_sys/sdmc_factory.cpp
@@ -0,0 +1,40 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <cinttypes>
+#include <memory>
+#include "common/common_types.h"
+#include "common/logging/log.h"
+#include "common/string_util.h"
+#include "core/core.h"
+#include "core/file_sys/disk_filesystem.h"
+#include "core/file_sys/sdmc_factory.h"
+
+namespace FileSys {
+
+SDMC_Factory::SDMC_Factory(std::string sd_directory) : sd_directory(std::move(sd_directory)) {}
+
+ResultVal<std::unique_ptr<FileSystemBackend>> SDMC_Factory::Open(const Path& path) {
+    // Create the SD Card directory if it doesn't already exist.
+    if (!FileUtil::IsDirectory(sd_directory)) {
+        FileUtil::CreateFullPath(sd_directory);
+    }
+
+    auto archive = std::make_unique<Disk_FileSystem>(sd_directory);
+    return MakeResult<std::unique_ptr<FileSystemBackend>>(std::move(archive));
+}
+
+ResultCode SDMC_Factory::Format(const Path& path) {
+    LOG_ERROR(Service_FS, "Unimplemented Format archive %s", GetName().c_str());
+    // TODO(Subv): Find the right error code for this
+    return ResultCode(-1);
+}
+
+ResultVal<ArchiveFormatInfo> SDMC_Factory::GetFormatInfo(const Path& path) const {
+    LOG_ERROR(Service_FS, "Unimplemented GetFormatInfo archive %s", GetName().c_str());
+    // TODO(bunnei): Find the right error code for this
+    return ResultCode(-1);
+}
+
+} // namespace FileSys
diff --git a/src/core/file_sys/sdmc_factory.h b/src/core/file_sys/sdmc_factory.h
new file mode 100644
index 000000000..93becda25
--- /dev/null
+++ b/src/core/file_sys/sdmc_factory.h
@@ -0,0 +1,31 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <memory>
+#include <string>
+#include "common/common_types.h"
+#include "core/file_sys/filesystem.h"
+#include "core/hle/result.h"
+
+namespace FileSys {
+
+/// File system interface to the SDCard archive
+class SDMC_Factory final : public FileSystemFactory {
+public:
+    explicit SDMC_Factory(std::string sd_directory);
+
+    std::string GetName() const override {
+        return "SDMC_Factory";
+    }
+    ResultVal<std::unique_ptr<FileSystemBackend>> Open(const Path& path) override;
+    ResultCode Format(const Path& path) override;
+    ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path) const override;
+
+private:
+    std::string sd_directory;
+};
+
+} // namespace FileSys
diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp
index ef05955b9..945832e98 100644
--- a/src/core/hle/service/filesystem/filesystem.cpp
+++ b/src/core/hle/service/filesystem/filesystem.cpp
@@ -6,6 +6,7 @@
 #include "common/file_util.h"
 #include "core/file_sys/filesystem.h"
 #include "core/file_sys/savedata_factory.h"
+#include "core/file_sys/sdmc_factory.h"
 #include "core/hle/service/filesystem/filesystem.h"
 #include "core/hle/service/filesystem/fsp_srv.h"
 
@@ -60,9 +61,13 @@ void RegisterFileSystems() {
     filesystem_map.clear();
 
     std::string nand_directory = FileUtil::GetUserPath(D_NAND_IDX);
+    std::string sd_directory = FileUtil::GetUserPath(D_SDMC_IDX);
 
     auto savedata = std::make_unique<FileSys::SaveData_Factory>(std::move(nand_directory));
     RegisterFileSystem(std::move(savedata), Type::SaveData);
+
+    auto sdcard = std::make_unique<FileSys::SDMC_Factory>(std::move(sd_directory));
+    RegisterFileSystem(std::move(sdcard), Type::SDMC);
 }
 
 void InstallInterfaces(SM::ServiceManager& service_manager) {
diff --git a/src/core/hle/service/filesystem/filesystem.h b/src/core/hle/service/filesystem/filesystem.h
index 8d30e94a1..56d26146e 100644
--- a/src/core/hle/service/filesystem/filesystem.h
+++ b/src/core/hle/service/filesystem/filesystem.h
@@ -26,6 +26,7 @@ namespace FileSystem {
 enum class Type {
     RomFS = 1,
     SaveData = 2,
+    SDMC = 3,
 };
 
 /**

From 808704c78cd2bb39523e488687eb3743ca443847 Mon Sep 17 00:00:00 2001
From: Subv <subv2112@gmail.com>
Date: Mon, 19 Mar 2018 21:21:49 -0500
Subject: [PATCH 02/10] FS: Implement MountSdCard.

---
 src/core/hle/service/filesystem/fsp_srv.cpp | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp
index 97b3fa290..720ac9930 100644
--- a/src/core/hle/service/filesystem/fsp_srv.cpp
+++ b/src/core/hle/service/filesystem/fsp_srv.cpp
@@ -274,10 +274,14 @@ void FSP_SRV::Initalize(Kernel::HLERequestContext& ctx) {
 }
 
 void FSP_SRV::MountSdCard(Kernel::HLERequestContext& ctx) {
-    LOG_WARNING(Service_FS, "(STUBBED) called");
+    LOG_DEBUG(Service_FS, "called");
 
-    IPC::ResponseBuilder rb{ctx, 2};
+    FileSys::Path unused;
+    auto filesystem = OpenFileSystem(Type::SDMC, unused).Unwrap();
+
+    IPC::ResponseBuilder rb{ctx, 2, 0, 1};
     rb.Push(RESULT_SUCCESS);
+    rb.PushIpcInterface<IFileSystem>(std::move(filesystem));
 }
 
 void FSP_SRV::CreateSaveData(Kernel::HLERequestContext& ctx) {

From fc44261dd1304c7dd1f38999a13ef9734c23b69a Mon Sep 17 00:00:00 2001
From: Subv <subv2112@gmail.com>
Date: Mon, 19 Mar 2018 22:57:34 -0500
Subject: [PATCH 03/10] FS: Support the file Append open mode.

---
 src/core/file_sys/disk_filesystem.cpp | 24 ++++++++++++++++++++++--
 src/core/file_sys/filesystem.h        |  1 +
 2 files changed, 23 insertions(+), 2 deletions(-)

diff --git a/src/core/file_sys/disk_filesystem.cpp b/src/core/file_sys/disk_filesystem.cpp
index 22b17ba04..9d456e0bf 100644
--- a/src/core/file_sys/disk_filesystem.cpp
+++ b/src/core/file_sys/disk_filesystem.cpp
@@ -17,10 +17,30 @@ std::string Disk_FileSystem::GetName() const {
 
 ResultVal<std::unique_ptr<StorageBackend>> Disk_FileSystem::OpenFile(const std::string& path,
                                                                      Mode mode) const {
-    ASSERT_MSG(mode == Mode::Read || mode == Mode::Write, "Other file modes are not supported");
+
+    std::string mode_str = "";
+    u32 mode_flags = static_cast<u32>(mode);
+
+    // Calculate the correct open mode for the file.
+    if ((mode_flags & static_cast<u32>(Mode::Read)) &&
+        (mode_flags & static_cast<u32>(Mode::Write))) {
+        if (mode_flags & static_cast<u32>(Mode::Append))
+            mode_str = "a+";
+        else
+            mode_str = "r+";
+    } else {
+        if (mode_flags & static_cast<u32>(Mode::Read))
+            mode_str = "r";
+        else if (mode_flags & static_cast<u32>(Mode::Append))
+            mode_str = "a";
+        else if (mode_flags & static_cast<u32>(Mode::Write))
+            mode_str = "w";
+    }
+
+    mode_str += "b";
 
     std::string full_path = base_directory + path;
-    auto file = std::make_shared<FileUtil::IOFile>(full_path, mode == Mode::Read ? "rb" : "wb");
+    auto file = std::make_shared<FileUtil::IOFile>(full_path, mode_str.c_str());
 
     if (!file->IsOpen()) {
         return ERROR_PATH_NOT_FOUND;
diff --git a/src/core/file_sys/filesystem.h b/src/core/file_sys/filesystem.h
index 94ad2abf2..4c9993efa 100644
--- a/src/core/file_sys/filesystem.h
+++ b/src/core/file_sys/filesystem.h
@@ -35,6 +35,7 @@ enum EntryType : u32 {
 enum class Mode : u32 {
     Read = 1,
     Write = 2,
+    Append = 4,
 };
 
 class Path {

From a9ba2c2000d9f2e4c6018aa6fc1e754eca82f72c Mon Sep 17 00:00:00 2001
From: Subv <subv2112@gmail.com>
Date: Mon, 19 Mar 2018 22:58:55 -0500
Subject: [PATCH 04/10] FS: Updated the Directory Entry structure to match the
 Switch.

---
 src/core/file_sys/directory.h         | 37 ++++++++++-----------
 src/core/file_sys/disk_filesystem.cpp | 48 +++++++++++++++++++++++----
 src/core/file_sys/disk_filesystem.h   | 22 ++++++++++--
 src/core/file_sys/filesystem.h        |  2 +-
 src/core/file_sys/romfs_filesystem.h  |  5 ++-
 5 files changed, 84 insertions(+), 30 deletions(-)

diff --git a/src/core/file_sys/directory.h b/src/core/file_sys/directory.h
index 5a40bf472..c7639795e 100644
--- a/src/core/file_sys/directory.h
+++ b/src/core/file_sys/directory.h
@@ -6,34 +6,28 @@
 
 #include <array>
 #include <cstddef>
+#include "common/common_funcs.h"
 #include "common/common_types.h"
+#include "core/file_sys/filesystem.h"
 
 ////////////////////////////////////////////////////////////////////////////////////////////////////
 // FileSys namespace
 
 namespace FileSys {
 
-// Structure of a directory entry, from http://3dbrew.org/wiki/FSDir:Read#Entry_format
-const size_t FILENAME_LENGTH = 0x20C / 2;
+// Structure of a directory entry, from
+// http://switchbrew.org/index.php?title=Filesystem_services#DirectoryEntry
+const size_t FILENAME_LENGTH = 0x300;
 struct Entry {
-    char16_t filename[FILENAME_LENGTH]; // Entry name (UTF-16, null-terminated)
-    std::array<char, 9> short_name; // 8.3 file name ('longfilename' -> 'LONGFI~1', null-terminated)
-    char unknown1;                  // unknown (observed values: 0x0A, 0x70, 0xFD)
-    std::array<char, 4>
-        extension;     // 8.3 file extension (set to spaces for directories, null-terminated)
-    char unknown2;     // unknown (always 0x01)
-    char unknown3;     // unknown (0x00 or 0x08)
-    char is_directory; // directory flag
-    char is_hidden;    // hidden flag
-    char is_archive;   // archive flag
-    char is_read_only; // read-only flag
-    u64 file_size;     // file size (for files only)
+    char filename[FILENAME_LENGTH];
+    INSERT_PADDING_BYTES(4);
+    EntryType type;
+    INSERT_PADDING_BYTES(3);
+    u64 file_size;
 };
-static_assert(sizeof(Entry) == 0x228, "Directory Entry struct isn't exactly 0x228 bytes long!");
-static_assert(offsetof(Entry, short_name) == 0x20C, "Wrong offset for short_name in Entry.");
-static_assert(offsetof(Entry, extension) == 0x216, "Wrong offset for extension in Entry.");
-static_assert(offsetof(Entry, is_archive) == 0x21E, "Wrong offset for is_archive in Entry.");
-static_assert(offsetof(Entry, file_size) == 0x220, "Wrong offset for file_size in Entry.");
+static_assert(sizeof(Entry) == 0x310, "Directory Entry struct isn't exactly 0x310 bytes long!");
+static_assert(offsetof(Entry, type) == 0x304, "Wrong offset for type in Entry.");
+static_assert(offsetof(Entry, file_size) == 0x308, "Wrong offset for file_size in Entry.");
 
 class DirectoryBackend : NonCopyable {
 public:
@@ -46,7 +40,10 @@ public:
      * @param entries Buffer to read data into
      * @return Number of entries listed
      */
-    virtual u32 Read(const u32 count, Entry* entries) = 0;
+    virtual u64 Read(const u64 count, Entry* entries) = 0;
+
+    /// Returns the number of entries still left to read.
+    virtual u64 GetEntryCount() const = 0;
 
     /**
      * Close the directory
diff --git a/src/core/file_sys/disk_filesystem.cpp b/src/core/file_sys/disk_filesystem.cpp
index 9d456e0bf..e2092b9df 100644
--- a/src/core/file_sys/disk_filesystem.cpp
+++ b/src/core/file_sys/disk_filesystem.cpp
@@ -153,14 +153,50 @@ bool Disk_Storage::SetSize(const u64 size) const {
     return false;
 }
 
-u32 Disk_Directory::Read(const u32 count, Entry* entries) {
-    LOG_WARNING(Service_FS, "(STUBBED) called");
-    return 0;
+Disk_Directory::Disk_Directory(const std::string& path) : directory() {
+    unsigned size = FileUtil::ScanDirectoryTree(path, directory);
+    directory.size = size;
+    directory.isDirectory = true;
+    children_iterator = directory.children.begin();
 }
 
-bool Disk_Directory::Close() const {
-    LOG_WARNING(Service_FS, "(STUBBED) called");
-    return true;
+u64 Disk_Directory::Read(const u64 count, Entry* entries) {
+    u64 entries_read = 0;
+
+    while (entries_read < count && children_iterator != directory.children.cend()) {
+        const FileUtil::FSTEntry& file = *children_iterator;
+        const std::string& filename = file.virtualName;
+        Entry& entry = entries[entries_read];
+
+        LOG_TRACE(Service_FS, "File %s: size=%llu dir=%d", filename.c_str(), file.size,
+                  file.isDirectory);
+
+        // TODO(Link Mauve): use a proper conversion to UTF-16.
+        for (size_t j = 0; j < FILENAME_LENGTH; ++j) {
+            entry.filename[j] = filename[j];
+            if (!filename[j])
+                break;
+        }
+
+        if (file.isDirectory) {
+            entry.file_size = 0;
+            entry.type = EntryType::Directory;
+        } else {
+            entry.file_size = file.size;
+            entry.type = EntryType::File;
+        }
+
+        ++entries_read;
+        ++children_iterator;
+    }
+    return entries_read;
+}
+
+u64 Disk_Directory::GetEntryCount() const {
+    // We convert the children iterator into a const_iterator to allow template argument deduction
+    // in std::distance.
+    std::vector<FileUtil::FSTEntry>::const_iterator current = children_iterator;
+    return std::distance(current, directory.children.end());
 }
 
 } // namespace FileSys
diff --git a/src/core/file_sys/disk_filesystem.h b/src/core/file_sys/disk_filesystem.h
index 53767b949..29383dbf7 100644
--- a/src/core/file_sys/disk_filesystem.h
+++ b/src/core/file_sys/disk_filesystem.h
@@ -59,8 +59,26 @@ private:
 
 class Disk_Directory : public DirectoryBackend {
 public:
-    u32 Read(const u32 count, Entry* entries) override;
-    bool Close() const override;
+    Disk_Directory(const std::string& path);
+
+    ~Disk_Directory() override {
+        Close();
+    }
+
+    u64 Read(const u64 count, Entry* entries) override;
+    u64 GetEntryCount() const override;
+
+    bool Close() const override {
+        return true;
+    }
+
+protected:
+    u32 total_entries_in_directory;
+    FileUtil::FSTEntry directory;
+
+    // We need to remember the last entry we returned, so a subsequent call to Read will continue
+    // from the next one. This iterator will always point to the next unread entry.
+    std::vector<FileUtil::FSTEntry>::iterator children_iterator;
 };
 
 } // namespace FileSys
diff --git a/src/core/file_sys/filesystem.h b/src/core/file_sys/filesystem.h
index 4c9993efa..5c91a46c2 100644
--- a/src/core/file_sys/filesystem.h
+++ b/src/core/file_sys/filesystem.h
@@ -27,7 +27,7 @@ enum LowPathType : u32 {
     Wchar = 4,
 };
 
-enum EntryType : u32 {
+enum EntryType : u8 {
     Directory = 0,
     File = 1,
 };
diff --git a/src/core/file_sys/romfs_filesystem.h b/src/core/file_sys/romfs_filesystem.h
index cedd70645..be52f20ef 100644
--- a/src/core/file_sys/romfs_filesystem.h
+++ b/src/core/file_sys/romfs_filesystem.h
@@ -70,7 +70,10 @@ private:
 
 class ROMFSDirectory : public DirectoryBackend {
 public:
-    u32 Read(const u32 count, Entry* entries) override {
+    u64 Read(const u64 count, Entry* entries) override {
+        return 0;
+    }
+    u64 GetEntryCount() const override {
         return 0;
     }
     bool Close() const override {

From e1d7b9fc2c8780552b40e8415104b4205efe2de7 Mon Sep 17 00:00:00 2001
From: Subv <subv2112@gmail.com>
Date: Mon, 19 Mar 2018 22:59:38 -0500
Subject: [PATCH 05/10] FS: Implement DiskFileSystem::GetEntryType for existing
 files/directories.

---
 src/core/file_sys/disk_filesystem.cpp | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/src/core/file_sys/disk_filesystem.cpp b/src/core/file_sys/disk_filesystem.cpp
index e2092b9df..e02b20faf 100644
--- a/src/core/file_sys/disk_filesystem.cpp
+++ b/src/core/file_sys/disk_filesystem.cpp
@@ -123,8 +123,10 @@ ResultVal<FileSys::EntryType> Disk_FileSystem::GetEntryType(const std::string& p
         return ERROR_PATH_NOT_FOUND;
     }
 
-    // TODO(Subv): Find out the EntryType values
-    UNIMPLEMENTED_MSG("Unimplemented GetEntryType");
+    if (FileUtil::IsDirectory(full_path))
+        return MakeResult(EntryType::Directory);
+
+    return MakeResult(EntryType::File);
 }
 
 ResultVal<size_t> Disk_Storage::Read(const u64 offset, const size_t length, u8* buffer) const {

From 6d90d99d12c6a1e7ec27831d93052a30c0e689b5 Mon Sep 17 00:00:00 2001
From: Subv <subv2112@gmail.com>
Date: Mon, 19 Mar 2018 23:00:37 -0500
Subject: [PATCH 06/10] FS: Implement DiskFileSystem's OpenDirectory interface.

---
 src/core/file_sys/disk_filesystem.cpp  | 13 +++++++++++--
 src/core/file_sys/disk_filesystem.h    |  3 ++-
 src/core/file_sys/filesystem.h         |  3 ++-
 src/core/file_sys/romfs_filesystem.cpp |  3 ++-
 src/core/file_sys/romfs_filesystem.h   |  3 ++-
 5 files changed, 19 insertions(+), 6 deletions(-)

diff --git a/src/core/file_sys/disk_filesystem.cpp b/src/core/file_sys/disk_filesystem.cpp
index e02b20faf..f620b7961 100644
--- a/src/core/file_sys/disk_filesystem.cpp
+++ b/src/core/file_sys/disk_filesystem.cpp
@@ -108,8 +108,17 @@ ResultCode Disk_FileSystem::RenameDirectory(const Path& src_path, const Path& de
 }
 
 ResultVal<std::unique_ptr<DirectoryBackend>> Disk_FileSystem::OpenDirectory(
-    const Path& path) const {
-    return MakeResult<std::unique_ptr<DirectoryBackend>>(std::make_unique<Disk_Directory>());
+    const std::string& path) const {
+
+    std::string full_path = base_directory + path;
+
+    if (!FileUtil::IsDirectory(full_path)) {
+        // TODO(Subv): Find the correct error code for this.
+        return ResultCode(-1);
+    }
+
+    auto directory = std::make_unique<Disk_Directory>(full_path);
+    return MakeResult<std::unique_ptr<DirectoryBackend>>(std::move(directory));
 }
 
 u64 Disk_FileSystem::GetFreeSpaceSize() const {
diff --git a/src/core/file_sys/disk_filesystem.h b/src/core/file_sys/disk_filesystem.h
index 29383dbf7..72a0afedf 100644
--- a/src/core/file_sys/disk_filesystem.h
+++ b/src/core/file_sys/disk_filesystem.h
@@ -32,7 +32,8 @@ public:
     ResultCode CreateFile(const std::string& path, u64 size) const override;
     ResultCode CreateDirectory(const Path& path) const override;
     ResultCode RenameDirectory(const Path& src_path, const Path& dest_path) const override;
-    ResultVal<std::unique_ptr<DirectoryBackend>> OpenDirectory(const Path& path) const override;
+    ResultVal<std::unique_ptr<DirectoryBackend>> OpenDirectory(
+        const std::string& path) const override;
     u64 GetFreeSpaceSize() const override;
     ResultVal<EntryType> GetEntryType(const std::string& path) const override;
 
diff --git a/src/core/file_sys/filesystem.h b/src/core/file_sys/filesystem.h
index 5c91a46c2..22ad24143 100644
--- a/src/core/file_sys/filesystem.h
+++ b/src/core/file_sys/filesystem.h
@@ -150,7 +150,8 @@ public:
      * @param path Path relative to the archive
      * @return Opened directory, or error code
      */
-    virtual ResultVal<std::unique_ptr<DirectoryBackend>> OpenDirectory(const Path& path) const = 0;
+    virtual ResultVal<std::unique_ptr<DirectoryBackend>> OpenDirectory(
+        const std::string& path) const = 0;
 
     /**
      * Get the free space
diff --git a/src/core/file_sys/romfs_filesystem.cpp b/src/core/file_sys/romfs_filesystem.cpp
index f1f9b4d04..169f0d4f6 100644
--- a/src/core/file_sys/romfs_filesystem.cpp
+++ b/src/core/file_sys/romfs_filesystem.cpp
@@ -70,7 +70,8 @@ ResultCode RomFS_FileSystem::RenameDirectory(const Path& src_path, const Path& d
 }
 
 ResultVal<std::unique_ptr<DirectoryBackend>> RomFS_FileSystem::OpenDirectory(
-    const Path& path) const {
+    const std::string& path) const {
+    LOG_WARNING(Service_FS, "Opening Directory in a ROMFS archive");
     return MakeResult<std::unique_ptr<DirectoryBackend>>(std::make_unique<ROMFSDirectory>());
 }
 
diff --git a/src/core/file_sys/romfs_filesystem.h b/src/core/file_sys/romfs_filesystem.h
index be52f20ef..ee41c2d02 100644
--- a/src/core/file_sys/romfs_filesystem.h
+++ b/src/core/file_sys/romfs_filesystem.h
@@ -38,7 +38,8 @@ public:
     ResultCode CreateFile(const std::string& path, u64 size) const override;
     ResultCode CreateDirectory(const Path& path) const override;
     ResultCode RenameDirectory(const Path& src_path, const Path& dest_path) const override;
-    ResultVal<std::unique_ptr<DirectoryBackend>> OpenDirectory(const Path& path) const override;
+    ResultVal<std::unique_ptr<DirectoryBackend>> OpenDirectory(
+        const std::string& path) const override;
     u64 GetFreeSpaceSize() const override;
     ResultVal<EntryType> GetEntryType(const std::string& path) const override;
 

From 21bac2d7d757df18f184a8d79393ab8f91c0fc03 Mon Sep 17 00:00:00 2001
From: Subv <subv2112@gmail.com>
Date: Mon, 19 Mar 2018 23:01:47 -0500
Subject: [PATCH 07/10] FS: Added the IDirectory IPC interface and implemented
 its two functions.

---
 src/core/hle/service/filesystem/fsp_srv.cpp | 51 +++++++++++++++++++++
 1 file changed, 51 insertions(+)

diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp
index 720ac9930..5536991bc 100644
--- a/src/core/hle/service/filesystem/fsp_srv.cpp
+++ b/src/core/hle/service/filesystem/fsp_srv.cpp
@@ -5,6 +5,7 @@
 #include <cinttypes>
 #include "common/logging/log.h"
 #include "core/core.h"
+#include "core/file_sys/directory.h"
 #include "core/file_sys/filesystem.h"
 #include "core/file_sys/storage.h"
 #include "core/hle/ipc_helpers.h"
@@ -151,6 +152,56 @@ private:
     }
 };
 
+class IDirectory final : public ServiceFramework<IDirectory> {
+public:
+    explicit IDirectory(std::unique_ptr<FileSys::DirectoryBackend>&& backend)
+        : ServiceFramework("IDirectory"), backend(std::move(backend)) {
+        static const FunctionInfo functions[] = {
+            {0, &IDirectory::Read, "Read"},
+            {1, &IDirectory::GetEntryCount, "GetEntryCount"},
+        };
+        RegisterHandlers(functions);
+    }
+
+private:
+    std::unique_ptr<FileSys::DirectoryBackend> backend;
+
+    void Read(Kernel::HLERequestContext& ctx) {
+        IPC::RequestParser rp{ctx};
+        const u64 unk = rp.Pop<u64>();
+
+        LOG_DEBUG(Service_FS, "called, unk=0x%llx", unk);
+
+        // Calculate how many entries we can fit in the output buffer
+        u64 count_entries = ctx.GetWriteBufferSize() / sizeof(FileSys::Entry);
+
+        // Read the data from the Directory backend
+        std::vector<FileSys::Entry> entries(count_entries);
+        u64 read_entries = backend->Read(count_entries, entries.data());
+
+        // Convert the data into a byte array
+        std::vector<u8> output(entries.size() * sizeof(FileSys::Entry));
+        std::memcpy(output.data(), entries.data(), output.size());
+
+        // Write the data to memory
+        ctx.WriteBuffer(output);
+
+        IPC::ResponseBuilder rb{ctx, 4};
+        rb.Push(RESULT_SUCCESS);
+        rb.Push(read_entries);
+    }
+
+    void GetEntryCount(Kernel::HLERequestContext& ctx) {
+        LOG_DEBUG(Service_FS, "called");
+
+        u64 count = backend->GetEntryCount();
+
+        IPC::ResponseBuilder rb{ctx, 4};
+        rb.Push(RESULT_SUCCESS);
+        rb.Push(count);
+    }
+};
+
 class IFileSystem final : public ServiceFramework<IFileSystem> {
 public:
     explicit IFileSystem(std::unique_ptr<FileSys::FileSystemBackend>&& backend)

From 0485ee499f9e00fb2ec1926876d6e50c9b22447b Mon Sep 17 00:00:00 2001
From: Subv <subv2112@gmail.com>
Date: Mon, 19 Mar 2018 23:02:30 -0500
Subject: [PATCH 08/10] FS: Implemented IFileSystem's OpenDirectory function.

Note that the filter parameter is not yet implemented.
---
 src/core/hle/service/filesystem/fsp_srv.cpp | 28 +++++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp
index 5536991bc..6f539316e 100644
--- a/src/core/hle/service/filesystem/fsp_srv.cpp
+++ b/src/core/hle/service/filesystem/fsp_srv.cpp
@@ -210,6 +210,7 @@ public:
             {0, &IFileSystem::CreateFile, "CreateFile"},
             {7, &IFileSystem::GetEntryType, "GetEntryType"},
             {8, &IFileSystem::OpenFile, "OpenFile"},
+            {9, &IFileSystem::OpenDirectory, "OpenDirectory"},
             {10, &IFileSystem::Commit, "Commit"},
         };
         RegisterHandlers(functions);
@@ -259,6 +260,33 @@ public:
         rb.PushIpcInterface<IFile>(std::move(file));
     }
 
+    void OpenDirectory(Kernel::HLERequestContext& ctx) {
+        IPC::RequestParser rp{ctx};
+
+        auto file_buffer = ctx.ReadBuffer();
+        auto end = std::find(file_buffer.begin(), file_buffer.end(), '\0');
+
+        std::string name(file_buffer.begin(), end);
+
+        // TODO(Subv): Implement this filter.
+        u32 filter_flags = rp.Pop<u32>();
+
+        LOG_DEBUG(Service_FS, "called directory %s filter %u", name.c_str(), filter_flags);
+
+        auto result = backend->OpenDirectory(name);
+        if (result.Failed()) {
+            IPC::ResponseBuilder rb{ctx, 2};
+            rb.Push(result.Code());
+            return;
+        }
+
+        auto directory = std::move(result.Unwrap());
+
+        IPC::ResponseBuilder rb{ctx, 2, 0, 1};
+        rb.Push(RESULT_SUCCESS);
+        rb.PushIpcInterface<IDirectory>(std::move(directory));
+    }
+
     void GetEntryType(Kernel::HLERequestContext& ctx) {
         IPC::RequestParser rp{ctx};
 

From eff3f60b73343365ad65638f55591965df6f7e25 Mon Sep 17 00:00:00 2001
From: Subv <subv2112@gmail.com>
Date: Wed, 21 Mar 2018 09:36:26 -0500
Subject: [PATCH 09/10] FS: Implemented IFileSystem::CreateDirectory.

---
 src/core/file_sys/disk_filesystem.cpp       | 13 ++++++++++---
 src/core/file_sys/disk_filesystem.h         |  2 +-
 src/core/file_sys/filesystem.h              |  2 +-
 src/core/file_sys/romfs_filesystem.cpp      |  2 +-
 src/core/file_sys/romfs_filesystem.h        |  2 +-
 src/core/hle/service/filesystem/fsp_srv.cpp | 15 +++++++++++++++
 6 files changed, 29 insertions(+), 7 deletions(-)

diff --git a/src/core/file_sys/disk_filesystem.cpp b/src/core/file_sys/disk_filesystem.cpp
index f620b7961..9383bf856 100644
--- a/src/core/file_sys/disk_filesystem.cpp
+++ b/src/core/file_sys/disk_filesystem.cpp
@@ -18,7 +18,7 @@ std::string Disk_FileSystem::GetName() const {
 ResultVal<std::unique_ptr<StorageBackend>> Disk_FileSystem::OpenFile(const std::string& path,
                                                                      Mode mode) const {
 
-    std::string mode_str = "";
+    std::string mode_str;
     u32 mode_flags = static_cast<u32>(mode);
 
     // Calculate the correct open mode for the file.
@@ -95,8 +95,15 @@ ResultCode Disk_FileSystem::CreateFile(const std::string& path, u64 size) const
     return ResultCode(-1);
 }
 
-ResultCode Disk_FileSystem::CreateDirectory(const Path& path) const {
-    LOG_WARNING(Service_FS, "(STUBBED) called");
+ResultCode Disk_FileSystem::CreateDirectory(const std::string& path) const {
+    // TODO(Subv): Perform path validation to prevent escaping the emulator sandbox.
+    std::string full_path = base_directory + path;
+
+    if (FileUtil::CreateDir(full_path)) {
+        return RESULT_SUCCESS;
+    }
+
+    LOG_CRITICAL(Service_FS, "(unreachable) Unknown error creating %s", full_path.c_str());
     // TODO(wwylele): Use correct error code
     return ResultCode(-1);
 }
diff --git a/src/core/file_sys/disk_filesystem.h b/src/core/file_sys/disk_filesystem.h
index 72a0afedf..742d7db1a 100644
--- a/src/core/file_sys/disk_filesystem.h
+++ b/src/core/file_sys/disk_filesystem.h
@@ -30,7 +30,7 @@ public:
     ResultCode DeleteDirectory(const Path& path) const override;
     ResultCode DeleteDirectoryRecursively(const Path& path) const override;
     ResultCode CreateFile(const std::string& path, u64 size) const override;
-    ResultCode CreateDirectory(const Path& path) const override;
+    ResultCode CreateDirectory(const std::string& path) const override;
     ResultCode RenameDirectory(const Path& src_path, const Path& dest_path) const override;
     ResultVal<std::unique_ptr<DirectoryBackend>> OpenDirectory(
         const std::string& path) const override;
diff --git a/src/core/file_sys/filesystem.h b/src/core/file_sys/filesystem.h
index 22ad24143..399427ca2 100644
--- a/src/core/file_sys/filesystem.h
+++ b/src/core/file_sys/filesystem.h
@@ -104,7 +104,7 @@ public:
      * @param path Path relative to the archive
      * @return Result of the operation
      */
-    virtual ResultCode CreateDirectory(const Path& path) const = 0;
+    virtual ResultCode CreateDirectory(const std::string& path) const = 0;
 
     /**
      * Delete a directory specified by its path
diff --git a/src/core/file_sys/romfs_filesystem.cpp b/src/core/file_sys/romfs_filesystem.cpp
index 169f0d4f6..0c6cc3157 100644
--- a/src/core/file_sys/romfs_filesystem.cpp
+++ b/src/core/file_sys/romfs_filesystem.cpp
@@ -55,7 +55,7 @@ ResultCode RomFS_FileSystem::CreateFile(const std::string& path, u64 size) const
     return ResultCode(-1);
 }
 
-ResultCode RomFS_FileSystem::CreateDirectory(const Path& path) const {
+ResultCode RomFS_FileSystem::CreateDirectory(const std::string& path) const {
     LOG_CRITICAL(Service_FS, "Attempted to create a directory in an ROMFS archive (%s).",
                  GetName().c_str());
     // TODO(wwylele): Use correct error code
diff --git a/src/core/file_sys/romfs_filesystem.h b/src/core/file_sys/romfs_filesystem.h
index ee41c2d02..3f94c04d0 100644
--- a/src/core/file_sys/romfs_filesystem.h
+++ b/src/core/file_sys/romfs_filesystem.h
@@ -36,7 +36,7 @@ public:
     ResultCode DeleteDirectory(const Path& path) const override;
     ResultCode DeleteDirectoryRecursively(const Path& path) const override;
     ResultCode CreateFile(const std::string& path, u64 size) const override;
-    ResultCode CreateDirectory(const Path& path) const override;
+    ResultCode CreateDirectory(const std::string& path) const override;
     ResultCode RenameDirectory(const Path& src_path, const Path& dest_path) const override;
     ResultVal<std::unique_ptr<DirectoryBackend>> OpenDirectory(
         const std::string& path) const override;
diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp
index 6f539316e..cbb7552d9 100644
--- a/src/core/hle/service/filesystem/fsp_srv.cpp
+++ b/src/core/hle/service/filesystem/fsp_srv.cpp
@@ -208,6 +208,7 @@ public:
         : ServiceFramework("IFileSystem"), backend(std::move(backend)) {
         static const FunctionInfo functions[] = {
             {0, &IFileSystem::CreateFile, "CreateFile"},
+            {2, &IFileSystem::CreateDirectory, "CreateDirectory"},
             {7, &IFileSystem::GetEntryType, "GetEntryType"},
             {8, &IFileSystem::OpenFile, "OpenFile"},
             {9, &IFileSystem::OpenDirectory, "OpenDirectory"},
@@ -234,6 +235,20 @@ public:
         rb.Push(backend->CreateFile(name, size));
     }
 
+    void CreateDirectory(Kernel::HLERequestContext& ctx) {
+        IPC::RequestParser rp{ctx};
+
+        auto file_buffer = ctx.ReadBuffer();
+        auto end = std::find(file_buffer.begin(), file_buffer.end(), '\0');
+
+        std::string name(file_buffer.begin(), end);
+
+        LOG_DEBUG(Service_FS, "called directory %s", name.c_str());
+
+        IPC::ResponseBuilder rb{ctx, 2};
+        rb.Push(backend->CreateDirectory(name));
+    }
+
     void OpenFile(Kernel::HLERequestContext& ctx) {
         IPC::RequestParser rp{ctx};
 

From 4c06d55a81304d0e658adf441d8bdb90a32ba228 Mon Sep 17 00:00:00 2001
From: Subv <subv2112@gmail.com>
Date: Fri, 23 Mar 2018 11:09:09 -0500
Subject: [PATCH 10/10] FS: Move the file open mode calculation to a separate
 function.

---
 src/core/file_sys/disk_filesystem.cpp | 21 ++++++++++++++-------
 1 file changed, 14 insertions(+), 7 deletions(-)

diff --git a/src/core/file_sys/disk_filesystem.cpp b/src/core/file_sys/disk_filesystem.cpp
index 9383bf856..3a4b45721 100644
--- a/src/core/file_sys/disk_filesystem.cpp
+++ b/src/core/file_sys/disk_filesystem.cpp
@@ -11,13 +11,7 @@
 
 namespace FileSys {
 
-std::string Disk_FileSystem::GetName() const {
-    return "Disk";
-}
-
-ResultVal<std::unique_ptr<StorageBackend>> Disk_FileSystem::OpenFile(const std::string& path,
-                                                                     Mode mode) const {
-
+static std::string ModeFlagsToString(Mode mode) {
     std::string mode_str;
     u32 mode_flags = static_cast<u32>(mode);
 
@@ -39,6 +33,19 @@ ResultVal<std::unique_ptr<StorageBackend>> Disk_FileSystem::OpenFile(const std::
 
     mode_str += "b";
 
+    return mode_str;
+}
+
+std::string Disk_FileSystem::GetName() const {
+    return "Disk";
+}
+
+ResultVal<std::unique_ptr<StorageBackend>> Disk_FileSystem::OpenFile(const std::string& path,
+                                                                     Mode mode) const {
+
+    // Calculate the correct open mode for the file.
+    std::string mode_str = ModeFlagsToString(mode);
+
     std::string full_path = base_directory + path;
     auto file = std::make_shared<FileUtil::IOFile>(full_path, mode_str.c_str());