fix VFS real path retrieval for files mounted from multiple directories (e.g. mods)
closes #564 GetRealPath was too simplistic and just asked the directory *most recently mounted* into the file's VFS directory for its path. the correct solution is to ask the file's loader for its path. the archiver IFileLoader new returns the archive's pathname as the real path. also simplified VfsFile's interface. This was SVN commit r8082.
This commit is contained in:
parent
0864ba4fb4
commit
c0c8132dd4
@ -265,6 +265,11 @@ public:
|
||||
return 'A';
|
||||
}
|
||||
|
||||
virtual fs::wpath Path() const
|
||||
{
|
||||
return m_file->Pathname();
|
||||
}
|
||||
|
||||
virtual LibError Load(const std::wstring& UNUSED(name), const shared_ptr<u8>& buf, size_t size) const
|
||||
{
|
||||
AdjustOffset();
|
||||
|
@ -29,6 +29,7 @@ struct IFileLoader
|
||||
|
||||
virtual size_t Precedence() const = 0;
|
||||
virtual wchar_t LocationCode() const = 0;
|
||||
virtual fs::wpath Path() const = 0;
|
||||
|
||||
virtual LibError Load(const std::wstring& name, const shared_ptr<u8>& buf, size_t size) const = 0;
|
||||
};
|
||||
|
@ -32,11 +32,6 @@ class RealDirectory : public IFileLoader
|
||||
public:
|
||||
RealDirectory(const fs::wpath& path, size_t priority, size_t flags);
|
||||
|
||||
const fs::wpath& Path() const
|
||||
{
|
||||
return m_path;
|
||||
}
|
||||
|
||||
size_t Priority() const
|
||||
{
|
||||
return m_priority;
|
||||
@ -50,6 +45,10 @@ public:
|
||||
// IFileLoader
|
||||
virtual size_t Precedence() const;
|
||||
virtual wchar_t LocationCode() const;
|
||||
virtual fs::wpath Path() const
|
||||
{
|
||||
return m_path;
|
||||
}
|
||||
virtual LibError Load(const std::wstring& name, const shared_ptr<u8>& buf, size_t size) const;
|
||||
|
||||
LibError Store(const std::wstring& name, const shared_ptr<u8>& fileContents, size_t size);
|
||||
|
@ -143,12 +143,12 @@ public:
|
||||
else if(size > m_cacheSize)
|
||||
{
|
||||
fileContents = io_Allocate(size);
|
||||
RETURN_ERR(file->Load(fileContents));
|
||||
RETURN_ERR(file->Loader()->Load(file->Name(), fileContents, file->Size()));
|
||||
}
|
||||
else
|
||||
{
|
||||
fileContents = m_fileCache.Reserve(size);
|
||||
RETURN_ERR(file->Load(fileContents));
|
||||
RETURN_ERR(file->Loader()->Load(file->Name(), fileContents, file->Size()));
|
||||
m_fileCache.Add(pathname, fileContents, size);
|
||||
}
|
||||
}
|
||||
@ -170,9 +170,9 @@ public:
|
||||
|
||||
virtual LibError GetRealPath(const VfsPath& pathname, fs::wpath& realPathname)
|
||||
{
|
||||
VfsDirectory* directory;
|
||||
CHECK_ERR(vfs_Lookup(pathname, &m_rootDirectory, directory, 0));
|
||||
realPathname = directory->AssociatedDirectory()->Path() / pathname.leaf();
|
||||
VfsDirectory* directory; VfsFile* file;
|
||||
CHECK_ERR(vfs_Lookup(pathname, &m_rootDirectory, directory, &file));
|
||||
realPathname = file->Loader()->Path() / pathname.leaf();
|
||||
return INFO::OK;
|
||||
}
|
||||
|
||||
|
@ -41,37 +41,6 @@ VfsFile::VfsFile(const std::wstring& name, size_t size, time_t mtime, size_t pri
|
||||
}
|
||||
|
||||
|
||||
bool VfsFile::IsSupersededBy(const VfsFile& file) const
|
||||
{
|
||||
// 1) priority (override mods)
|
||||
if(file.m_priority < m_priority) // lower priority
|
||||
return false;
|
||||
|
||||
// 2) timestamp
|
||||
{
|
||||
const double howMuchNewer = difftime(file.MTime(), MTime());
|
||||
const double threshold = 2.0; // [seconds]; resolution provided by FAT
|
||||
if(howMuchNewer > threshold) // newer timestamp
|
||||
return true;
|
||||
if(howMuchNewer < -threshold) // older timestamp
|
||||
return false;
|
||||
// else: "equal" (tolerating small differences due to FAT's low
|
||||
// mtime resolution)
|
||||
}
|
||||
|
||||
// 3) precedence (efficiency of file provider)
|
||||
if(file.m_loader->Precedence() < m_loader->Precedence()) // less efficient
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
LibError VfsFile::Load(const shared_ptr<u8>& buf) const
|
||||
{
|
||||
return m_loader->Load(Name(), buf, Size());
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
@ -81,6 +50,32 @@ VfsDirectory::VfsDirectory()
|
||||
}
|
||||
|
||||
|
||||
static bool ShouldReplaceWith(const VfsFile& previousFile, const VfsFile& newFile)
|
||||
{
|
||||
// 1) priority (override mods)
|
||||
if(newFile.Priority() < previousFile.Priority())
|
||||
return false;
|
||||
|
||||
// 2) timestamp
|
||||
{
|
||||
const double howMuchNewer = difftime(newFile.MTime(), previousFile.MTime());
|
||||
const double threshold = 2.0; // FAT timestamp resolution [seconds]
|
||||
if(howMuchNewer > threshold) // newer
|
||||
return true;
|
||||
if(howMuchNewer < -threshold) // older
|
||||
return false;
|
||||
// else: "equal" (tolerating small differences due to FAT's low
|
||||
// mtime resolution)
|
||||
}
|
||||
|
||||
// 3) precedence (efficiency of file provider)
|
||||
if(newFile.Loader()->Precedence() < previousFile.Loader()->Precedence())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
VfsFile* VfsDirectory::AddFile(const VfsFile& file)
|
||||
{
|
||||
std::pair<std::wstring, VfsFile> value = std::make_pair(file.Name(), file);
|
||||
@ -89,7 +84,7 @@ VfsFile* VfsDirectory::AddFile(const VfsFile& file)
|
||||
{
|
||||
VfsFile& previousFile = ret.first->second;
|
||||
const VfsFile& newFile = value.second;
|
||||
if(previousFile.IsSupersededBy(newFile))
|
||||
if(ShouldReplaceWith(previousFile, newFile))
|
||||
previousFile = newFile;
|
||||
}
|
||||
else
|
||||
@ -166,7 +161,7 @@ std::wstring FileDescription(const VfsFile& file)
|
||||
wcsftime(timestamp, ARRAY_SIZE(timestamp), L"%a %b %d %H:%M:%S %Y", localtime(&mtime));
|
||||
|
||||
wchar_t buf[200];
|
||||
swprintf_s(buf, ARRAY_SIZE(buf), L"(%c; %6lu; %ls) %ls", file.LocationCode(), (unsigned long)file.Size(), timestamp, file.Name().c_str());
|
||||
swprintf_s(buf, ARRAY_SIZE(buf), L"(%c; %6lu; %ls) %ls", file.Loader()->LocationCode(), (unsigned long)file.Size(), timestamp, file.Name().c_str());
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
@ -43,11 +43,6 @@ public:
|
||||
return m_name;
|
||||
}
|
||||
|
||||
wchar_t LocationCode() const
|
||||
{
|
||||
return m_loader->LocationCode();
|
||||
}
|
||||
|
||||
size_t Size() const
|
||||
{
|
||||
return m_size;
|
||||
@ -58,9 +53,15 @@ public:
|
||||
return m_mtime;
|
||||
}
|
||||
|
||||
bool IsSupersededBy(const VfsFile& file) const;
|
||||
size_t Priority() const
|
||||
{
|
||||
return m_priority;
|
||||
}
|
||||
|
||||
LibError Load(const shared_ptr<u8>& buf) const;
|
||||
const PIFileLoader& Loader() const
|
||||
{
|
||||
return m_loader;
|
||||
}
|
||||
|
||||
private:
|
||||
std::wstring m_name;
|
||||
|
Loading…
Reference in New Issue
Block a user