mirror of https://github.com/RPCS3/rpcs3.git
Partial commit: FS
This commit is contained in:
parent
b85a68e8a1
commit
984aa44220
|
@ -1,568 +0,0 @@
|
||||||
#include "stdafx.h"
|
|
||||||
#include "VFS.h"
|
|
||||||
#include "vfsDir.h"
|
|
||||||
#include "vfsFile.h"
|
|
||||||
#include "vfsDirBase.h"
|
|
||||||
#include "Emu/HDD/HDD.h"
|
|
||||||
#include "vfsDeviceLocalFile.h"
|
|
||||||
#include "Emu/System.h"
|
|
||||||
#include "Emu/state.h"
|
|
||||||
|
|
||||||
std::vector<std::string> simplify_path_blocks(const std::string& path)
|
|
||||||
{
|
|
||||||
// fmt::tolower() removed
|
|
||||||
std::vector<std::string> path_blocks = std::move(fmt::split(path, { "/", "\\" }));
|
|
||||||
|
|
||||||
for (s32 i = 0; i < path_blocks.size(); ++i)
|
|
||||||
{
|
|
||||||
if (path_blocks[i] == "." || (i > 0 && path_blocks[i].empty()))
|
|
||||||
{
|
|
||||||
path_blocks.erase(path_blocks.begin() + i);
|
|
||||||
i--;
|
|
||||||
}
|
|
||||||
else if (i > 0 && path_blocks[i] == "..")
|
|
||||||
{
|
|
||||||
path_blocks.erase(path_blocks.begin() + (i - 1), path_blocks.begin() + (i + 1));
|
|
||||||
i--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return path_blocks;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string simplify_path(const std::string& path, bool is_dir, bool is_ps3)
|
|
||||||
{
|
|
||||||
std::vector<std::string> path_blocks = simplify_path_blocks(path);
|
|
||||||
|
|
||||||
if (path_blocks.empty())
|
|
||||||
return "";
|
|
||||||
|
|
||||||
std::string result = fmt::merge(path_blocks, "/");
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
if (is_ps3)
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
result = "/" + result;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_dir) result = result + "/";
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
VFS::~VFS()
|
|
||||||
{
|
|
||||||
UnMountAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
void VFS::Mount(const std::string& ps3_path, const std::string& local_path, vfsDevice* device)
|
|
||||||
{
|
|
||||||
std::string simpl_ps3_path = simplify_path(ps3_path, true, true);
|
|
||||||
|
|
||||||
UnMount(simpl_ps3_path);
|
|
||||||
|
|
||||||
device->SetPath(simpl_ps3_path, simplify_path(local_path, true, false));
|
|
||||||
m_devices.push_back(device);
|
|
||||||
|
|
||||||
if (m_devices.size() > 1)
|
|
||||||
{
|
|
||||||
std::sort(m_devices.begin(), m_devices.end(), [](vfsDevice *a, vfsDevice *b) { return b->GetPs3Path().length() < a->GetPs3Path().length(); });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void VFS::Link(const std::string& mount_point, const std::string& ps3_path)
|
|
||||||
{
|
|
||||||
links[simplify_path_blocks(mount_point)] = simplify_path_blocks(ps3_path);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string VFS::GetLinked(const std::string& ps3_path) const
|
|
||||||
{
|
|
||||||
// fmt::tolower removed
|
|
||||||
auto path_blocks = fmt::split(ps3_path, { "/", "\\" });
|
|
||||||
|
|
||||||
for (auto link : links)
|
|
||||||
{
|
|
||||||
if (path_blocks.size() < link.first.size())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
bool is_ok = true;
|
|
||||||
|
|
||||||
for (size_t i = 0; i < link.first.size(); ++i)
|
|
||||||
{
|
|
||||||
if (link.first[i] != path_blocks[i])
|
|
||||||
{
|
|
||||||
is_ok = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_ok)
|
|
||||||
return fmt::merge({ link.second, std::vector<std::string>(path_blocks.begin() + link.first.size(), path_blocks.end()) }, "/");
|
|
||||||
}
|
|
||||||
|
|
||||||
return ps3_path;
|
|
||||||
}
|
|
||||||
|
|
||||||
void VFS::UnMount(const std::string& ps3_path)
|
|
||||||
{
|
|
||||||
std::string simpl_ps3_path = simplify_path(ps3_path, true, true);
|
|
||||||
|
|
||||||
for (u32 i = 0; i < m_devices.size(); ++i)
|
|
||||||
{
|
|
||||||
if (!strcmp(m_devices[i]->GetPs3Path().c_str(), simpl_ps3_path.c_str()))
|
|
||||||
{
|
|
||||||
delete m_devices[i];
|
|
||||||
|
|
||||||
m_devices.erase(m_devices.begin() +i);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void VFS::UnMountAll()
|
|
||||||
{
|
|
||||||
for(u32 i=0; i<m_devices.size(); ++i)
|
|
||||||
{
|
|
||||||
delete m_devices[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
m_devices.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
vfsFileBase* VFS::OpenFile(const std::string& ps3_path, u32 mode) const
|
|
||||||
{
|
|
||||||
std::string path;
|
|
||||||
|
|
||||||
if (vfsDevice* dev = GetDevice(ps3_path, path))
|
|
||||||
{
|
|
||||||
if (vfsFileBase* res = dev->GetNewFileStream())
|
|
||||||
{
|
|
||||||
res->Open(path, mode);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
vfsDirBase* VFS::OpenDir(const std::string& ps3_path) const
|
|
||||||
{
|
|
||||||
std::string path;
|
|
||||||
|
|
||||||
if (vfsDevice* dev = GetDevice(ps3_path, path))
|
|
||||||
{
|
|
||||||
if (vfsDirBase* res = dev->GetNewDirStream())
|
|
||||||
{
|
|
||||||
res->Open(path);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool VFS::CreateDir(const std::string& ps3_path) const
|
|
||||||
{
|
|
||||||
std::string path;
|
|
||||||
|
|
||||||
if (vfsDevice* dev = GetDevice(ps3_path, path))
|
|
||||||
{
|
|
||||||
// return dev->create_dir(path);
|
|
||||||
return fs::create_dir(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool VFS::CreatePath(const std::string& ps3_path) const
|
|
||||||
{
|
|
||||||
std::string path;
|
|
||||||
|
|
||||||
if (vfsDevice* dev = GetDevice(ps3_path, path))
|
|
||||||
{
|
|
||||||
// return dev->create_path(path);
|
|
||||||
return fs::create_path(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool VFS::RemoveFile(const std::string& ps3_path) const
|
|
||||||
{
|
|
||||||
std::string path;
|
|
||||||
|
|
||||||
if (vfsDevice* dev = GetDevice(ps3_path, path))
|
|
||||||
{
|
|
||||||
// return dev->remove_file(path);
|
|
||||||
return fs::remove_file(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool VFS::RemoveDir(const std::string& ps3_path) const
|
|
||||||
{
|
|
||||||
std::string path;
|
|
||||||
|
|
||||||
if (vfsDevice* dev = GetDevice(ps3_path, path))
|
|
||||||
{
|
|
||||||
// return dev->remove_dir(path);
|
|
||||||
return fs::remove_dir(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void VFS::DeleteAll(const std::string& ps3_path) const
|
|
||||||
{
|
|
||||||
// Delete directory and all its contents recursively
|
|
||||||
for (const auto entry : vfsDir(ps3_path))
|
|
||||||
{
|
|
||||||
if (entry->name == "." || entry->name == "..")
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (entry->flags & DirEntry_TypeFile)
|
|
||||||
{
|
|
||||||
RemoveFile(ps3_path + "/" + entry->name);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (entry->flags & DirEntry_TypeDir)
|
|
||||||
{
|
|
||||||
DeleteAll(ps3_path + "/" + entry->name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
RemoveDir(ps3_path);
|
|
||||||
}
|
|
||||||
|
|
||||||
u64 VFS::GetDirSize(const std::string& ps3_path) const
|
|
||||||
{
|
|
||||||
u64 result = 0;
|
|
||||||
|
|
||||||
for (const auto entry : vfsDir(ps3_path))
|
|
||||||
{
|
|
||||||
if (entry->name == "." || entry->name == "..")
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (entry->flags & DirEntry_TypeFile)
|
|
||||||
{
|
|
||||||
result += entry->size;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (entry->flags & DirEntry_TypeDir)
|
|
||||||
{
|
|
||||||
result += GetDirSize(ps3_path + "/" + entry->name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool VFS::ExistsFile(const std::string& ps3_path) const
|
|
||||||
{
|
|
||||||
std::string path;
|
|
||||||
|
|
||||||
if (vfsDevice* dev = GetDevice(ps3_path, path))
|
|
||||||
{
|
|
||||||
// return dev->is_file(path);
|
|
||||||
return fs::is_file(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool VFS::ExistsDir(const std::string& ps3_path) const
|
|
||||||
{
|
|
||||||
std::string path;
|
|
||||||
|
|
||||||
if (vfsDevice* dev = GetDevice(ps3_path, path))
|
|
||||||
{
|
|
||||||
// return dev->is_dir(path);
|
|
||||||
return fs::is_dir(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool VFS::Exists(const std::string& ps3_path) const
|
|
||||||
{
|
|
||||||
std::string path;
|
|
||||||
|
|
||||||
if (vfsDevice* dev = GetDevice(ps3_path, path))
|
|
||||||
{
|
|
||||||
// return dev->exists(path);
|
|
||||||
return fs::exists(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool VFS::Rename(const std::string& ps3_path_from, const std::string& ps3_path_to) const
|
|
||||||
{
|
|
||||||
std::string path_from, path_to;
|
|
||||||
|
|
||||||
if (vfsDevice* dev = GetDevice(ps3_path_from, path_from))
|
|
||||||
{
|
|
||||||
if (vfsDevice* dev_ = GetDevice(ps3_path_to, path_to))
|
|
||||||
{
|
|
||||||
// return dev->rename(dev_, path_from, path_to);
|
|
||||||
return fs::rename(path_from, path_to);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool VFS::CopyFile(const std::string& ps3_path_from, const std::string& ps3_path_to, bool overwrite) const
|
|
||||||
{
|
|
||||||
std::string path_from, path_to;
|
|
||||||
|
|
||||||
if (vfsDevice* dev = GetDevice(ps3_path_from, path_from))
|
|
||||||
{
|
|
||||||
if (vfsDevice* dev_ = GetDevice(ps3_path_to, path_to))
|
|
||||||
{
|
|
||||||
// return dev->copy_file(dev_, path_from, path_to, overwrite);
|
|
||||||
return fs::copy_file(path_from, path_to, overwrite);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool VFS::TruncateFile(const std::string& ps3_path, u64 length) const
|
|
||||||
{
|
|
||||||
std::string path;
|
|
||||||
|
|
||||||
if (vfsDevice* dev = GetDevice(ps3_path, path))
|
|
||||||
{
|
|
||||||
// return dev->truncate_file(path, length);
|
|
||||||
return fs::truncate_file(path, length);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
vfsDevice* VFS::GetDevice(const std::string& ps3_path, std::string& path) const
|
|
||||||
{
|
|
||||||
auto try_get_device = [this, &path](const std::string& ps3_path) -> vfsDevice*
|
|
||||||
{
|
|
||||||
std::vector<std::string> ps3_path_blocks = simplify_path_blocks(ps3_path);
|
|
||||||
size_t max_eq = 0;
|
|
||||||
int max_i = -1;
|
|
||||||
|
|
||||||
for (u32 i = 0; i < m_devices.size(); ++i)
|
|
||||||
{
|
|
||||||
std::vector<std::string> dev_ps3_path_blocks = simplify_path_blocks(m_devices[i]->GetPs3Path());
|
|
||||||
|
|
||||||
if (ps3_path_blocks.size() < dev_ps3_path_blocks.size())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
size_t eq = 0;
|
|
||||||
for (; eq < dev_ps3_path_blocks.size(); ++eq)
|
|
||||||
{
|
|
||||||
if (strcmp(ps3_path_blocks[eq].c_str(), dev_ps3_path_blocks[eq].c_str()))
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (eq > max_eq)
|
|
||||||
{
|
|
||||||
max_eq = eq;
|
|
||||||
max_i = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (max_i < 0)
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
path = m_devices[max_i]->GetLocalPath();
|
|
||||||
|
|
||||||
for (size_t i = max_eq; i < ps3_path_blocks.size(); i++)
|
|
||||||
{
|
|
||||||
path += "/" + ps3_path_blocks[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
path = simplify_path(path, false, false);
|
|
||||||
|
|
||||||
return m_devices[max_i];
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!ps3_path.size() || ps3_path[0] != '/')
|
|
||||||
{
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
return try_get_device(GetLinked(ps3_path));
|
|
||||||
|
|
||||||
// What is it? cwd is real path, ps3_path is ps3 path, but GetLinked accepts ps3 path
|
|
||||||
//if (auto res = try_get_device(GetLinked(cwd + ps3_path)))
|
|
||||||
// return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
vfsDevice* VFS::GetDeviceLocal(const std::string& local_path, std::string& path) const
|
|
||||||
{
|
|
||||||
int max_eq = -1;
|
|
||||||
int max_i = -1;
|
|
||||||
|
|
||||||
std::vector<std::string> local_path_blocks = simplify_path_blocks(local_path);
|
|
||||||
|
|
||||||
for (u32 i = 0; i < m_devices.size(); ++i)
|
|
||||||
{
|
|
||||||
std::vector<std::string> dev_local_path_blocks = simplify_path_blocks(m_devices[i]->GetLocalPath());
|
|
||||||
|
|
||||||
if (local_path_blocks.size() < dev_local_path_blocks.size())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
int dev_blocks = dev_local_path_blocks.size();
|
|
||||||
|
|
||||||
bool prefix_equal = std::equal(
|
|
||||||
std::begin(dev_local_path_blocks),
|
|
||||||
std::end(dev_local_path_blocks),
|
|
||||||
std::begin(local_path_blocks),
|
|
||||||
[](const std::string& a, const std::string& b){ return strcmp(a.c_str(), b.c_str()) == 0; }
|
|
||||||
);
|
|
||||||
|
|
||||||
if (prefix_equal && dev_blocks > max_eq)
|
|
||||||
{
|
|
||||||
max_eq = dev_blocks;
|
|
||||||
max_i = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (max_i < 0)
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
path = m_devices[max_i]->GetPs3Path();
|
|
||||||
|
|
||||||
for (size_t i = max_eq; i < local_path_blocks.size(); i++)
|
|
||||||
{
|
|
||||||
path += "/" + local_path_blocks[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
path = simplify_path(path, false, true);
|
|
||||||
|
|
||||||
return m_devices[max_i];
|
|
||||||
}
|
|
||||||
|
|
||||||
void VFS::Init(const std::string& path)
|
|
||||||
{
|
|
||||||
cwd = simplify_path(path, true, false);
|
|
||||||
|
|
||||||
UnMountAll();
|
|
||||||
|
|
||||||
std::vector<VFSManagerEntry> entries;
|
|
||||||
SaveLoadDevices(entries, true);
|
|
||||||
|
|
||||||
for(const VFSManagerEntry& entry : entries)
|
|
||||||
{
|
|
||||||
vfsDevice* dev;
|
|
||||||
|
|
||||||
switch(entry.device)
|
|
||||||
{
|
|
||||||
case vfsDevice_LocalFile:
|
|
||||||
dev = new vfsDeviceLocalFile();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case vfsDevice_HDD:
|
|
||||||
dev = new vfsDeviceHDD(entry.device_path);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string mpath = entry.path;
|
|
||||||
// If no value assigned to SysEmulationDirPath in INI, use the path that with executable.
|
|
||||||
if (rpcs3::config.system.emulation_dir_path_enable.value())
|
|
||||||
{
|
|
||||||
fmt::Replace(mpath, "$(EmulatorDir)", rpcs3::config.system.emulation_dir_path.value());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
fmt::Replace(mpath, "$(EmulatorDir)", fs::get_executable_dir());
|
|
||||||
}
|
|
||||||
fmt::Replace(mpath, "$(GameDir)", cwd);
|
|
||||||
Mount(entry.mount, mpath, dev);
|
|
||||||
}
|
|
||||||
|
|
||||||
Link("/app_home/", "/host_root/" + cwd);
|
|
||||||
}
|
|
||||||
|
|
||||||
void VFS::SaveLoadDevices(std::vector<VFSManagerEntry>& res, bool is_load)
|
|
||||||
{
|
|
||||||
int count = 0;
|
|
||||||
if (is_load)
|
|
||||||
{
|
|
||||||
count = rpcs3::config.vfs.count.value();
|
|
||||||
|
|
||||||
if (!count)
|
|
||||||
{
|
|
||||||
res.emplace_back(vfsDevice_LocalFile, "$(EmulatorDir)/dev_hdd0/", "/dev_hdd0/");
|
|
||||||
res.emplace_back(vfsDevice_LocalFile, "$(EmulatorDir)/dev_hdd1/", "/dev_hdd1/");
|
|
||||||
res.emplace_back(vfsDevice_LocalFile, "$(EmulatorDir)/dev_flash/", "/dev_flash/");
|
|
||||||
res.emplace_back(vfsDevice_LocalFile, "$(EmulatorDir)/dev_usb000/", "/dev_usb000/");
|
|
||||||
res.emplace_back(vfsDevice_LocalFile, "$(EmulatorDir)/dev_usb000/", "/dev_usb/");
|
|
||||||
res.emplace_back(vfsDevice_LocalFile, "", "/host_root/");
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
res.resize(count);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
count = (int)res.size();
|
|
||||||
rpcs3::config.vfs.count = count;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Custom EmulationDir
|
|
||||||
if (rpcs3::config.system.emulation_dir_path_enable.value())
|
|
||||||
{
|
|
||||||
std::string dir = rpcs3::config.system.emulation_dir_path.value();
|
|
||||||
|
|
||||||
if (dir.empty())
|
|
||||||
{
|
|
||||||
rpcs3::config.system.emulation_dir_path = fs::get_executable_dir();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!fs::is_dir(dir))
|
|
||||||
{
|
|
||||||
LOG_ERROR(GENERAL, "Custom EmulationDir: directory '%s' not found", dir);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
LOG_NOTICE(GENERAL, "Custom EmulationDir: $(EmulatorDir) bound to '%s'", dir);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for(int i=0; i<count; ++i)
|
|
||||||
{
|
|
||||||
rpcs3::config.vfs.add_entry(fmt::format("path[%d]", i), std::string{});
|
|
||||||
rpcs3::config.vfs.add_entry(fmt::format("device_path[%d]", i), std::string{});
|
|
||||||
rpcs3::config.vfs.add_entry(fmt::format("mount[%d]", i), std::string{});
|
|
||||||
rpcs3::config.vfs.add_entry(fmt::format("device[%d]", i), 0);
|
|
||||||
|
|
||||||
if (is_load)
|
|
||||||
{
|
|
||||||
res[i] = VFSManagerEntry();
|
|
||||||
res[i].path = rpcs3::config.vfs.get_entry_value<std::string>(fmt::format("path[%d]", i), std::string{});
|
|
||||||
res[i].device_path = rpcs3::config.vfs.get_entry_value<std::string>(fmt::format("device_path[%d]", i), std::string{});
|
|
||||||
res[i].mount = rpcs3::config.vfs.get_entry_value<std::string>(fmt::format("mount[%d]", i), std::string{});
|
|
||||||
res[i].device = (vfsDeviceType)rpcs3::config.vfs.get_entry_value<int>(fmt::format("device[%d]", i), 0);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
rpcs3::config.vfs.set_entry_value(fmt::format("path[%d]", i), res[i].path);
|
|
||||||
rpcs3::config.vfs.set_entry_value(fmt::format("device_path[%d]", i), res[i].device_path);
|
|
||||||
rpcs3::config.vfs.set_entry_value(fmt::format("mount[%d]", i), res[i].mount);
|
|
||||||
rpcs3::config.vfs.set_entry_value(fmt::format("device[%d]", i), (int)res[i].device);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,98 +0,0 @@
|
||||||
#pragma once
|
|
||||||
#include <map>
|
|
||||||
|
|
||||||
class vfsDevice;
|
|
||||||
struct vfsFileBase;
|
|
||||||
class vfsDirBase;
|
|
||||||
|
|
||||||
enum vfsDeviceType
|
|
||||||
{
|
|
||||||
vfsDevice_LocalFile,
|
|
||||||
vfsDevice_HDD,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const char* vfsDeviceTypeNames[] =
|
|
||||||
{
|
|
||||||
"Local",
|
|
||||||
"HDD",
|
|
||||||
};
|
|
||||||
|
|
||||||
struct VFSManagerEntry
|
|
||||||
{
|
|
||||||
vfsDeviceType device;
|
|
||||||
std::string device_path;
|
|
||||||
std::string path;
|
|
||||||
std::string mount;
|
|
||||||
|
|
||||||
VFSManagerEntry()
|
|
||||||
: device(vfsDevice_LocalFile)
|
|
||||||
, device_path("")
|
|
||||||
, path("")
|
|
||||||
, mount("")
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
VFSManagerEntry(const vfsDeviceType& device, const std::string& path, const std::string& mount)
|
|
||||||
: device(device)
|
|
||||||
, device_path("")
|
|
||||||
, path(path)
|
|
||||||
, mount(mount)
|
|
||||||
|
|
||||||
{
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
std::vector<std::string> simplify_path_blocks(const std::string& path);
|
|
||||||
std::string simplify_path(const std::string& path, bool is_dir, bool is_ps3);
|
|
||||||
|
|
||||||
struct VFS
|
|
||||||
{
|
|
||||||
~VFS();
|
|
||||||
|
|
||||||
std::string cwd;
|
|
||||||
|
|
||||||
//TODO: find out where these are supposed to be deleted or just make it shared_ptr
|
|
||||||
//and also make GetDevice and GetDeviceLocal return shared_ptr then.
|
|
||||||
// A vfsDevice will be deleted when they're unmounted or the VFS struct is destroyed.
|
|
||||||
// This will cause problems if other code stores the pointer returned by GetDevice/GetDeviceLocal
|
|
||||||
// and tries to use it after the device is unmounted.
|
|
||||||
std::vector<vfsDevice *> m_devices;
|
|
||||||
|
|
||||||
struct links_sorter
|
|
||||||
{
|
|
||||||
bool operator()(const std::vector<std::string>& a, const std::vector<std::string>& b) const
|
|
||||||
{
|
|
||||||
return b.size() < a.size();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
std::map<std::vector<std::string>, std::vector<std::string>, links_sorter> links;
|
|
||||||
|
|
||||||
void Mount(const std::string& ps3_path, const std::string& local_path, vfsDevice* device);
|
|
||||||
void Link(const std::string& mount_point, const std::string& ps3_path);
|
|
||||||
void UnMount(const std::string& ps3_path);
|
|
||||||
void UnMountAll();
|
|
||||||
|
|
||||||
std::string GetLinked(const std::string& ps3_path) const;
|
|
||||||
|
|
||||||
vfsFileBase* OpenFile(const std::string& ps3_path, u32 mode) const;
|
|
||||||
vfsDirBase* OpenDir(const std::string& ps3_path) const;
|
|
||||||
bool CreateDir(const std::string& ps3_path) const;
|
|
||||||
bool CreatePath(const std::string& ps3_path) const;
|
|
||||||
bool RemoveFile(const std::string& ps3_path) const;
|
|
||||||
bool RemoveDir(const std::string& ps3_path) const;
|
|
||||||
void DeleteAll(const std::string& ps3_path) const;
|
|
||||||
u64 GetDirSize(const std::string& ps3_path) const;
|
|
||||||
bool ExistsFile(const std::string& ps3_path) const;
|
|
||||||
bool ExistsDir(const std::string& ps3_path) const;
|
|
||||||
bool Exists(const std::string& ps3_path) const;
|
|
||||||
bool Rename(const std::string& ps3_path_from, const std::string& ps3_path_to) const;
|
|
||||||
bool CopyFile(const std::string& ps3_path_from, const std::string& ps3_path_to, bool overwrite = true) const;
|
|
||||||
bool TruncateFile(const std::string& ps3_path, u64 length) const;
|
|
||||||
|
|
||||||
vfsDevice* GetDevice(const std::string& ps3_path, std::string& path) const;
|
|
||||||
vfsDevice* GetDeviceLocal(const std::string& local_path, std::string& path) const;
|
|
||||||
|
|
||||||
void Init(const std::string& path);
|
|
||||||
void SaveLoadDevices(std::vector<VFSManagerEntry>& res, bool is_load);
|
|
||||||
};
|
|
|
@ -1,249 +0,0 @@
|
||||||
#include "stdafx.h"
|
|
||||||
#include "vfsDevice.h"
|
|
||||||
|
|
||||||
vfsDevice::vfsDevice(const std::string& ps3_path, const std::string& local_path)
|
|
||||||
: m_ps3_path(ps3_path)
|
|
||||||
, m_local_path(GetWinPath(local_path))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string vfsDevice::GetLocalPath() const
|
|
||||||
{
|
|
||||||
return m_local_path;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string vfsDevice::GetPs3Path() const
|
|
||||||
{
|
|
||||||
return m_ps3_path;
|
|
||||||
}
|
|
||||||
|
|
||||||
void vfsDevice::SetPath(const std::string& ps3_path, const std::string& local_path)
|
|
||||||
{
|
|
||||||
m_ps3_path = ps3_path;
|
|
||||||
m_local_path = local_path;
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 vfsDevice::CmpPs3Path(const std::string& ps3_path)
|
|
||||||
{
|
|
||||||
const u32 lim = (u32)std::min(m_ps3_path.length(), ps3_path.length());
|
|
||||||
u32 ret = 0;
|
|
||||||
|
|
||||||
for(u32 i=0; i<lim; ++i, ++ret)
|
|
||||||
{
|
|
||||||
if(m_ps3_path[i] != ps3_path[i])
|
|
||||||
{
|
|
||||||
ret = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 vfsDevice::CmpLocalPath(const std::string& local_path)
|
|
||||||
{
|
|
||||||
if(local_path.length() < m_local_path.length())
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
#define DL "\\"
|
|
||||||
#else
|
|
||||||
#define DL "/"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
std::vector<std::string> arr0 = fmt::rSplit(m_local_path, DL);
|
|
||||||
std::vector<std::string> arr1 = fmt::rSplit(local_path, DL);
|
|
||||||
|
|
||||||
const u32 lim = (u32)std::min(arr0.size(), arr1.size());
|
|
||||||
u32 ret = 0;
|
|
||||||
|
|
||||||
for(u32 i=0; i<lim; ret += (u32)arr0[i++].size() + 1)
|
|
||||||
{
|
|
||||||
if(fmt::CmpNoCase(arr0[i],arr1[i]) != 0)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string vfsDevice::ErasePath(const std::string& path, u32 start_dir_count, u32 end_dir_count)
|
|
||||||
{
|
|
||||||
u32 from = 0;
|
|
||||||
u32 to = (u32)path.length() - 1;
|
|
||||||
|
|
||||||
for(uint i = 0, dir = 0; i < path.length(); ++i)
|
|
||||||
{
|
|
||||||
if(path[i] == '\\' || path[i] == '/' || i == path.length() - 1)
|
|
||||||
{
|
|
||||||
if(++dir == start_dir_count)
|
|
||||||
{
|
|
||||||
from = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for(int i = (int)path.length() - 1, dir = 0; i >= 0; --i)
|
|
||||||
{
|
|
||||||
if(path[i] == '\\' || path[i] == '/' || i == 0)
|
|
||||||
{
|
|
||||||
if(dir++ == end_dir_count)
|
|
||||||
{
|
|
||||||
to = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return path.substr(from, to - from);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string vfsDevice::GetRoot(const std::string& path)
|
|
||||||
{
|
|
||||||
//return fmt::ToUTF8(wxFileName(fmt::FromUTF8(path), wxPATH_UNIX).GetPath());
|
|
||||||
if(path.empty()) return "";
|
|
||||||
|
|
||||||
u32 first_dir = (u32)path.length() - 1;
|
|
||||||
|
|
||||||
for(int i = (int)path.length() - 1, dir = 0, li = (int)path.length() - 1; i >= 0 && dir < 2; --i)
|
|
||||||
{
|
|
||||||
if(path[i] == '\\' || path[i] == '/' || i == 0)
|
|
||||||
{
|
|
||||||
switch(dir++)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
first_dir = i;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 1:
|
|
||||||
if(!path.substr(i + 1, li - i).compare("USRDIR")) return path.substr(0, i + 1);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
li = i - 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return path.substr(0, first_dir + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string vfsDevice::GetRootPs3(const std::string& path)
|
|
||||||
{
|
|
||||||
if(path.empty()) return "";
|
|
||||||
|
|
||||||
static const std::string home = "/dev_hdd0/game/";
|
|
||||||
u32 last_dir = 0;
|
|
||||||
u32 first_dir = (u32)path.length() - 1;
|
|
||||||
|
|
||||||
for(int i = (int)path.length() - 1, dir = 0; i >= 0; --i)
|
|
||||||
{
|
|
||||||
if(path[i] == '\\' || path[i] == '/' || i == 0)
|
|
||||||
{
|
|
||||||
switch(dir++)
|
|
||||||
{
|
|
||||||
case 1:
|
|
||||||
if(path.substr(i + 1, last_dir - i - 1) == "USRDIR") return "";
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 2:
|
|
||||||
return GetPs3Path(home + path.substr(i + 1, last_dir - i - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
last_dir = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return GetPs3Path(home + path.substr(0, last_dir - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string vfsDevice::GetWinPath(const std::string& p, bool is_dir)
|
|
||||||
{
|
|
||||||
if(p.empty()) return "";
|
|
||||||
|
|
||||||
std::string ret;
|
|
||||||
bool is_ls = false;
|
|
||||||
|
|
||||||
for(u32 i=0; i<p.length(); ++i)
|
|
||||||
{
|
|
||||||
if(p[i] == '/' || p[i] == '\\')
|
|
||||||
{
|
|
||||||
if(!is_ls)
|
|
||||||
{
|
|
||||||
ret += '/';
|
|
||||||
is_ls = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
is_ls = false;
|
|
||||||
ret += p[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
if(is_dir && ret[ret.length() - 1] != '/' && ret[ret.length() - 1] != '\\') ret += '/'; // ???
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string vfsDevice::GetWinPath(const std::string& l, const std::string& r)
|
|
||||||
{
|
|
||||||
if(l.empty()) return GetWinPath(r, false);
|
|
||||||
if(r.empty()) return GetWinPath(l);
|
|
||||||
|
|
||||||
return GetWinPath(l + '/' + r, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string vfsDevice::GetPs3Path(const std::string& p, bool is_dir)
|
|
||||||
{
|
|
||||||
if(p.empty()) return "";
|
|
||||||
|
|
||||||
std::string ret;
|
|
||||||
bool is_ls = false;
|
|
||||||
|
|
||||||
for(u32 i=0; i<p.length(); ++i)
|
|
||||||
{
|
|
||||||
if(p[i] == L'/' || p[i] == L'\\')
|
|
||||||
{
|
|
||||||
if(!is_ls)
|
|
||||||
{
|
|
||||||
ret += '/';
|
|
||||||
is_ls = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
is_ls = false;
|
|
||||||
ret += p[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
if(ret[0] != '/') ret = '/' + ret;
|
|
||||||
if(is_dir && ret[ret.length() - 1] != '/') ret += '/';
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string vfsDevice::GetPs3Path(const std::string& l, const std::string& r)
|
|
||||||
{
|
|
||||||
if(l.empty()) return GetPs3Path(r, false);
|
|
||||||
if(r.empty()) return GetPs3Path(l);
|
|
||||||
|
|
||||||
return GetPs3Path(l + '/' + r, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void vfsDevice::Lock() const
|
|
||||||
{
|
|
||||||
m_mtx_lock.lock();
|
|
||||||
}
|
|
||||||
|
|
||||||
void vfsDevice::Unlock() const
|
|
||||||
{
|
|
||||||
m_mtx_lock.unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool vfsDevice::TryLock() const
|
|
||||||
{
|
|
||||||
return m_mtx_lock.try_lock();
|
|
||||||
}
|
|
|
@ -1,55 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
struct vfsFileBase;
|
|
||||||
class vfsDirBase;
|
|
||||||
|
|
||||||
class vfsDevice
|
|
||||||
{
|
|
||||||
std::string m_ps3_path;
|
|
||||||
std::string m_local_path;
|
|
||||||
mutable std::mutex m_mtx_lock;
|
|
||||||
|
|
||||||
public:
|
|
||||||
vfsDevice(const std::string& ps3_path, const std::string& local_path);
|
|
||||||
vfsDevice() {}
|
|
||||||
virtual ~vfsDevice() {}
|
|
||||||
|
|
||||||
virtual vfsFileBase* GetNewFileStream()=0;
|
|
||||||
virtual vfsDirBase* GetNewDirStream()=0;
|
|
||||||
|
|
||||||
std::string GetLocalPath() const;
|
|
||||||
std::string GetPs3Path() const;
|
|
||||||
|
|
||||||
void SetPath(const std::string& ps3_path, const std::string& local_path);
|
|
||||||
|
|
||||||
u32 CmpPs3Path(const std::string& ps3_path);
|
|
||||||
u32 CmpLocalPath(const std::string& local_path);
|
|
||||||
|
|
||||||
static std::string ErasePath(const std::string& local_path, u32 start_dir_count, u32 end_dir_count);
|
|
||||||
static std::string GetRoot(const std::string& local_path);
|
|
||||||
static std::string GetRootPs3(const std::string& local_path);
|
|
||||||
static std::string GetWinPath(const std::string& p, bool is_dir = true);
|
|
||||||
static std::string GetWinPath(const std::string& l, const std::string& r);
|
|
||||||
static std::string GetPs3Path(const std::string& p, bool is_dir = true);
|
|
||||||
static std::string GetPs3Path(const std::string& l, const std::string& r);
|
|
||||||
|
|
||||||
void Lock() const;
|
|
||||||
void Unlock() const;
|
|
||||||
bool TryLock() const;
|
|
||||||
};
|
|
||||||
|
|
||||||
class vfsDeviceLocker
|
|
||||||
{
|
|
||||||
vfsDevice& m_device;
|
|
||||||
|
|
||||||
public:
|
|
||||||
vfsDeviceLocker(vfsDevice& device) : m_device(device)
|
|
||||||
{
|
|
||||||
m_device.Lock();
|
|
||||||
}
|
|
||||||
|
|
||||||
~vfsDeviceLocker()
|
|
||||||
{
|
|
||||||
m_device.Unlock();
|
|
||||||
}
|
|
||||||
};
|
|
|
@ -1,14 +0,0 @@
|
||||||
#include "stdafx.h"
|
|
||||||
#include "vfsDeviceLocalFile.h"
|
|
||||||
#include "vfsLocalFile.h"
|
|
||||||
#include "vfsLocalDir.h"
|
|
||||||
|
|
||||||
vfsFileBase* vfsDeviceLocalFile::GetNewFileStream()
|
|
||||||
{
|
|
||||||
return new vfsLocalFile(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
vfsDirBase* vfsDeviceLocalFile::GetNewDirStream()
|
|
||||||
{
|
|
||||||
return new vfsLocalDir(this);
|
|
||||||
}
|
|
|
@ -1,9 +0,0 @@
|
||||||
#pragma once
|
|
||||||
#include "vfsDevice.h"
|
|
||||||
|
|
||||||
class vfsDeviceLocalFile : public vfsDevice
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
virtual vfsFileBase* GetNewFileStream() override;
|
|
||||||
virtual vfsDirBase* GetNewDirStream() override;
|
|
||||||
};
|
|
|
@ -1,79 +0,0 @@
|
||||||
#include "stdafx.h"
|
|
||||||
#include "Emu/System.h"
|
|
||||||
|
|
||||||
#include "vfsDevice.h"
|
|
||||||
#include "VFS.h"
|
|
||||||
#include "vfsDir.h"
|
|
||||||
|
|
||||||
vfsDir::vfsDir()
|
|
||||||
: vfsDirBase(nullptr)
|
|
||||||
, m_stream(nullptr)
|
|
||||||
{
|
|
||||||
// TODO: proper implementation
|
|
||||||
// m_stream is nullptr here. So open root until a proper dir is given
|
|
||||||
//Open("/");
|
|
||||||
}
|
|
||||||
|
|
||||||
vfsDir::vfsDir(const std::string& path)
|
|
||||||
: vfsDirBase(nullptr)
|
|
||||||
, m_stream(nullptr)
|
|
||||||
{
|
|
||||||
Open(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool vfsDir::Open(const std::string& path)
|
|
||||||
{
|
|
||||||
Close();
|
|
||||||
|
|
||||||
m_stream.reset(Emu.GetVFS().OpenDir(path));
|
|
||||||
|
|
||||||
DirEntryInfo info;
|
|
||||||
|
|
||||||
m_cwd = simplify_path(Emu.GetVFS().GetLinked(0 && m_stream && m_stream->IsOpened() ? m_stream->GetPath() : path), true, true);
|
|
||||||
|
|
||||||
auto blocks = simplify_path_blocks(GetPath());
|
|
||||||
|
|
||||||
for (auto dev : Emu.GetVFS().m_devices)
|
|
||||||
{
|
|
||||||
auto dev_blocks = simplify_path_blocks(dev->GetPs3Path());
|
|
||||||
|
|
||||||
if (dev_blocks.size() < (blocks.size() + 1))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_ok = true;
|
|
||||||
|
|
||||||
for (size_t i = 0; i < blocks.size(); ++i)
|
|
||||||
{
|
|
||||||
if (strcmp(dev_blocks[i].c_str(), blocks[i].c_str()))
|
|
||||||
{
|
|
||||||
is_ok = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_ok)
|
|
||||||
{
|
|
||||||
info.name = dev_blocks[blocks.size()];
|
|
||||||
m_entries.push_back(info);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_stream && m_stream->IsOpened())
|
|
||||||
{
|
|
||||||
m_entries.insert(m_entries.begin(), m_stream->GetEntries().begin(), m_stream->GetEntries().end());
|
|
||||||
}
|
|
||||||
|
|
||||||
return !m_entries.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
void vfsDir::Close()
|
|
||||||
{
|
|
||||||
m_stream.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool vfsDir::IsOpened() const
|
|
||||||
{
|
|
||||||
return !m_entries.empty();
|
|
||||||
}
|
|
|
@ -1,17 +0,0 @@
|
||||||
#pragma once
|
|
||||||
#include "vfsDirBase.h"
|
|
||||||
|
|
||||||
class vfsDir : public vfsDirBase
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
std::shared_ptr<vfsDirBase> m_stream;
|
|
||||||
|
|
||||||
public:
|
|
||||||
vfsDir();
|
|
||||||
vfsDir(const std::string& path);
|
|
||||||
|
|
||||||
virtual bool Open(const std::string& path) override;
|
|
||||||
virtual bool IsOpened() const override;
|
|
||||||
virtual void Close() override;
|
|
||||||
//virtual std::string GetPath() const override;
|
|
||||||
};
|
|
|
@ -1,59 +0,0 @@
|
||||||
#include "stdafx.h"
|
|
||||||
#include "vfsDirBase.h"
|
|
||||||
|
|
||||||
vfsDirBase::vfsDirBase(vfsDevice* device)
|
|
||||||
: m_pos(0)
|
|
||||||
, m_device(device)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
vfsDirBase::~vfsDirBase()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
bool vfsDirBase::Open(const std::string& path)
|
|
||||||
{
|
|
||||||
if (IsOpened())
|
|
||||||
{
|
|
||||||
Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
m_pos = 0;
|
|
||||||
m_cwd += '/' + path;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool vfsDirBase::IsOpened() const
|
|
||||||
{
|
|
||||||
return !m_cwd.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::vector<DirEntryInfo>& vfsDirBase::GetEntries() const
|
|
||||||
{
|
|
||||||
return m_entries;
|
|
||||||
}
|
|
||||||
|
|
||||||
void vfsDirBase::Close()
|
|
||||||
{
|
|
||||||
m_cwd = "";
|
|
||||||
m_entries.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string vfsDirBase::GetPath() const
|
|
||||||
{
|
|
||||||
return m_cwd;
|
|
||||||
}
|
|
||||||
|
|
||||||
const DirEntryInfo* vfsDirBase::Read()
|
|
||||||
{
|
|
||||||
if (m_pos >= m_entries.size())
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
return &m_entries[m_pos++];
|
|
||||||
}
|
|
||||||
|
|
||||||
const DirEntryInfo* vfsDirBase::First()
|
|
||||||
{
|
|
||||||
m_pos = 0;
|
|
||||||
return Read();
|
|
||||||
}
|
|
|
@ -1,106 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
class vfsDevice;
|
|
||||||
|
|
||||||
enum DirEntryFlags
|
|
||||||
{
|
|
||||||
DirEntry_TypeDir = 0x1,
|
|
||||||
DirEntry_TypeFile = 0x2,
|
|
||||||
DirEntry_TypeMask = 0x3,
|
|
||||||
DirEntry_PermWritable = 0x20,
|
|
||||||
DirEntry_PermReadable = 0x40,
|
|
||||||
DirEntry_PermExecutable = 0x80,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct DirEntryInfo
|
|
||||||
{
|
|
||||||
std::string name;
|
|
||||||
u32 flags;
|
|
||||||
u64 size;
|
|
||||||
time_t create_time;
|
|
||||||
time_t access_time;
|
|
||||||
time_t modify_time;
|
|
||||||
|
|
||||||
DirEntryInfo()
|
|
||||||
: flags(0)
|
|
||||||
, size(0)
|
|
||||||
, create_time(0)
|
|
||||||
, access_time(0)
|
|
||||||
, modify_time(0)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class vfsDirBase
|
|
||||||
{
|
|
||||||
protected:
|
|
||||||
std::string m_cwd;
|
|
||||||
std::vector<DirEntryInfo> m_entries;
|
|
||||||
uint m_pos;
|
|
||||||
vfsDevice* m_device;
|
|
||||||
|
|
||||||
public:
|
|
||||||
vfsDirBase(vfsDevice* device);
|
|
||||||
virtual ~vfsDirBase();
|
|
||||||
|
|
||||||
virtual bool Open(const std::string& path);
|
|
||||||
virtual bool IsOpened() const;
|
|
||||||
virtual const std::vector<DirEntryInfo>& GetEntries() const;
|
|
||||||
virtual void Close();
|
|
||||||
virtual std::string GetPath() const;
|
|
||||||
|
|
||||||
virtual const DirEntryInfo* Read();
|
|
||||||
virtual const DirEntryInfo* First();
|
|
||||||
|
|
||||||
class iterator
|
|
||||||
{
|
|
||||||
vfsDirBase *parent;
|
|
||||||
const DirEntryInfo* data;
|
|
||||||
|
|
||||||
public:
|
|
||||||
iterator(vfsDirBase* parent)
|
|
||||||
: parent(parent)
|
|
||||||
, data(parent->First())
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
iterator(vfsDirBase* parent, const DirEntryInfo* data)
|
|
||||||
: parent(parent)
|
|
||||||
, data(data)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
iterator& operator++()
|
|
||||||
{
|
|
||||||
data = parent->Read();
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
iterator operator++(int)
|
|
||||||
{
|
|
||||||
const DirEntryInfo* olddata = data;
|
|
||||||
data = parent->Read();
|
|
||||||
return iterator(parent, olddata);
|
|
||||||
}
|
|
||||||
|
|
||||||
const DirEntryInfo* operator *()
|
|
||||||
{
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator !=(iterator other) const
|
|
||||||
{
|
|
||||||
return data != other.data;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
iterator begin()
|
|
||||||
{
|
|
||||||
return iterator(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
iterator end()
|
|
||||||
{
|
|
||||||
return iterator(this, nullptr);
|
|
||||||
}
|
|
||||||
};
|
|
|
@ -1,62 +0,0 @@
|
||||||
#include "stdafx.h"
|
|
||||||
#include "Emu/System.h"
|
|
||||||
|
|
||||||
#include "VFS.h"
|
|
||||||
#include "vfsFile.h"
|
|
||||||
|
|
||||||
vfsFile::vfsFile()
|
|
||||||
: vfsFileBase(nullptr)
|
|
||||||
, m_stream(nullptr)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
vfsFile::vfsFile(const std::string& path, u32 mode)
|
|
||||||
: vfsFileBase(nullptr)
|
|
||||||
, m_stream(nullptr)
|
|
||||||
{
|
|
||||||
Open(path, mode);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool vfsFile::Open(const std::string& path, u32 mode)
|
|
||||||
{
|
|
||||||
Close();
|
|
||||||
|
|
||||||
m_stream.reset(Emu.GetVFS().OpenFile(path, mode));
|
|
||||||
|
|
||||||
return m_stream && m_stream->IsOpened();
|
|
||||||
}
|
|
||||||
|
|
||||||
void vfsFile::Close()
|
|
||||||
{
|
|
||||||
m_stream.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
u64 vfsFile::GetSize() const
|
|
||||||
{
|
|
||||||
return m_stream->GetSize();
|
|
||||||
}
|
|
||||||
|
|
||||||
u64 vfsFile::Write(const void* src, u64 size)
|
|
||||||
{
|
|
||||||
return m_stream->Write(src, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
u64 vfsFile::Read(void* dst, u64 size)
|
|
||||||
{
|
|
||||||
return m_stream->Read(dst, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
u64 vfsFile::Seek(s64 offset, fs::seek_mode whence)
|
|
||||||
{
|
|
||||||
return m_stream->Seek(offset, whence);
|
|
||||||
}
|
|
||||||
|
|
||||||
u64 vfsFile::Tell() const
|
|
||||||
{
|
|
||||||
return m_stream->Tell();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool vfsFile::IsOpened() const
|
|
||||||
{
|
|
||||||
return m_stream && m_stream->IsOpened();
|
|
||||||
}
|
|
|
@ -1,26 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "vfsFileBase.h"
|
|
||||||
|
|
||||||
class vfsFile : public vfsFileBase
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
std::shared_ptr<vfsFileBase> m_stream;
|
|
||||||
|
|
||||||
public:
|
|
||||||
vfsFile();
|
|
||||||
vfsFile(const std::string& path, u32 mode = fom::read);
|
|
||||||
|
|
||||||
virtual bool Open(const std::string& path, u32 mode = fom::read) override;
|
|
||||||
virtual void Close() override;
|
|
||||||
|
|
||||||
virtual u64 GetSize() const override;
|
|
||||||
|
|
||||||
virtual u64 Write(const void* src, u64 size) override;
|
|
||||||
virtual u64 Read(void* dst, u64 size) override;
|
|
||||||
|
|
||||||
virtual u64 Seek(s64 offset, fs::seek_mode whence = fs::seek_set) override;
|
|
||||||
virtual u64 Tell() const override;
|
|
||||||
|
|
||||||
virtual bool IsOpened() const override;
|
|
||||||
};
|
|
|
@ -1,37 +0,0 @@
|
||||||
#include "stdafx.h"
|
|
||||||
#include "vfsFileBase.h"
|
|
||||||
|
|
||||||
vfsFileBase::vfsFileBase(vfsDevice* device)
|
|
||||||
: vfsStream()
|
|
||||||
, m_device(device)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
vfsFileBase::~vfsFileBase()
|
|
||||||
{
|
|
||||||
Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool vfsFileBase::Open(const std::string& path, u32 mode)
|
|
||||||
{
|
|
||||||
m_path = path;
|
|
||||||
m_mode = mode;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void vfsFileBase::Close()
|
|
||||||
{
|
|
||||||
m_path = "";
|
|
||||||
vfsStream::Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string vfsFileBase::GetPath() const
|
|
||||||
{
|
|
||||||
return m_path;
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 vfsFileBase::GetOpenMode() const
|
|
||||||
{
|
|
||||||
return m_mode;
|
|
||||||
}
|
|
|
@ -1,24 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "vfsStream.h"
|
|
||||||
|
|
||||||
class vfsDevice;
|
|
||||||
|
|
||||||
struct vfsFileBase : public vfsStream
|
|
||||||
{
|
|
||||||
protected:
|
|
||||||
std::string m_path;
|
|
||||||
u32 m_mode;
|
|
||||||
vfsDevice* m_device;
|
|
||||||
|
|
||||||
public:
|
|
||||||
vfsFileBase(vfsDevice* device);
|
|
||||||
virtual ~vfsFileBase() override;
|
|
||||||
|
|
||||||
virtual bool Open(const std::string& path, u32 mode);
|
|
||||||
virtual void Close() override;
|
|
||||||
virtual bool IsOpened() const override { return !m_path.empty(); }
|
|
||||||
|
|
||||||
std::string GetPath() const;
|
|
||||||
u32 GetOpenMode() const;
|
|
||||||
};
|
|
|
@ -1,44 +0,0 @@
|
||||||
#include "stdafx.h"
|
|
||||||
#include "vfsDevice.h"
|
|
||||||
#include "vfsLocalDir.h"
|
|
||||||
|
|
||||||
vfsLocalDir::vfsLocalDir(vfsDevice* device) : vfsDirBase(device)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
vfsLocalDir::~vfsLocalDir()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
bool vfsLocalDir::Open(const std::string& path)
|
|
||||||
{
|
|
||||||
if (!vfsDirBase::Open(path) || !m_dir.open(path))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string name;
|
|
||||||
fs::stat_t file_info;
|
|
||||||
|
|
||||||
while (m_dir.read(name, file_info) && name.size())
|
|
||||||
{
|
|
||||||
m_entries.emplace_back();
|
|
||||||
|
|
||||||
DirEntryInfo& info = m_entries.back();
|
|
||||||
|
|
||||||
info.name = name;
|
|
||||||
info.flags |= file_info.is_directory ? DirEntry_TypeDir | DirEntry_PermExecutable : DirEntry_TypeFile;
|
|
||||||
info.flags |= file_info.is_writable ? DirEntry_PermWritable | DirEntry_PermReadable : DirEntry_PermReadable;
|
|
||||||
info.size = file_info.size;
|
|
||||||
info.access_time = file_info.atime;
|
|
||||||
info.modify_time = file_info.mtime;
|
|
||||||
info.create_time = file_info.ctime;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool vfsLocalDir::IsOpened() const
|
|
||||||
{
|
|
||||||
return m_dir && vfsDirBase::IsOpened();
|
|
||||||
}
|
|
|
@ -1,16 +0,0 @@
|
||||||
#pragma once
|
|
||||||
#include "vfsDirBase.h"
|
|
||||||
|
|
||||||
class vfsLocalDir : public vfsDirBase
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
u32 m_pos;
|
|
||||||
fs::dir m_dir;
|
|
||||||
|
|
||||||
public:
|
|
||||||
vfsLocalDir(vfsDevice* device);
|
|
||||||
virtual ~vfsLocalDir();
|
|
||||||
|
|
||||||
virtual bool Open(const std::string& path) override;
|
|
||||||
virtual bool IsOpened() const override;
|
|
||||||
};
|
|
|
@ -1,49 +0,0 @@
|
||||||
#include "stdafx.h"
|
|
||||||
#include "vfsLocalFile.h"
|
|
||||||
|
|
||||||
vfsLocalFile::vfsLocalFile(vfsDevice* device) : vfsFileBase(device)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
bool vfsLocalFile::Open(const std::string& path, u32 mode)
|
|
||||||
{
|
|
||||||
Close();
|
|
||||||
|
|
||||||
return m_file.open(path, mode) && vfsFileBase::Open(path, mode);
|
|
||||||
}
|
|
||||||
|
|
||||||
void vfsLocalFile::Close()
|
|
||||||
{
|
|
||||||
m_file.close();
|
|
||||||
vfsFileBase::Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
u64 vfsLocalFile::GetSize() const
|
|
||||||
{
|
|
||||||
return m_file.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
u64 vfsLocalFile::Write(const void* src, u64 size)
|
|
||||||
{
|
|
||||||
return m_file.write(src, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
u64 vfsLocalFile::Read(void* dst, u64 size)
|
|
||||||
{
|
|
||||||
return m_file.read(dst, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
u64 vfsLocalFile::Seek(s64 offset, fs::seek_mode whence)
|
|
||||||
{
|
|
||||||
return m_file.seek(offset, whence);
|
|
||||||
}
|
|
||||||
|
|
||||||
u64 vfsLocalFile::Tell() const
|
|
||||||
{
|
|
||||||
return m_file.seek(0, fs::seek_cur);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool vfsLocalFile::IsOpened() const
|
|
||||||
{
|
|
||||||
return m_file && vfsFileBase::IsOpened();
|
|
||||||
}
|
|
|
@ -1,27 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "vfsFileBase.h"
|
|
||||||
|
|
||||||
class vfsLocalFile : public vfsFileBase
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
fs::file m_file;
|
|
||||||
|
|
||||||
public:
|
|
||||||
vfsLocalFile(vfsDevice* device);
|
|
||||||
|
|
||||||
virtual bool Open(const std::string& path, u32 mode = fom::read) override;
|
|
||||||
virtual void Close() override;
|
|
||||||
|
|
||||||
virtual u64 GetSize() const override;
|
|
||||||
|
|
||||||
virtual u64 Write(const void* src, u64 size) override;
|
|
||||||
virtual u64 Read(void* dst, u64 size) override;
|
|
||||||
|
|
||||||
virtual u64 Seek(s64 offset, fs::seek_mode whence = fs::seek_set) override;
|
|
||||||
virtual u64 Tell() const override;
|
|
||||||
|
|
||||||
virtual bool IsOpened() const override;
|
|
||||||
|
|
||||||
virtual const fs::file& GetFile() const { return m_file; }
|
|
||||||
};
|
|
|
@ -1,2 +0,0 @@
|
||||||
#include "stdafx.h"
|
|
||||||
#include "vfsStream.h"
|
|
|
@ -1,69 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
struct vfsStream
|
|
||||||
{
|
|
||||||
vfsStream() = default;
|
|
||||||
|
|
||||||
virtual ~vfsStream()
|
|
||||||
{
|
|
||||||
Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void Close()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual u64 GetSize() const = 0;
|
|
||||||
|
|
||||||
virtual u64 Write(const void* src, u64 count) = 0;
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
force_inline bool SWrite(const T& data, u64 count = sizeof(T))
|
|
||||||
{
|
|
||||||
return Write(&data, count) == count;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual u64 Read(void* dst, u64 count) = 0;
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
force_inline bool SRead(T& data, u64 count = sizeof(T))
|
|
||||||
{
|
|
||||||
return Read(&data, count) == count;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
bool VWrite(const std::vector<T>& vec)
|
|
||||||
{
|
|
||||||
return IsOpened() && Write(vec.data(), vec.size() * sizeof(T)) == vec.size() * sizeof(T);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
std::vector<T> VRead()
|
|
||||||
{
|
|
||||||
std::vector<T> result;
|
|
||||||
if (IsOpened() == false)
|
|
||||||
{
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
result.resize(GetSize() / sizeof(T));
|
|
||||||
|
|
||||||
if (Seek(0) == -1 || Read(result.data(), result.size() * sizeof(T)) != result.size() * sizeof(T))
|
|
||||||
{
|
|
||||||
result.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual u64 Seek(s64 offset, fs::seek_mode whence = fs::seek_set) = 0;
|
|
||||||
|
|
||||||
virtual u64 Tell() const = 0;
|
|
||||||
|
|
||||||
virtual bool Eof() const
|
|
||||||
{
|
|
||||||
return Tell() >= GetSize();
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual bool IsOpened() const = 0;
|
|
||||||
};
|
|
|
@ -1,29 +0,0 @@
|
||||||
#include "stdafx.h"
|
|
||||||
#include "Emu/Memory/Memory.h"
|
|
||||||
#include "vfsStreamMemory.h"
|
|
||||||
|
|
||||||
u64 vfsStreamMemory::Write(const void* src, u64 count)
|
|
||||||
{
|
|
||||||
assert(m_pos < m_size);
|
|
||||||
if (m_pos + count > m_size)
|
|
||||||
{
|
|
||||||
count = m_size - m_pos;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::memcpy(vm::base(VM_CAST(m_addr + m_pos)), src, count);
|
|
||||||
m_pos += count;
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
u64 vfsStreamMemory::Read(void* dst, u64 count)
|
|
||||||
{
|
|
||||||
assert(m_pos < m_size);
|
|
||||||
if (m_pos + count > m_size)
|
|
||||||
{
|
|
||||||
count = m_size - m_pos;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::memcpy(dst, vm::base(VM_CAST(m_addr + m_pos)), count);
|
|
||||||
m_pos += count;
|
|
||||||
return count;
|
|
||||||
}
|
|
|
@ -1,55 +0,0 @@
|
||||||
#pragma once
|
|
||||||
#include "vfsStream.h"
|
|
||||||
|
|
||||||
class vfsStreamMemory : public vfsStream
|
|
||||||
{
|
|
||||||
u64 m_pos = 0;
|
|
||||||
u32 m_addr = 0;
|
|
||||||
u64 m_size = 0;
|
|
||||||
|
|
||||||
public:
|
|
||||||
vfsStreamMemory() = default;
|
|
||||||
|
|
||||||
vfsStreamMemory(u32 addr, u32 size = 0)
|
|
||||||
{
|
|
||||||
Open(addr, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Open(u32 addr, u32 size = 0)
|
|
||||||
{
|
|
||||||
m_pos = 0;
|
|
||||||
m_addr = addr;
|
|
||||||
m_size = size ? size : 0x100000000ull - addr; // determine max possible size
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual u64 GetSize() const override
|
|
||||||
{
|
|
||||||
return m_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual u64 Write(const void* src, u64 count) override;
|
|
||||||
|
|
||||||
virtual u64 Read(void* dst, u64 count) override;
|
|
||||||
|
|
||||||
virtual u64 Seek(s64 offset, fs::seek_mode whence) override
|
|
||||||
{
|
|
||||||
switch (whence)
|
|
||||||
{
|
|
||||||
case fs::seek_set: return m_pos = offset;
|
|
||||||
case fs::seek_cur: return m_pos += offset;
|
|
||||||
case fs::seek_end: return m_pos = m_size + offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw EXCEPTION("Unknown seek_mode (0x%x)", whence);
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual u64 Tell() const override
|
|
||||||
{
|
|
||||||
return m_pos;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual bool IsOpened() const override
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
|
Loading…
Reference in New Issue