2017-10-11 02:19:32 +02:00
|
|
|
|
#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-04-27 00:27:24 +02:00
|
|
|
|
|
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>();
|
|
|
|
|
|
|
2018-03-11 11:05:47 +01:00
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
|
|
2018-03-11 11:05:47 +01: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>();
|
|
|
|
|
|
|
2018-03-11 11:05:47 +01:00
|
|
|
|
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
|
|
|
|
|
2018-03-11 11:05:47 +01: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
|
|
|
|
|
2017-10-11 02:19:32 +02:00
|
|
|
|
return found->second + vfs::escape(vpath);
|
2017-09-18 23:03:26 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2018-03-11 11:05:47 +01:00
|
|
|
|
if (match.length(1) + pos == 0)
|
2017-09-18 23:03:26 +02:00
|
|
|
|
{
|
|
|
|
|
|
return "/";
|
|
|
|
|
|
}
|
2016-04-14 00:59:00 +02:00
|
|
|
|
|
2018-03-11 11:05:47 +01: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
|
|
|
|
{
|
2018-03-11 11:05:47 +01: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
|
|
|
|
}
|
|
|
|
|
|
|
2017-10-11 02:19:32 +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
|
|
|
|
}
|