Skip to content

Commit

Permalink
Merge pull request #5870 from JosJuice/lazy-filesystem
Browse files Browse the repository at this point in the history
DiscIO: Use Common::Lazy more
  • Loading branch information
leoetlino committed Sep 15, 2017
2 parents 7caf44c + f294599 commit 7cb8d66
Show file tree
Hide file tree
Showing 23 changed files with 237 additions and 249 deletions.
10 changes: 10 additions & 0 deletions Source/Core/Common/Lazy.h
Expand Up @@ -21,6 +21,16 @@ class Lazy
Lazy() : m_value(T()) {}
Lazy(const std::variant<T, std::function<T()>>& value) : m_value(value) {}
Lazy(std::variant<T, std::function<T()>>&& value) : m_value(std::move(value)) {}
const Lazy<T>& operator=(const std::variant<T, std::function<T()>>& value)
{
m_value = value;
return *this;
}
const Lazy<T>& operator=(std::variant<T, std::function<T()>>&& value)
{
m_value = std::move(value);
return *this;
}
const T& operator*() const { return *ComputeValue(); }
const T* operator->() const { return ComputeValue(); }
T& operator*() { return *ComputeValue(); }
Expand Down
9 changes: 1 addition & 8 deletions Source/Core/Core/HW/DVD/DVDThread.cpp
Expand Up @@ -116,7 +116,6 @@ void Stop()
{
StopDVDThread();
s_disc.reset();
FileMonitor::SetFileSystem(nullptr);
}

static void StopDVDThread()
Expand Down Expand Up @@ -160,14 +159,9 @@ void DoState(PointerWrap& p)
if (had_disc != HasDisc())
{
if (had_disc)
{
PanicAlertT("An inserted disc was expected but not found.");
}
else
{
s_disc.reset();
FileMonitor::SetFileSystem(nullptr);
}
}

// TODO: Savestates can be smaller if the buffers of results aren't saved,
Expand All @@ -185,7 +179,6 @@ void SetDisc(std::unique_ptr<DiscIO::Volume> disc)
{
WaitUntilIdle();
s_disc = std::move(disc);
FileMonitor::SetFileSystem(s_disc.get());
}

bool HasDisc()
Expand Down Expand Up @@ -356,7 +349,7 @@ static void DVDThread()
ReadRequest request;
while (s_request_queue.Pop(request))
{
FileMonitor::Log(request.dvd_offset, request.partition);
FileMonitor::Log(*s_disc, request.partition, request.dvd_offset);

std::vector<u8> buffer(request.length);
if (!s_disc->Read(request.dvd_offset, request.length, buffer.data(), request.partition))
Expand Down
39 changes: 7 additions & 32 deletions Source/Core/Core/HW/DVD/FileMonitor.cpp
Expand Up @@ -21,10 +21,7 @@

namespace FileMonitor
{
static const DiscIO::Volume* s_volume;
static bool s_new_volume = false;
static std::unique_ptr<DiscIO::FileSystem> s_filesystem;
static DiscIO::Partition s_partition;
static DiscIO::Partition s_previous_partition;
static std::string s_previous_file;

// Filtered files
Expand Down Expand Up @@ -53,42 +50,19 @@ static bool IsSoundFile(const std::string& filename)
return extensions.find(extension) != extensions.end();
}

void SetFileSystem(const DiscIO::Volume* volume)
{
// Instead of creating the file system object right away, we will let Log
// create it later once we know that it actually will get used
s_volume = volume;
s_new_volume = true;
}

// Logs access to files in the file system set by SetFileSystem
void Log(u64 offset, const DiscIO::Partition& partition)
void Log(const DiscIO::Volume& volume, const DiscIO::Partition& partition, u64 offset)
{
// Do nothing if the log isn't selected
if (!LogManager::GetInstance()->IsEnabled(LogTypes::FILEMON, LogTypes::LWARNING))
return;

// If the volume or partition changed, load the filesystem of the new partition
if (s_new_volume || s_partition != partition)
{
// Discs with partitions don't have PARTITION_NONE filesystems,
// so let's not waste time trying to read one
const bool reading_from_partition = partition != DiscIO::PARTITION_NONE;
const bool disc_has_partitions = !s_volume->GetPartitions().empty();
if (reading_from_partition != disc_has_partitions)
return;

s_new_volume = false;
s_filesystem = DiscIO::CreateFileSystem(s_volume, partition);
s_partition = partition;
s_previous_file.clear();
}
const DiscIO::FileSystem* file_system = volume.GetFileSystem(partition);

// Do nothing if there is no valid file system
if (!s_filesystem)
if (!file_system)
return;

const std::unique_ptr<DiscIO::FileInfo> file_info = s_filesystem->FindFileInfo(offset);
const std::unique_ptr<DiscIO::FileInfo> file_info = file_system->FindFileInfo(offset);

// Do nothing if no file was found at that offset
if (!file_info)
Expand All @@ -97,7 +71,7 @@ void Log(u64 offset, const DiscIO::Partition& partition)
const std::string path = file_info->GetPath();

// Do nothing if we found the same file again
if (s_previous_file == path)
if (s_previous_partition == partition && s_previous_file == path)
return;

const std::string size_string = ThousandSeparate(file_info->GetSize() / 1000, 7);
Expand All @@ -109,6 +83,7 @@ void Log(u64 offset, const DiscIO::Partition& partition)
WARN_LOG(FILEMON, "%s", log_string.c_str());

// Update the last accessed file
s_previous_partition = partition;
s_previous_file = path;
}

Expand Down
6 changes: 1 addition & 5 deletions Source/Core/Core/HW/DVD/FileMonitor.h
Expand Up @@ -14,9 +14,5 @@ class Volume;

namespace FileMonitor
{
// Can be called with nullptr to set the file system to nothing. When not called
// with nullptr, the volume must remain valid until the next SetFileSystem call.
void SetFileSystem(const DiscIO::Volume* volume);
// Logs access to files in the file system set by SetFileSystem
void Log(u64 offset, const DiscIO::Partition& partition);
void Log(const DiscIO::Volume& volume, const DiscIO::Partition& partition, u64 offset);
}
28 changes: 16 additions & 12 deletions Source/Core/Core/WiiUtils.cpp
Expand Up @@ -552,7 +552,7 @@ class DiscSystemUpdater final : public SystemUpdater

UpdateCallback m_update_callback;
std::unique_ptr<DiscIO::Volume> m_volume;
std::unique_ptr<DiscIO::FileSystem> m_disc_fs;
DiscIO::Partition m_partition;
};

