sys_fs: Implemented sys_fs_mount(prot=1) read-only mounting & fixed up some operation and permission checks

This commit is contained in:
brian218
2023-06-05 13:51:54 +03:00
committed by kd-11
parent 5e6aa45658
commit 6a570ae57e
6 changed files with 183 additions and 212 deletions
+13 -41
View File
@@ -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
View File
@@ -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);
+6 -4
View File
@@ -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);
}
File diff suppressed because it is too large Load Diff
+21 -16
View File
@@ -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
View File
@@ -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
}