Escape problematic characters in VFS

With full-width <>:"\|?*
This commit is contained in:
Nekotekina 2017-10-11 03:19:32 +03:00
parent 19f3bb8cb0
commit 5b19908996
5 changed files with 253 additions and 15 deletions

View File

@ -4,6 +4,7 @@
#include "sha1.h"
#include "key_vault.h"
#include "Utilities/StrFmt.h"
#include "Emu/VFS.h"
#include "unpkg.h"
bool pkg_install(const fs::file& pkg_f, const std::string& dir, atomic_t<double>& sync, const std::string& pkg_filepath)
@ -285,7 +286,7 @@ bool pkg_install(const fs::file& pkg_f, const std::string& dir, atomic_t<double>
decrypt(entry.name_offset, entry.name_size, is_psp ? PKG_AES_KEY2 : dec_key.data());
const std::string name(reinterpret_cast<char*>(buf.get()), entry.name_size);
std::string name{reinterpret_cast<char*>(buf.get()), entry.name_size};
LOG_NOTICE(LOADER, "Entry 0x%08x: %s", entry.type, name);
@ -303,17 +304,17 @@ bool pkg_install(const fs::file& pkg_f, const std::string& dir, atomic_t<double>
case 0x15:
case 0x16:
{
const std::string path = dir + name;
const std::string path = dir + vfs::escape(name);
const bool did_overwrite = fs::is_file(path);
if (did_overwrite && (entry.type&PKG_FILE_ENTRY_OVERWRITE) == 0)
if (did_overwrite && (entry.type & PKG_FILE_ENTRY_OVERWRITE) == 0)
{
LOG_NOTICE(LOADER, "Didn't overwrite %s", name);
break;
}
if (fs::file out{ path, fs::rewrite })
if (fs::file out{path, fs::rewrite})
{
for (u64 pos = 0; pos < entry.file_size; pos += BUF_SIZE)
{
@ -358,7 +359,7 @@ bool pkg_install(const fs::file& pkg_f, const std::string& dir, atomic_t<double>
case PKG_FILE_ENTRY_FOLDER:
case 0x12:
{
const std::string path = dir + name;
const std::string path = dir + vfs::escape(name);
if (fs::create_dir(path))
{

View File

@ -103,13 +103,15 @@ static NEVER_INLINE s32 savedata_op(ppu_thread& ppu, u32 operation, u32 version,
const auto prefix_list = fmt::split(setList->dirNamePrefix.get_ptr(), { "|" });
// get the saves matching the supplied prefix
for (const auto& entry : fs::dir(base_dir))
for (auto&& entry : fs::dir(base_dir))
{
if (!entry.is_directory)
{
continue;
}
entry.name = vfs::unescape(entry.name);
for (const auto& prefix : prefix_list)
{
if (entry.name.substr(0, prefix.size()) == prefix)
@ -453,8 +455,10 @@ static NEVER_INLINE s32 savedata_op(ppu_thread& ppu, u32 operation, u32 version,
auto file_list = statGet->fileList.get_ptr();
for (const auto& entry : fs::dir(dir_path))
for (auto&& entry : fs::dir(dir_path))
{
entry.name = vfs::unescape(entry.name);
// only files, system files ignored, fileNum is limited by setBuf->fileListMax
if (!entry.is_directory && entry.name != "PARAM.SFO" && statGet->fileListNum++ < setBuf->fileListMax)
{

View File

@ -480,9 +480,10 @@ error_code sys_fs_readdir(u32 fd, vm::ptr<CellFsDirent> dir, vm::ptr<u64> nread)
if (directory->dir.read(info))
{
const std::string vfs_name = vfs::unescape(info.name);
dir->d_type = info.is_directory ? CELL_FS_TYPE_DIRECTORY : CELL_FS_TYPE_REGULAR;
dir->d_namlen = u8(std::min<size_t>(info.name.size(), CELL_FS_MAX_FS_FILE_NAME_LENGTH));
strcpy_trunc(dir->d_name, info.name);
dir->d_namlen = u8(std::min<size_t>(vfs_name.size(), CELL_FS_MAX_FS_FILE_NAME_LENGTH));
strcpy_trunc(dir->d_name, vfs_name);
*nread = sizeof(CellFsDirent);
}
else
@ -1014,9 +1015,10 @@ error_code sys_fs_fcntl(u32 fd, u32 op, vm::ptr<void> _arg, u32 _size)
entry.attribute.size = info.size;
entry.attribute.blksize = 4096; // ???
const std::string vfs_name = vfs::unescape(info.name);
entry.entry_name.d_type = info.is_directory ? CELL_FS_TYPE_DIRECTORY : CELL_FS_TYPE_REGULAR;
entry.entry_name.d_namlen = u8(std::min<size_t>(info.name.size(), CELL_FS_MAX_FS_FILE_NAME_LENGTH));
strcpy_trunc(entry.entry_name.d_name, info.name);
entry.entry_name.d_namlen = u8(std::min<size_t>(vfs_name.size(), CELL_FS_MAX_FS_FILE_NAME_LENGTH));
strcpy_trunc(entry.entry_name.d_name, vfs_name);
}
else
{

View File

@ -1,4 +1,4 @@
#include "stdafx.h"
#include "stdafx.h"
#include "IdManager.h"
#include "VFS.h"
@ -42,7 +42,7 @@ std::string vfs::get(const std::string& vpath, vfs::type _type)
return {};
}
return found->second + vpath;
return found->second + vfs::escape(vpath);
}
if (_type == type::ps3 && match.length(1) == 0)
@ -58,6 +58,231 @@ std::string vfs::get(const std::string& vpath, vfs::type _type)
return {};
}
// Concatenate
return found->second + match.str(2);
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;
}

View File

@ -16,4 +16,10 @@ namespace vfs
// Convert VFS path to fs path
std::string get(const std::string& vpath, type _type = type::ps3);
// Escape VFS path by replacing non-portable characters with surrogates
std::string escape(const std::string& path);
// Invert escape operation
std::string unescape(const std::string& path);
}