Core/VirtualDirectory: Add Uproot property
This commit is contained in:
parent
b6ab3ba1b3
commit
dd4be081aa
|
|
@ -39,13 +39,17 @@ namespace Nz
|
||||||
VirtualDirectory(VirtualDirectory&&) = delete;
|
VirtualDirectory(VirtualDirectory&&) = delete;
|
||||||
~VirtualDirectory() = default;
|
~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> void Foreach(F&& callback, bool includeDots = false);
|
||||||
|
|
||||||
template<typename F> bool GetEntry(std::string_view path, F&& callback);
|
template<typename F> bool GetEntry(std::string_view path, F&& callback);
|
||||||
template<typename F> bool GetFileContent(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 DirectoryEntry& StoreDirectory(std::string_view path, VirtualDirectoryPtr directory);
|
||||||
inline PhysicalDirectoryEntry& StoreDirectory(std::string_view path, std::filesystem::path directoryPath);
|
inline PhysicalDirectoryEntry& StoreDirectory(std::string_view path, std::filesystem::path directoryPath);
|
||||||
inline FileContentEntry& StoreFile(std::string_view path, std::vector<UInt8> file);
|
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::optional<std::filesystem::path> m_physicalPath;
|
||||||
std::vector<ContentEntry> m_content;
|
std::vector<ContentEntry> m_content;
|
||||||
std::weak_ptr<VirtualDirectory> m_parent;
|
std::weak_ptr<VirtualDirectory> m_parent;
|
||||||
|
bool m_isUprootAllowed;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,16 +12,23 @@
|
||||||
namespace Nz
|
namespace Nz
|
||||||
{
|
{
|
||||||
inline VirtualDirectory::VirtualDirectory(std::weak_ptr<VirtualDirectory> parentDirectory) :
|
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) :
|
inline VirtualDirectory::VirtualDirectory(std::filesystem::path physicalPath, std::weak_ptr<VirtualDirectory> parentDirectory) :
|
||||||
m_physicalPath(std::move(physicalPath)),
|
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)
|
inline bool VirtualDirectory::Exists(std::string_view path)
|
||||||
{
|
{
|
||||||
return GetEntry(path, [](const auto&) {});
|
return GetEntry(path, [](const auto&) {});
|
||||||
|
|
@ -94,7 +101,7 @@ namespace Nz
|
||||||
if (physicalPathBase)
|
if (physicalPathBase)
|
||||||
{
|
{
|
||||||
// Special case when traversing directory
|
// Special case when traversing directory
|
||||||
if (dirName == "..")
|
if (dirName == ".." && !m_isUprootAllowed)
|
||||||
{
|
{
|
||||||
// Don't allow to escape virtual directory
|
// Don't allow to escape virtual directory
|
||||||
if (!physicalDirectoryParts.empty())
|
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&
|
inline auto VirtualDirectory::StoreDirectory(std::string_view path, VirtualDirectoryPtr directory) -> DirectoryEntry&
|
||||||
{
|
{
|
||||||
assert(!path.empty());
|
assert(!path.empty());
|
||||||
|
|
@ -260,18 +272,22 @@ namespace Nz
|
||||||
Entry entry{ DirectoryEntry{ shared_from_this() } };
|
Entry entry{ DirectoryEntry{ shared_from_this() } };
|
||||||
return CallbackReturn(callback, entry);
|
return CallbackReturn(callback, entry);
|
||||||
}
|
}
|
||||||
else if (name == "..")
|
|
||||||
{
|
|
||||||
Entry entry;
|
|
||||||
if (VirtualDirectoryPtr parent = m_parent.lock())
|
|
||||||
entry = DirectoryEntry{ std::move(parent) };
|
|
||||||
else
|
|
||||||
entry = DirectoryEntry{ shared_from_this() };
|
|
||||||
|
|
||||||
|
if (name == "..")
|
||||||
|
{
|
||||||
|
VirtualDirectoryPtr parentEntry;
|
||||||
|
if (VirtualDirectoryPtr parent = m_parent.lock())
|
||||||
|
parentEntry = std::move(parent);
|
||||||
|
else if (!m_isUprootAllowed)
|
||||||
|
parentEntry = shared_from_this();
|
||||||
|
|
||||||
|
if (parentEntry)
|
||||||
|
{
|
||||||
|
Entry entry = DirectoryEntry{ std::move(parentEntry) };
|
||||||
return CallbackReturn(callback, entry);
|
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;
|
return entry.name < name;
|
||||||
|
|
@ -300,7 +316,6 @@ namespace Nz
|
||||||
|
|
||||||
return CallbackReturn(callback, it->entry);
|
return CallbackReturn(callback, it->entry);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
inline bool VirtualDirectory::CreateOrRetrieveDirectory(std::string_view path, std::shared_ptr<VirtualDirectory>& directory, std::string_view& entryName)
|
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")
|
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")
|
WHEN("Iterating, it's not empty")
|
||||||
{
|
{
|
||||||
bool empty = true;
|
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 == ".");
|
||||||
CHECK_FALSE(name == "..");
|
CHECK_FALSE(name == "..");
|
||||||
|
|
@ -205,9 +205,9 @@ TEST_CASE("VirtualDirectory", "[Core][VirtualDirectory]")
|
||||||
REQUIRE_FALSE(empty);
|
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));
|
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;
|
Nz::SHA256Hash hash;
|
||||||
WHEN("We compute " << hash.GetHashName() << " of " << filepath << " file")
|
WHEN("We compute " << hash.GetHashName() << " of " << filepath << " file")
|
||||||
|
|
@ -240,42 +240,63 @@ TEST_CASE("VirtualDirectory", "[Core][VirtualDirectory]")
|
||||||
|
|
||||||
WHEN("Accessing files")
|
WHEN("Accessing files")
|
||||||
{
|
{
|
||||||
CHECK(CheckFileHash("Logo.png", "5C4B9387327C039A6CE9ED51983D6C2ADA9F9DD01D024C2D5D588237ADFC7423"));
|
CHECK(CheckFileHash(resourceDir, "Logo.png", "5C4B9387327C039A6CE9ED51983D6C2ADA9F9DD01D024C2D5D588237ADFC7423"));
|
||||||
CHECK(CheckFileHash("./Logo.png", "5C4B9387327C039A6CE9ED51983D6C2ADA9F9DD01D024C2D5D588237ADFC7423"));
|
CHECK(CheckFileHash(resourceDir, "./Logo.png", "5C4B9387327C039A6CE9ED51983D6C2ADA9F9DD01D024C2D5D588237ADFC7423"));
|
||||||
CHECK(CheckFileHash("Engine/Audio/The_Brabanconne.ogg", "E07706E0BEEC7770CDE36008826743AF9EEE5C80CA0BD83C37771CBC8B52E738"));
|
CHECK(CheckFileHash(resourceDir, "Engine/Audio/The_Brabanconne.ogg", "E07706E0BEEC7770CDE36008826743AF9EEE5C80CA0BD83C37771CBC8B52E738"));
|
||||||
CHECK(CheckFileHash("Engine/Audio/./The_Brabanconne.ogg", "E07706E0BEEC7770CDE36008826743AF9EEE5C80CA0BD83C37771CBC8B52E738"));
|
CHECK(CheckFileHash(resourceDir, "Engine/Audio/./The_Brabanconne.ogg", "E07706E0BEEC7770CDE36008826743AF9EEE5C80CA0BD83C37771CBC8B52E738"));
|
||||||
CHECK_FALSE(CheckFileHash("The_Brabanconne.ogg", "E07706E0BEEC7770CDE36008826743AF9EEE5C80CA0BD83C37771CBC8B52E738"));
|
CHECK_FALSE(CheckFileHash(resourceDir, "The_Brabanconne.ogg", "E07706E0BEEC7770CDE36008826743AF9EEE5C80CA0BD83C37771CBC8B52E738"));
|
||||||
CHECK_FALSE(CheckFileHash("Engine/The_Brabanconne.ogg", "E07706E0BEEC7770CDE36008826743AF9EEE5C80CA0BD83C37771CBC8B52E738"));
|
CHECK_FALSE(CheckFileHash(resourceDir, "Engine/The_Brabanconne.ogg", "E07706E0BEEC7770CDE36008826743AF9EEE5C80CA0BD83C37771CBC8B52E738"));
|
||||||
CHECK_FALSE(CheckFileHash("Engine/Audio/../The_Brabanconne.ogg", "E07706E0BEEC7770CDE36008826743AF9EEE5C80CA0BD83C37771CBC8B52E738"));
|
CHECK_FALSE(CheckFileHash(resourceDir, "Engine/Audio/../The_Brabanconne.ogg", "E07706E0BEEC7770CDE36008826743AF9EEE5C80CA0BD83C37771CBC8B52E738"));
|
||||||
|
|
||||||
// We can't escape the virtual directory
|
// We can't escape the virtual directory
|
||||||
CHECK(CheckFileHash("../Logo.png", "5C4B9387327C039A6CE9ED51983D6C2ADA9F9DD01D024C2D5D588237ADFC7423"));
|
CHECK(CheckFileHash(resourceDir, "../Logo.png", "5C4B9387327C039A6CE9ED51983D6C2ADA9F9DD01D024C2D5D588237ADFC7423"));
|
||||||
CHECK(CheckFileHash("../../Logo.png", "5C4B9387327C039A6CE9ED51983D6C2ADA9F9DD01D024C2D5D588237ADFC7423"));
|
CHECK(CheckFileHash(resourceDir, "../../Logo.png", "5C4B9387327C039A6CE9ED51983D6C2ADA9F9DD01D024C2D5D588237ADFC7423"));
|
||||||
CHECK(CheckFileHash("Engine/../Engine/Audio/The_Brabanconne.ogg", "E07706E0BEEC7770CDE36008826743AF9EEE5C80CA0BD83C37771CBC8B52E738"));
|
CHECK(CheckFileHash(resourceDir, "Engine/../Engine/Audio/The_Brabanconne.ogg", "E07706E0BEEC7770CDE36008826743AF9EEE5C80CA0BD83C37771CBC8B52E738"));
|
||||||
CHECK(CheckFileHash("../Engine/./Audio/The_Brabanconne.ogg", "E07706E0BEEC7770CDE36008826743AF9EEE5C80CA0BD83C37771CBC8B52E738"));
|
CHECK(CheckFileHash(resourceDir, "../Engine/./Audio/The_Brabanconne.ogg", "E07706E0BEEC7770CDE36008826743AF9EEE5C80CA0BD83C37771CBC8B52E738"));
|
||||||
CHECK_FALSE(CheckFileHash("../Engine/Engine/Audio/The_Brabanconne.ogg", "E07706E0BEEC7770CDE36008826743AF9EEE5C80CA0BD83C37771CBC8B52E738"));
|
CHECK_FALSE(CheckFileHash(resourceDir, "../Engine/Engine/Audio/The_Brabanconne.ogg", "E07706E0BEEC7770CDE36008826743AF9EEE5C80CA0BD83C37771CBC8B52E738"));
|
||||||
|
|
||||||
auto CheckOurselves = [&](const auto& entry)
|
auto CheckOurselves = [&](const auto& entry)
|
||||||
{
|
{
|
||||||
REQUIRE(std::holds_alternative<Nz::VirtualDirectory::DirectoryEntry>(entry));
|
REQUIRE(std::holds_alternative<Nz::VirtualDirectory::DirectoryEntry>(entry));
|
||||||
const auto& dirEntry = std::get<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(resourceDir->GetEntry("..", CheckOurselves));
|
||||||
CHECK(virtualDir->GetEntry("../..", CheckOurselves));
|
CHECK(resourceDir->GetEntry("../..", CheckOurselves));
|
||||||
CHECK(virtualDir->GetEntry("./..", CheckOurselves));
|
CHECK(resourceDir->GetEntry("./..", CheckOurselves));
|
||||||
CHECK(virtualDir->GetEntry("./..", CheckOurselves));
|
CHECK(resourceDir->GetEntry("./..", CheckOurselves));
|
||||||
CHECK(virtualDir->GetEntry("Engine/../..", CheckOurselves));
|
CHECK(resourceDir->GetEntry("Engine/../..", CheckOurselves));
|
||||||
CHECK(virtualDir->GetEntry("Engine/../Engine/Audio/../../..", CheckOurselves));
|
CHECK(resourceDir->GetEntry("Engine/../Engine/Audio/../../..", CheckOurselves));
|
||||||
}
|
}
|
||||||
AND_THEN("Overriding the physical file with another one")
|
AND_THEN("Overriding the physical file with another one")
|
||||||
{
|
{
|
||||||
virtualDir->StoreFile("Logo.png", GetResourceDir() / "ambience.ogg");
|
resourceDir->StoreFile("Logo.png", GetResourceDir() / "ambience.ogg");
|
||||||
CHECK(CheckFileHash("ambience.ogg", "49C486F44E43F023D54C9F375D902C21375DDB2748D3FA1863C9581D30E17F94"));
|
CHECK(CheckFileHash(resourceDir, "ambience.ogg", "49C486F44E43F023D54C9F375D902C21375DDB2748D3FA1863C9581D30E17F94"));
|
||||||
CHECK(CheckFileHash("Logo.png", "49C486F44E43F023D54C9F375D902C21375DDB2748D3FA1863C9581D30E17F94"));
|
CHECK(CheckFileHash(resourceDir, "Logo.png", "49C486F44E43F023D54C9F375D902C21375DDB2748D3FA1863C9581D30E17F94"));
|
||||||
CHECK(CheckFileContentHash("ambience.ogg", "49C486F44E43F023D54C9F375D902C21375DDB2748D3FA1863C9581D30E17F94"));
|
CHECK(CheckFileContentHash(resourceDir, "ambience.ogg", "49C486F44E43F023D54C9F375D902C21375DDB2748D3FA1863C9581D30E17F94"));
|
||||||
CHECK(CheckFileContentHash("Logo.png", "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