Core/VirtualDirectory: Add Uproot property
This commit is contained in:
parent
b6ab3ba1b3
commit
dd4be081aa
|
|
@ -39,13 +39,17 @@ namespace Nz
|
|||
VirtualDirectory(VirtualDirectory&&) = delete;
|
||||
~VirtualDirectory() = default;
|
||||
|
||||
bool Exists(std::string_view path);
|
||||
inline void AllowUproot(bool uproot = true);
|
||||
|
||||
inline bool Exists(std::string_view path);
|
||||
|
||||
template<typename F> void Foreach(F&& callback, bool includeDots = false);
|
||||
|
||||
template<typename F> bool GetEntry(std::string_view path, F&& callback);
|
||||
template<typename F> bool GetFileContent(std::string_view path, F&& callback);
|
||||
|
||||
inline bool IsUprootAllowed() const;
|
||||
|
||||
inline DirectoryEntry& StoreDirectory(std::string_view path, VirtualDirectoryPtr directory);
|
||||
inline PhysicalDirectoryEntry& StoreDirectory(std::string_view path, std::filesystem::path directoryPath);
|
||||
inline FileContentEntry& StoreFile(std::string_view path, std::vector<UInt8> file);
|
||||
|
|
@ -99,6 +103,7 @@ namespace Nz
|
|||
std::optional<std::filesystem::path> m_physicalPath;
|
||||
std::vector<ContentEntry> m_content;
|
||||
std::weak_ptr<VirtualDirectory> m_parent;
|
||||
bool m_isUprootAllowed;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,16 +12,23 @@
|
|||
namespace Nz
|
||||
{
|
||||
inline VirtualDirectory::VirtualDirectory(std::weak_ptr<VirtualDirectory> parentDirectory) :
|
||||
m_parent(std::move(parentDirectory))
|
||||
m_parent(std::move(parentDirectory)),
|
||||
m_isUprootAllowed(false)
|
||||
{
|
||||
}
|
||||
|
||||
inline VirtualDirectory::VirtualDirectory(std::filesystem::path physicalPath, std::weak_ptr<VirtualDirectory> parentDirectory) :
|
||||
m_physicalPath(std::move(physicalPath)),
|
||||
m_parent(std::move(parentDirectory))
|
||||
m_parent(std::move(parentDirectory)),
|
||||
m_isUprootAllowed(false)
|
||||
{
|
||||
}
|
||||
|
||||
inline void VirtualDirectory::AllowUproot(bool uproot)
|
||||
{
|
||||
m_isUprootAllowed = uproot;
|
||||
}
|
||||
|
||||
inline bool VirtualDirectory::Exists(std::string_view path)
|
||||
{
|
||||
return GetEntry(path, [](const auto&) {});
|
||||
|
|
@ -94,7 +101,7 @@ namespace Nz
|
|||
if (physicalPathBase)
|
||||
{
|
||||
// Special case when traversing directory
|
||||
if (dirName == "..")
|
||||
if (dirName == ".." && !m_isUprootAllowed)
|
||||
{
|
||||
// Don't allow to escape virtual directory
|
||||
if (!physicalDirectoryParts.empty())
|
||||
|
|
@ -193,6 +200,11 @@ namespace Nz
|
|||
});
|
||||
}
|
||||
|
||||
inline bool VirtualDirectory::IsUprootAllowed() const
|
||||
{
|
||||
return m_isUprootAllowed;
|
||||
}
|
||||
|
||||
inline auto VirtualDirectory::StoreDirectory(std::string_view path, VirtualDirectoryPtr directory) -> DirectoryEntry&
|
||||
{
|
||||
assert(!path.empty());
|
||||
|
|
@ -260,46 +272,49 @@ namespace Nz
|
|||
Entry entry{ DirectoryEntry{ shared_from_this() } };
|
||||
return CallbackReturn(callback, entry);
|
||||
}
|
||||
else if (name == "..")
|
||||
|
||||
if (name == "..")
|
||||
{
|
||||
Entry entry;
|
||||
VirtualDirectoryPtr parentEntry;
|
||||
if (VirtualDirectoryPtr parent = m_parent.lock())
|
||||
entry = DirectoryEntry{ std::move(parent) };
|
||||
else
|
||||
entry = DirectoryEntry{ shared_from_this() };
|
||||
parentEntry = std::move(parent);
|
||||
else if (!m_isUprootAllowed)
|
||||
parentEntry = shared_from_this();
|
||||
|
||||
return CallbackReturn(callback, entry);
|
||||
if (parentEntry)
|
||||
{
|
||||
Entry entry = DirectoryEntry{ std::move(parentEntry) };
|
||||
return CallbackReturn(callback, entry);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
auto it = std::lower_bound(m_content.begin(), m_content.end(), name, [](const ContentEntry& entry, std::string_view name)
|
||||
{
|
||||
auto it = std::lower_bound(m_content.begin(), m_content.end(), name, [](const ContentEntry& entry, std::string_view name)
|
||||
return entry.name < name;
|
||||
});
|
||||
if (it == m_content.end() || it->name != name)
|
||||
{
|
||||
// Virtual file not found, check if it has a physical one
|
||||
if (m_physicalPath)
|
||||
{
|
||||
return entry.name < name;
|
||||
});
|
||||
if (it == m_content.end() || it->name != name)
|
||||
{
|
||||
// Virtual file not found, check if it has a physical one
|
||||
if (m_physicalPath)
|
||||
{
|
||||
std::filesystem::path filePath = *m_physicalPath / name;
|
||||
std::filesystem::file_status status = std::filesystem::status(filePath); //< FIXME: This will follow symlink, is this the intended behavior? (see symlink_status)
|
||||
std::filesystem::path filePath = *m_physicalPath / name;
|
||||
std::filesystem::file_status status = std::filesystem::status(filePath); //< FIXME: This will follow symlink, is this the intended behavior? (see symlink_status)
|
||||
|
||||
Entry entry;
|
||||
if (std::filesystem::is_regular_file(status))
|
||||
entry = PhysicalFileEntry{ std::move(filePath) };
|
||||
else if (std::filesystem::is_directory(status))
|
||||
entry = PhysicalDirectoryEntry{ std::move(filePath) };
|
||||
else
|
||||
return false; //< either not known or of a special type
|
||||
Entry entry;
|
||||
if (std::filesystem::is_regular_file(status))
|
||||
entry = PhysicalFileEntry{ std::move(filePath) };
|
||||
else if (std::filesystem::is_directory(status))
|
||||
entry = PhysicalDirectoryEntry{ std::move(filePath) };
|
||||
else
|
||||
return false; //< either not known or of a special type
|
||||
|
||||
return CallbackReturn(callback, entry);
|
||||
}
|
||||
|
||||
return false;
|
||||
return CallbackReturn(callback, entry);
|
||||
}
|
||||
|
||||
return CallbackReturn(callback, it->entry);
|
||||
return false;
|
||||
}
|
||||
|
||||
return CallbackReturn(callback, it->entry);
|
||||
}
|
||||
|
||||
inline bool VirtualDirectory::CreateOrRetrieveDirectory(std::string_view path, std::shared_ptr<VirtualDirectory>& directory, std::string_view& entryName)
|
||||
|
|
|
|||
|
|
@ -187,12 +187,12 @@ TEST_CASE("VirtualDirectory", "[Core][VirtualDirectory]")
|
|||
|
||||
SECTION("Accessing filesystem using a VirtualDirectory")
|
||||
{
|
||||
std::shared_ptr<Nz::VirtualDirectory> virtualDir = std::make_shared<Nz::VirtualDirectory>(GetResourceDir());
|
||||
std::shared_ptr<Nz::VirtualDirectory> resourceDir = std::make_shared<Nz::VirtualDirectory>(GetResourceDir());
|
||||
|
||||
WHEN("Iterating, it's not empty")
|
||||
{
|
||||
bool empty = true;
|
||||
virtualDir->Foreach([&](std::string_view name, const Nz::VirtualDirectory::Entry& entry)
|
||||
resourceDir->Foreach([&](std::string_view name, const Nz::VirtualDirectory::Entry& entry)
|
||||
{
|
||||
CHECK_FALSE(name == ".");
|
||||
CHECK_FALSE(name == "..");
|
||||
|
|
@ -205,9 +205,9 @@ TEST_CASE("VirtualDirectory", "[Core][VirtualDirectory]")
|
|||
REQUIRE_FALSE(empty);
|
||||
}
|
||||
|
||||
auto CheckFileHash = [&](const char* filepath, const char* expectedHash)
|
||||
auto CheckFileHash = [](const Nz::VirtualDirectoryPtr& dir, const char* filepath, const char* expectedHash)
|
||||
{
|
||||
return virtualDir->GetEntry(filepath, [&](const Nz::VirtualDirectory::Entry& entry)
|
||||
return dir->GetEntry(filepath, [&](const Nz::VirtualDirectory::Entry& entry)
|
||||
{
|
||||
REQUIRE(std::holds_alternative<Nz::VirtualDirectory::PhysicalFileEntry>(entry));
|
||||
|
||||
|
|
@ -224,9 +224,9 @@ TEST_CASE("VirtualDirectory", "[Core][VirtualDirectory]")
|
|||
});
|
||||
};
|
||||
|
||||
auto CheckFileContentHash = [&](const char* filepath, const char* expectedHash)
|
||||
auto CheckFileContentHash = [](const Nz::VirtualDirectoryPtr& dir, const char* filepath, const char* expectedHash)
|
||||
{
|
||||
return virtualDir->GetFileContent(filepath, [&](const void* data, std::size_t size)
|
||||
return dir->GetFileContent(filepath, [&](const void* data, std::size_t size)
|
||||
{
|
||||
Nz::SHA256Hash hash;
|
||||
WHEN("We compute " << hash.GetHashName() << " of " << filepath << " file")
|
||||
|
|
@ -240,42 +240,63 @@ TEST_CASE("VirtualDirectory", "[Core][VirtualDirectory]")
|
|||
|
||||
WHEN("Accessing files")
|
||||
{
|
||||
CHECK(CheckFileHash("Logo.png", "5C4B9387327C039A6CE9ED51983D6C2ADA9F9DD01D024C2D5D588237ADFC7423"));
|
||||
CHECK(CheckFileHash("./Logo.png", "5C4B9387327C039A6CE9ED51983D6C2ADA9F9DD01D024C2D5D588237ADFC7423"));
|
||||
CHECK(CheckFileHash("Engine/Audio/The_Brabanconne.ogg", "E07706E0BEEC7770CDE36008826743AF9EEE5C80CA0BD83C37771CBC8B52E738"));
|
||||
CHECK(CheckFileHash("Engine/Audio/./The_Brabanconne.ogg", "E07706E0BEEC7770CDE36008826743AF9EEE5C80CA0BD83C37771CBC8B52E738"));
|
||||
CHECK_FALSE(CheckFileHash("The_Brabanconne.ogg", "E07706E0BEEC7770CDE36008826743AF9EEE5C80CA0BD83C37771CBC8B52E738"));
|
||||
CHECK_FALSE(CheckFileHash("Engine/The_Brabanconne.ogg", "E07706E0BEEC7770CDE36008826743AF9EEE5C80CA0BD83C37771CBC8B52E738"));
|
||||
CHECK_FALSE(CheckFileHash("Engine/Audio/../The_Brabanconne.ogg", "E07706E0BEEC7770CDE36008826743AF9EEE5C80CA0BD83C37771CBC8B52E738"));
|
||||
CHECK(CheckFileHash(resourceDir, "Logo.png", "5C4B9387327C039A6CE9ED51983D6C2ADA9F9DD01D024C2D5D588237ADFC7423"));
|
||||
CHECK(CheckFileHash(resourceDir, "./Logo.png", "5C4B9387327C039A6CE9ED51983D6C2ADA9F9DD01D024C2D5D588237ADFC7423"));
|
||||
CHECK(CheckFileHash(resourceDir, "Engine/Audio/The_Brabanconne.ogg", "E07706E0BEEC7770CDE36008826743AF9EEE5C80CA0BD83C37771CBC8B52E738"));
|
||||
CHECK(CheckFileHash(resourceDir, "Engine/Audio/./The_Brabanconne.ogg", "E07706E0BEEC7770CDE36008826743AF9EEE5C80CA0BD83C37771CBC8B52E738"));
|
||||
CHECK_FALSE(CheckFileHash(resourceDir, "The_Brabanconne.ogg", "E07706E0BEEC7770CDE36008826743AF9EEE5C80CA0BD83C37771CBC8B52E738"));
|
||||
CHECK_FALSE(CheckFileHash(resourceDir, "Engine/The_Brabanconne.ogg", "E07706E0BEEC7770CDE36008826743AF9EEE5C80CA0BD83C37771CBC8B52E738"));
|
||||
CHECK_FALSE(CheckFileHash(resourceDir, "Engine/Audio/../The_Brabanconne.ogg", "E07706E0BEEC7770CDE36008826743AF9EEE5C80CA0BD83C37771CBC8B52E738"));
|
||||
|
||||
// We can't escape the virtual directory
|
||||
CHECK(CheckFileHash("../Logo.png", "5C4B9387327C039A6CE9ED51983D6C2ADA9F9DD01D024C2D5D588237ADFC7423"));
|
||||
CHECK(CheckFileHash("../../Logo.png", "5C4B9387327C039A6CE9ED51983D6C2ADA9F9DD01D024C2D5D588237ADFC7423"));
|
||||
CHECK(CheckFileHash("Engine/../Engine/Audio/The_Brabanconne.ogg", "E07706E0BEEC7770CDE36008826743AF9EEE5C80CA0BD83C37771CBC8B52E738"));
|
||||
CHECK(CheckFileHash("../Engine/./Audio/The_Brabanconne.ogg", "E07706E0BEEC7770CDE36008826743AF9EEE5C80CA0BD83C37771CBC8B52E738"));
|
||||
CHECK_FALSE(CheckFileHash("../Engine/Engine/Audio/The_Brabanconne.ogg", "E07706E0BEEC7770CDE36008826743AF9EEE5C80CA0BD83C37771CBC8B52E738"));
|
||||
CHECK(CheckFileHash(resourceDir, "../Logo.png", "5C4B9387327C039A6CE9ED51983D6C2ADA9F9DD01D024C2D5D588237ADFC7423"));
|
||||
CHECK(CheckFileHash(resourceDir, "../../Logo.png", "5C4B9387327C039A6CE9ED51983D6C2ADA9F9DD01D024C2D5D588237ADFC7423"));
|
||||
CHECK(CheckFileHash(resourceDir, "Engine/../Engine/Audio/The_Brabanconne.ogg", "E07706E0BEEC7770CDE36008826743AF9EEE5C80CA0BD83C37771CBC8B52E738"));
|
||||
CHECK(CheckFileHash(resourceDir, "../Engine/./Audio/The_Brabanconne.ogg", "E07706E0BEEC7770CDE36008826743AF9EEE5C80CA0BD83C37771CBC8B52E738"));
|
||||
CHECK_FALSE(CheckFileHash(resourceDir, "../Engine/Engine/Audio/The_Brabanconne.ogg", "E07706E0BEEC7770CDE36008826743AF9EEE5C80CA0BD83C37771CBC8B52E738"));
|
||||
|
||||
auto CheckOurselves = [&](const auto& entry)
|
||||
{
|
||||
REQUIRE(std::holds_alternative<Nz::VirtualDirectory::DirectoryEntry>(entry));
|
||||
const auto& dirEntry = std::get<Nz::VirtualDirectory::DirectoryEntry>(entry);
|
||||
return dirEntry.directory == virtualDir;
|
||||
return dirEntry.directory == resourceDir;
|
||||
};
|
||||
|
||||
CHECK(virtualDir->GetEntry("..", CheckOurselves));
|
||||
CHECK(virtualDir->GetEntry("../..", CheckOurselves));
|
||||
CHECK(virtualDir->GetEntry("./..", CheckOurselves));
|
||||
CHECK(virtualDir->GetEntry("./..", CheckOurselves));
|
||||
CHECK(virtualDir->GetEntry("Engine/../..", CheckOurselves));
|
||||
CHECK(virtualDir->GetEntry("Engine/../Engine/Audio/../../..", CheckOurselves));
|
||||
CHECK(resourceDir->GetEntry("..", CheckOurselves));
|
||||
CHECK(resourceDir->GetEntry("../..", CheckOurselves));
|
||||
CHECK(resourceDir->GetEntry("./..", CheckOurselves));
|
||||
CHECK(resourceDir->GetEntry("./..", CheckOurselves));
|
||||
CHECK(resourceDir->GetEntry("Engine/../..", CheckOurselves));
|
||||
CHECK(resourceDir->GetEntry("Engine/../Engine/Audio/../../..", CheckOurselves));
|
||||
}
|
||||
AND_THEN("Overriding the physical file with another one")
|
||||
{
|
||||
virtualDir->StoreFile("Logo.png", GetResourceDir() / "ambience.ogg");
|
||||
CHECK(CheckFileHash("ambience.ogg", "49C486F44E43F023D54C9F375D902C21375DDB2748D3FA1863C9581D30E17F94"));
|
||||
CHECK(CheckFileHash("Logo.png", "49C486F44E43F023D54C9F375D902C21375DDB2748D3FA1863C9581D30E17F94"));
|
||||
CHECK(CheckFileContentHash("ambience.ogg", "49C486F44E43F023D54C9F375D902C21375DDB2748D3FA1863C9581D30E17F94"));
|
||||
CHECK(CheckFileContentHash("Logo.png", "49C486F44E43F023D54C9F375D902C21375DDB2748D3FA1863C9581D30E17F94"));
|
||||
resourceDir->StoreFile("Logo.png", GetResourceDir() / "ambience.ogg");
|
||||
CHECK(CheckFileHash(resourceDir, "ambience.ogg", "49C486F44E43F023D54C9F375D902C21375DDB2748D3FA1863C9581D30E17F94"));
|
||||
CHECK(CheckFileHash(resourceDir, "Logo.png", "49C486F44E43F023D54C9F375D902C21375DDB2748D3FA1863C9581D30E17F94"));
|
||||
CHECK(CheckFileContentHash(resourceDir, "ambience.ogg", "49C486F44E43F023D54C9F375D902C21375DDB2748D3FA1863C9581D30E17F94"));
|
||||
CHECK(CheckFileContentHash(resourceDir, "Logo.png", "49C486F44E43F023D54C9F375D902C21375DDB2748D3FA1863C9581D30E17F94"));
|
||||
}
|
||||
|
||||
WHEN("Testing uproot escape")
|
||||
{
|
||||
std::shared_ptr<Nz::VirtualDirectory> engineDir = std::make_shared<Nz::VirtualDirectory>(GetResourceDir() / "Engine");
|
||||
|
||||
CHECK_FALSE(engineDir->IsUprootAllowed());
|
||||
|
||||
// We can't escape the virtual directory
|
||||
CHECK_FALSE(engineDir->Exists("../Logo.png"));
|
||||
CHECK_FALSE(engineDir->Exists("../../Logo.png"));
|
||||
CHECK_FALSE(engineDir->Exists("../Engine/Audio/Audio/The_Brabanconne.ogg"));
|
||||
CHECK(CheckFileHash(engineDir, "Audio/../../Audio/The_Brabanconne.ogg", "E07706E0BEEC7770CDE36008826743AF9EEE5C80CA0BD83C37771CBC8B52E738"));
|
||||
CHECK(CheckFileHash(engineDir, "../Audio/./The_Brabanconne.ogg", "E07706E0BEEC7770CDE36008826743AF9EEE5C80CA0BD83C37771CBC8B52E738"));
|
||||
|
||||
engineDir->AllowUproot(true);
|
||||
CHECK(engineDir->IsUprootAllowed());
|
||||
|
||||
// Now we're able to access the resource folder beneath
|
||||
CHECK(CheckFileHash(engineDir, "../Logo.png", "5C4B9387327C039A6CE9ED51983D6C2ADA9F9DD01D024C2D5D588237ADFC7423"));
|
||||
CHECK(CheckFileHash(engineDir, "../Engine/Audio/The_Brabanconne.ogg", "E07706E0BEEC7770CDE36008826743AF9EEE5C80CA0BD83C37771CBC8B52E738"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue