mirror of
https://github.com/Team-Resurgent/rpcs3.git
synced 2026-08-15 11:18:10 -07:00
sys_fs: Implemented sys_fs_mount(prot=1) read-only mounting & fixed up some operation and permission checks
This commit is contained in:
+13
-41
@@ -3,6 +3,7 @@
|
||||
#include "StrFmt.h"
|
||||
#include "Crypto/sha1.h"
|
||||
|
||||
#include <filesystem>
|
||||
#include <unordered_map>
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
@@ -384,55 +385,26 @@ shared_ptr<fs::device_base> fs::set_virtual_device(const std::string& name, shar
|
||||
return get_device_manager().set_device(name, std::move(device));
|
||||
}
|
||||
|
||||
std::string fs::get_parent_dir(std::string_view path, u32 levels)
|
||||
std::string fs::get_parent_dir(std::string_view path, u32 parent_level)
|
||||
{
|
||||
std::string_view result = path;
|
||||
std::string normalized_path = std::filesystem::path(path).lexically_normal().string();
|
||||
|
||||
// Number of path components to remove
|
||||
usz to_remove = levels;
|
||||
#ifdef _WIN32
|
||||
std::replace(normalized_path.begin(), normalized_path.end(), '\\', '/');
|
||||
#endif
|
||||
|
||||
while (to_remove--)
|
||||
if (normalized_path.back() == '/')
|
||||
normalized_path.pop_back();
|
||||
|
||||
while (parent_level--)
|
||||
{
|
||||
// Trim contiguous delimiters at the end
|
||||
if (usz sz = result.find_last_not_of(delim) + 1)
|
||||
{
|
||||
result = result.substr(0, sz);
|
||||
}
|
||||
if (const auto pos = normalized_path.find_last_of('/'); pos != umax)
|
||||
normalized_path = normalized_path.substr(0, pos);
|
||||
else
|
||||
{
|
||||
return "/";
|
||||
}
|
||||
|
||||
const auto elem = result.substr(result.find_last_of(delim) + 1);
|
||||
|
||||
if (elem.empty() || elem.size() == result.size())
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (elem == ".")
|
||||
{
|
||||
to_remove += 1;
|
||||
}
|
||||
|
||||
if (elem == "..")
|
||||
{
|
||||
to_remove += 2;
|
||||
}
|
||||
|
||||
result.remove_suffix(elem.size());
|
||||
}
|
||||
|
||||
if (usz sz = result.find_last_not_of(delim) + 1)
|
||||
{
|
||||
result = result.substr(0, sz);
|
||||
}
|
||||
else
|
||||
{
|
||||
return "/";
|
||||
}
|
||||
|
||||
return std::string{result};
|
||||
return normalized_path.empty() ? "/" : normalized_path;
|
||||
}
|
||||
|
||||
bool fs::stat(const std::string& path, stat_t& info)
|
||||
|
||||
+2
-2
@@ -165,8 +165,8 @@ namespace fs
|
||||
// Set virtual device with specified name (nullptr for deletion)
|
||||
shared_ptr<device_base> set_virtual_device(const std::string& name, shared_ptr<device_base> device);
|
||||
|
||||
// Try to get parent directory (returns empty string on failure)
|
||||
std::string get_parent_dir(std::string_view path, u32 levels = 1);
|
||||
// Try to get normalized parent directory
|
||||
std::string get_parent_dir(std::string_view path, u32 parent_level = 1);
|
||||
|
||||
// Get file information
|
||||
bool stat(const std::string& path, stat_t& info);
|
||||
|
||||
@@ -139,18 +139,19 @@ error_code cellSysCacheMount(vm::ptr<CellSysCacheParam> param)
|
||||
{
|
||||
});
|
||||
|
||||
std::lock_guard lock0(g_mp_sys_dev_hdd1.mutex);
|
||||
|
||||
// Check if can reuse existing cache (won't if cache id is an empty string)
|
||||
if (param->cacheId[0] && cache_id == cache.cache_id)
|
||||
{
|
||||
// Isn't mounted yet on first call to cellSysCacheMount
|
||||
vfs::mount("/dev_hdd1", new_path);
|
||||
if (vfs::mount("/dev_hdd1", new_path))
|
||||
g_fxo->get<lv2_fs_mount_info_map>().add("/dev_hdd1", &g_mp_sys_dev_hdd1);
|
||||
|
||||
cellSysutil.success("Mounted existing cache at %s", new_path);
|
||||
return not_an_error(CELL_SYSCACHE_RET_OK_RELAYED);
|
||||
}
|
||||
|
||||
std::lock_guard lock0(g_mp_sys_dev_hdd1.mutex);
|
||||
|
||||
// Clear existing cache
|
||||
if (!cache.cache_id.empty())
|
||||
{
|
||||
@@ -160,7 +161,8 @@ error_code cellSysCacheMount(vm::ptr<CellSysCacheParam> param)
|
||||
// Set new cache id
|
||||
cache.cache_id = std::move(cache_id);
|
||||
fs::create_dir(new_path);
|
||||
vfs::mount("/dev_hdd1", new_path);
|
||||
if (vfs::mount("/dev_hdd1", new_path))
|
||||
g_fxo->get<lv2_fs_mount_info_map>().add("/dev_hdd1", &g_mp_sys_dev_hdd1);
|
||||
|
||||
return not_an_error(CELL_SYSCACHE_RET_OK_CLEARED);
|
||||
}
|
||||
|
||||
+140
-148
File diff suppressed because it is too large
Load Diff
+21
-16
@@ -173,7 +173,7 @@ struct lv2_fs_mount_info
|
||||
: mp(mp ? mp : &g_mp_sys_no_device)
|
||||
, device(device.empty() ? this->mp->device : device)
|
||||
, file_system(file_system.empty() ? this->mp->file_system : file_system)
|
||||
, read_only((this->mp->flags & lv2_mp_flag::read_only) || read_only)
|
||||
, read_only((this->mp->flags & lv2_mp_flag::read_only) || read_only) // respect the original flags of the mount point as well
|
||||
{
|
||||
}
|
||||
|
||||
@@ -181,16 +181,18 @@ struct lv2_fs_mount_info
|
||||
{
|
||||
return this == &rhs;
|
||||
}
|
||||
constexpr bool operator==(lv2_fs_mount_point* const& rhs) const noexcept
|
||||
constexpr bool operator==(const lv2_fs_mount_point* const& rhs) const noexcept
|
||||
{
|
||||
return mp == rhs;
|
||||
}
|
||||
constexpr const lv2_fs_mount_point* operator->() const noexcept
|
||||
constexpr lv2_fs_mount_point* operator->() const noexcept
|
||||
{
|
||||
return mp;
|
||||
}
|
||||
};
|
||||
|
||||
extern lv2_fs_mount_info g_mi_sys_not_found;
|
||||
|
||||
struct CellFsMountInfo; // Forward Declaration
|
||||
|
||||
struct lv2_fs_mount_info_map
|
||||
@@ -205,11 +207,16 @@ public:
|
||||
|
||||
// Forwarding arguments to map.try_emplace(): refer to the constructor of lv2_fs_mount_info
|
||||
template <typename... Args>
|
||||
bool add(Args&&... args);
|
||||
bool add(Args&&... args)
|
||||
{
|
||||
return map.try_emplace(std::forward<Args>(args)...).second;
|
||||
}
|
||||
bool remove(std::string_view path);
|
||||
const lv2_fs_mount_info& lookup(std::string_view path) const;
|
||||
const lv2_fs_mount_info& lookup(std::string_view path, bool no_cell_fs_path = false) const;
|
||||
u64 get_all(CellFsMountInfo* info = nullptr, u64 len = 0) const;
|
||||
|
||||
static bool vfs_unmount(std::string_view vpath);
|
||||
|
||||
private:
|
||||
struct string_hash
|
||||
{
|
||||
@@ -231,7 +238,6 @@ private:
|
||||
};
|
||||
|
||||
std::unordered_map<std::string, lv2_fs_mount_info, string_hash, std::equal_to<>> map;
|
||||
lv2_fs_mount_info mount_info_no_device;
|
||||
};
|
||||
|
||||
struct lv2_fs_object
|
||||
@@ -245,15 +251,11 @@ struct lv2_fs_object
|
||||
// File Name (max 1055)
|
||||
const std::array<char, 0x420> name;
|
||||
|
||||
// Mount Point
|
||||
lv2_fs_mount_point* const mp = get_mp(name.data());
|
||||
// Mount Info
|
||||
const lv2_fs_mount_info& mp;
|
||||
|
||||
protected:
|
||||
lv2_fs_object(std::string_view filename)
|
||||
: name(get_name(filename))
|
||||
{
|
||||
}
|
||||
|
||||
lv2_fs_object(std::string_view filename);
|
||||
lv2_fs_object(utils::serial& ar, bool dummy);
|
||||
|
||||
public:
|
||||
@@ -261,9 +263,12 @@ public:
|
||||
|
||||
lv2_fs_object& operator=(const lv2_fs_object&) = delete;
|
||||
|
||||
static std::string_view get_device_root(std::string_view filename);
|
||||
static std::string get_device_root(std::string_view filename);
|
||||
|
||||
// Filename can be either a path starting with '/' or a CELL_FS device name
|
||||
// This should be used only when handling devices that are not mounted
|
||||
// Otherwise, use g_fxo->get<lv2_fs_mount_info_map>().lookup() to look up mounted devices accurately
|
||||
static lv2_fs_mount_point* get_mp(std::string_view filename, std::string* vfs_path = nullptr);
|
||||
static bool vfs_unmount(std::string_view vpath);
|
||||
|
||||
static std::array<char, 0x420> get_name(std::string_view filename)
|
||||
{
|
||||
@@ -345,7 +350,7 @@ struct lv2_file final : lv2_fs_object
|
||||
};
|
||||
|
||||
// Open a file with wrapped logic of sys_fs_open
|
||||
static open_raw_result_t open_raw(const std::string& path, s32 flags, s32 mode, lv2_file_type type = lv2_file_type::regular, const lv2_fs_mount_point* mp = nullptr);
|
||||
static open_raw_result_t open_raw(const std::string& path, s32 flags, s32 mode, lv2_file_type type = lv2_file_type::regular, const lv2_fs_mount_info& mp = g_mi_sys_not_found);
|
||||
static open_result_t open(std::string_view vpath, s32 flags, s32 mode, const void* arg = {}, u64 size = 0);
|
||||
|
||||
// File reading with intermediate buffer
|
||||
|
||||
+1
-1
@@ -956,7 +956,7 @@ bool vfs::host::rename(const std::string& from, const std::string& to, const lv2
|
||||
|
||||
file.restore_data.seek_pos = file.file.pos();
|
||||
|
||||
if (!(file.mp->flags & (lv2_mp_flag::read_only + lv2_mp_flag::cache)) && file.flags & CELL_FS_O_ACCMODE)
|
||||
if (!(file.mp.read_only && file.mp->flags & lv2_mp_flag::cache) && file.flags & CELL_FS_O_ACCMODE)
|
||||
{
|
||||
file.file.sync(); // For cellGameContentPermit atomicity
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user