rpcsx/rpcs3/Emu/VFS.cpp

303 lines
4.5 KiB
C++
Raw Normal View History

#include "stdafx.h"
2016-06-02 17:16:01 +02:00
#include "IdManager.h"
2016-04-14 00:59:00 +02:00
#include "VFS.h"
2016-06-02 17:16:01 +02:00
#include <regex>
struct vfs_manager
{
shared_mutex mutex;
2016-06-02 17:16:01 +02:00
// Device name -> Real path
std::unordered_map<std::string, std::string> mounted;
};
2016-04-14 00:59:00 +02:00
2016-06-02 17:16:01 +02:00
const std::regex s_regex_ps3("^/+(.*?)(?:$|/)(.*)", std::regex::optimize);
2016-04-14 00:59:00 +02:00
2016-06-02 17:16:01 +02:00
bool vfs::mount(const std::string& dev_name, const std::string& path)
2016-04-14 00:59:00 +02:00
{
2016-06-02 17:16:01 +02:00
const auto table = fxm::get_always<vfs_manager>();
safe_writer_lock lock(table->mutex);
2016-06-02 17:16:01 +02:00
return table->mounted.emplace(dev_name, path).second;
2016-04-14 00:59:00 +02:00
}
std::string vfs::get(const std::string& vpath, const std::string* prev, std::size_t pos)
2016-04-14 00:59:00 +02:00
{
2017-09-18 23:03:26 +02:00
const auto table = fxm::get_always<vfs_manager>();
safe_reader_lock lock(table->mutex);
2017-09-18 23:03:26 +02:00
2016-06-02 17:16:01 +02:00
std::smatch match;
2016-04-14 00:59:00 +02:00
if (!std::regex_match(vpath.begin() + pos, vpath.end(), match, s_regex_ps3))
2016-04-14 00:59:00 +02:00
{
2017-09-18 23:03:26 +02:00
const auto found = table->mounted.find("");
2016-04-14 00:59:00 +02:00
2017-09-18 23:03:26 +02:00
if (found == table->mounted.end())
{
LOG_WARNING(GENERAL, "vfs::get(): no default directory: %s", vpath);
return {};
}
2016-04-14 00:59:00 +02:00
return found->second + vfs::escape(vpath);
2017-09-18 23:03:26 +02:00
}
if (match.length(1) + pos == 0)
2017-09-18 23:03:26 +02:00
{
return "/";
}
2016-04-14 00:59:00 +02:00
std::string dev;
if (prev)
{
dev += *prev;
dev += '/';
}
dev += match.str(1);
const auto found = table->mounted.find(dev);
2016-04-14 00:59:00 +02:00
2016-06-02 17:16:01 +02:00
if (found == table->mounted.end())
2016-04-14 00:59:00 +02:00
{
if (match.length(2))
{
return vfs::get(vpath, &dev, pos + match.position(1) + match.length(1));
}
2016-06-02 17:16:01 +02:00
LOG_WARNING(GENERAL, "vfs::get(): device not found: %s", vpath);
2017-09-18 23:03:26 +02:00
return {};
2016-04-14 00:59:00 +02:00
}
if (found->second.empty())
{
// Don't escape /host_root (TODO)
return match.str(2);
}
// Escape and concatenate
return found->second + vfs::escape(match.str(2));
}
std::string vfs::escape(const std::string& path)
{
std::string result;
result.reserve(path.size());
for (std::size_t i = 0, s = path.size(); i < s; i++)
{
switch (char c = path[i])
{
case '<':
{
result += u8"";
break;
}
case '>':
{
result += u8"";
break;
}
case ':':
{
result += u8"";
break;
}
case '"':
{
result += u8"";
break;
}
case '\\':
{
result += u8"";
break;
}
case '|':
{
result += u8"";
break;
}
case '?':
{
result += u8"";
break;
}
case '*':
{
result += u8"";
break;
}
case char{u8""[0]}:
{
// Escape full-width characters 0xFF01..0xFF5e with (0xFF01)
switch (path[i + 1])
{
case char{u8""[1]}:
{
const uchar c3 = reinterpret_cast<const uchar&>(path[i + 2]);
if (c3 >= 0x81 && c3 <= 0xbf)
{
result += u8"";
}
break;
}
case char{u8""[1]}:
{
const uchar c3 = reinterpret_cast<const uchar&>(path[i + 2]);
if (c3 >= 0x80 && c3 <= 0x9e)
{
result += u8"";
}
break;
}
}
result += c;
break;
}
default:
{
result += c;
break;
}
}
}
return result;
}
std::string vfs::unescape(const std::string& path)
{
std::string result;
result.reserve(path.size());
for (std::size_t i = 0, s = path.size(); i < s; i++)
{
switch (char c = path[i])
{
case char{u8""[0]}:
{
switch (path[i + 1])
{
case char{u8""[1]}:
{
const uchar c3 = reinterpret_cast<const uchar&>(path[i + 2]);
if (c3 >= 0x81 && c3 <= 0xbf)
{
switch (path[i + 2])
{
case char{u8""[2]}:
{
i += 3;
result += c;
continue;
}
case char{u8""[2]}:
{
result += '<';
break;
}
case char{u8""[2]}:
{
result += '>';
break;
}
case char{u8""[2]}:
{
result += ':';
break;
}
case char{u8""[2]}:
{
result += '"';
break;
}
case char{u8""[2]}:
{
result += '\\';
break;
}
case char{u8""[2]}:
{
result += '?';
break;
}
case char{u8""[2]}:
{
result += '*';
break;
}
default:
{
// Unrecognized character (ignored)
break;
}
}
i += 2;
}
else
{
result += c;
}
break;
}
case char{u8""[1]}:
{
const uchar c3 = reinterpret_cast<const uchar&>(path[i + 2]);
if (c3 >= 0x80 && c3 <= 0x9e)
{
switch (path[i + 2])
{
case char{u8""[2]}:
{
result += '|';
break;
}
default:
{
// Unrecognized character (ignored)
break;
}
}
i += 2;
}
else
{
result += c;
}
break;
}
default:
{
result += c;
break;
}
}
break;
}
default:
{
result += c;
break;
}
}
}
return result;
2016-04-14 00:59:00 +02:00
}