UpdateResult DiscSystemUpdater::DoDiscUpdate()
Expand All @@ -578,16 +578,21 @@ UpdateResult DiscSystemUpdater::DoDiscUpdate()
return UpdateResult::MissingUpdatePartition;
}

m_disc_fs = DiscIO::CreateFileSystem(m_volume.get(), *update_partition);
if (!m_disc_fs || !m_disc_fs->IsValid())
return UpdateResult::DiscReadFailed;
m_partition = *update_partition;

return UpdateFromManifest("__update.inf");
}

UpdateResult DiscSystemUpdater::UpdateFromManifest(const std::string& manifest_name)
{
const std::unique_ptr<DiscIO::FileInfo> update_manifest = m_disc_fs->FindFileInfo(manifest_name);
const DiscIO::FileSystem* disc_fs = m_volume->GetFileSystem(m_partition);
if (!disc_fs)
{
ERROR_LOG(CORE, "Could not read the update partition file system");
return UpdateResult::DiscReadFailed;
}

const std::unique_ptr<DiscIO::FileInfo> update_manifest = disc_fs->FindFileInfo(manifest_name);
if (!update_manifest ||
(update_manifest->GetSize() - sizeof(ManifestHeader)) % sizeof(Entry) != 0)
{
Expand All @@ -604,8 +609,8 @@ UpdateResult DiscSystemUpdater::UpdateFromManifest(const std::string& manifest_n
for (u32 i = 0; i < num_entries; ++i)
{
const u32 offset = sizeof(ManifestHeader) + sizeof(Entry) * i;
if (entry.size() != DiscIO::ReadFile(*m_volume, m_disc_fs->GetPartition(),
update_manifest.get(), entry.data(), entry.size(), offset))
if (entry.size() != DiscIO::ReadFile(*m_volume, m_partition, update_manifest.get(),
entry.data(), entry.size(), offset))
{
ERROR_LOG(CORE, "Failed to read update information from update manifest");
return UpdateResult::DiscReadFailed;
Expand Down Expand Up @@ -654,14 +659,13 @@ UpdateResult DiscSystemUpdater::ProcessEntry(u32 type, std::bitset<32> attrs,
return UpdateResult::AlreadyUpToDate;

// Import the WAD.
const std::unique_ptr<DiscIO::FileInfo> wad_file = m_disc_fs->FindFileInfo(path);
if (!wad_file)
auto blob = DiscIO::VolumeFileBlobReader::Create(*m_volume, m_partition, path);
if (!blob)
{
ERROR_LOG(CORE, "Failed to get info for %s", path.c_str());
ERROR_LOG(CORE, "Could not find %s", path.c_str());
return UpdateResult::DiscReadFailed;
}

const DiscIO::WiiWAD wad{DiscIO::VolumeFileBlobReader::Create(*m_volume, *m_disc_fs, path)};
const DiscIO::WiiWAD wad{std::move(blob)};
return InstallWAD(m_ios, wad) ? UpdateResult::Succeeded : UpdateResult::ImportFailed;
}

Expand Down
21 changes: 21 additions & 0 deletions Source/Core/DiscIO/DiscExtractor.cpp
Expand Up @@ -61,6 +61,17 @@ u64 ReadFile(const Volume& volume, const Partition& partition, const FileInfo* f
return read_length;
}

u64 ReadFile(const Volume& volume, const Partition& partition, const std::string& path, u8* buffer,
u64 max_buffer_size, u64 offset_in_file)
{
const FileSystem* file_system = volume.GetFileSystem(partition);
if (!file_system)
return 0;

return ReadFile(volume, partition, file_system->FindFileInfo(path).get(), buffer, max_buffer_size,
offset_in_file);
}

bool ExportData(const Volume& volume, const Partition& partition, u64 offset, u64 size,
const std::string& export_filename)
{
Expand Down Expand Up @@ -98,6 +109,16 @@ bool ExportFile(const Volume& volume, const Partition& partition, const FileInfo
export_filename);
}

bool ExportFile(const Volume& volume, const Partition& partition, const std::string& path,
const std::string& export_filename)
{
const FileSystem* file_system = volume.GetFileSystem(partition);
if (!file_system)
return false;

return ExportFile(volume, partition, file_system->FindFileInfo(path).get(), export_filename);
}

void ExportDirectory(const Volume& volume, const Partition partition, const FileInfo& directory,
bool recursive, const std::string& filesystem_path,
const std::string& export_folder,
Expand Down
4 changes: 4 additions & 0 deletions Source/Core/DiscIO/DiscExtractor.h
Expand Up @@ -19,10 +19,14 @@ std::string DirectoryNameForPartitionType(u32 partition_type);

u64 ReadFile(const Volume& volume, const Partition& partition, const FileInfo* file_info,
u8* buffer, u64 max_buffer_size, u64 offset_in_file = 0);
u64 ReadFile(const Volume& volume, const Partition& partition, const std::string& path, u8* buffer,
u64 max_buffer_size, u64 offset_in_file = 0);
bool ExportData(const Volume& volume, const Partition& partition, u64 offset, u64 size,
const std::string& export_filename);
bool ExportFile(const Volume& volume, const Partition& partition, const FileInfo* file_info,
const std::string& export_filename);
bool ExportFile(const Volume& volume, const Partition& partition, const std::string& path,
const std::string& export_filename);

// update_progress is called once for each child (file or directory).
// If update_progress returns true, the extraction gets cancelled.
Expand Down
2 changes: 1 addition & 1 deletion Source/Core/DiscIO/DiscScrubber.cpp
Expand Up @@ -182,7 +182,7 @@ bool DiscScrubber::ParseDisc()
// Operations dealing with encrypted space are done here
bool DiscScrubber::ParsePartitionData(const Partition& partition, PartitionHeader* header)
{
std::unique_ptr<FileSystem> filesystem(CreateFileSystem(m_disc.get(), partition));
const FileSystem* filesystem = m_disc->GetFileSystem(partition);
if (!filesystem)
{
ERROR_LOG(DISCIO, "Failed to read file system for the partition at 0x%" PRIx64,
Expand Down
12 changes: 6 additions & 6 deletions Source/Core/DiscIO/FileSystemGCWii.cpp
Expand Up @@ -185,19 +185,19 @@ bool FileInfoGCWii::IsValid(u64 fst_size, const FileInfoGCWii& parent_directory)
}

FileSystemGCWii::FileSystemGCWii(const Volume* volume, const Partition& partition)
: FileSystem(volume, partition), m_valid(false), m_root(nullptr, 0, 0, 0)
: m_valid(false), m_root(nullptr, 0, 0, 0)
{
u8 offset_shift;
// Check if this is a GameCube or Wii disc
if (m_volume->ReadSwapped<u32>(0x18, m_partition) == u32(0x5D1C9EA3))
if (volume->ReadSwapped<u32>(0x18, partition) == u32(0x5D1C9EA3))
offset_shift = 2; // Wii file system
else if (m_volume->ReadSwapped<u32>(0x1c, m_partition) == u32(0xC2339F3D))
else if (volume->ReadSwapped<u32>(0x1c, partition) == u32(0xC2339F3D))
offset_shift = 0; // GameCube file system
else
return; // Invalid partition (maybe someone removed its data but not its partition table entry)

const std::optional<u64> fst_offset = GetFSTOffset(*m_volume, m_partition);
const std::optional<u64> fst_size = GetFSTSize(*m_volume, m_partition);
const std::optional<u64> fst_offset = GetFSTOffset(*volume, partition);
const std::optional<u64> fst_size = GetFSTSize(*volume, partition);
if (!fst_offset || !fst_size)
return;
if (*fst_size < FST_ENTRY_SIZE)
Expand All @@ -220,7 +220,7 @@ FileSystemGCWii::FileSystemGCWii(const Volume* volume, const Partition& partitio

// Read the whole FST
m_file_system_table.resize(*fst_size);
if (!m_volume->Read(*fst_offset, *fst_size, m_file_system_table.data(), m_partition))
if (!volume->Read(*fst_offset, *fst_size, m_file_system_table.data(), partition))
{
ERROR_LOG(DISCIO, "Couldn't read file system table");
return;
Expand Down
24 changes: 0 additions & 24 deletions Source/Core/DiscIO/Filesystem.cpp
Expand Up @@ -3,35 +3,11 @@
// Refer to the license.txt file included.

#include "DiscIO/Filesystem.h"
#include <memory>
#include "DiscIO/FileSystemGCWii.h"
#include "DiscIO/Volume.h"

namespace DiscIO
{
FileInfo::~FileInfo() = default;

FileSystem::FileSystem(const Volume* volume, const Partition& partition)
: m_volume(volume), m_partition(partition)
{
}

FileSystem::~FileSystem() = default;

std::unique_ptr<FileSystem> CreateFileSystem(const Volume* volume, const Partition& partition)
{
if (!volume)
return nullptr;

std::unique_ptr<FileSystem> filesystem = std::make_unique<FileSystemGCWii>(volume, partition);

if (!filesystem)
return nullptr;

if (!filesystem->IsValid())
filesystem.reset();

return filesystem;
}

} // namespace
14 changes: 4 additions & 10 deletions Source/Core/DiscIO/Filesystem.h
Expand Up @@ -106,11 +106,9 @@ class FileInfo
class FileSystem
{
public:
FileSystem(const Volume* volume, const Partition& partition);
virtual ~FileSystem();

// If IsValid is false, GetRoot must not be called. CreateFileSystem
// takes care of this automatically, so other code is recommended to use it.
// If IsValid is false, GetRoot must not be called.
virtual bool IsValid() const = 0;
// The object returned by GetRoot and all objects created from it
// are only valid for as long as the file system object is valid.
Expand All @@ -119,14 +117,10 @@ class FileSystem
virtual std::unique_ptr<FileInfo> FindFileInfo(const std::string& path) const = 0;
// Returns nullptr if not found
virtual std::unique_ptr<FileInfo> FindFileInfo(u64 disc_offset) const = 0;

virtual const Partition GetPartition() const { return m_partition; }
protected:
const Volume* const m_volume;
const Partition m_partition;
};

// Returns nullptr if a valid file system could not be created
std::unique_ptr<FileSystem> CreateFileSystem(const Volume* volume, const Partition& partition);
// Calling Volume::GetFileSystem instead of manually constructing a filesystem is recommended,
// because it will check IsValid for you, will automatically pick the right type of filesystem,
// and will cache the filesystem in case it's needed again later.

} // namespace
3 changes: 3 additions & 0 deletions Source/Core/DiscIO/Volume.h
Expand Up @@ -21,6 +21,7 @@
namespace DiscIO
{
enum class BlobType;
class FileSystem;

struct Partition final
{
Expand Down Expand Up @@ -67,6 +68,8 @@ class Volume
return INVALID_TICKET;
}
virtual const IOS::ES::TMDReader& GetTMD(const Partition& partition) const { return INVALID_TMD; }
// Returns a non-owning pointer. Returns nullptr if the file system couldn't be read.
virtual const FileSystem* GetFileSystem(const Partition& partition) const = 0;
std::string GetGameID() const { return GetGameID(GetGamePartition()); }
virtual std::string GetGameID(const Partition& partition) const = 0;
std::string GetMakerID() const { return GetMakerID(GetGamePartition()); }
Expand Down

0 comments on commit 7cb8d66

Please sign in to comment.