2024-02-23 22:32:32 +01:00
|
|
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
|
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
2023-11-19 09:22:46 +01:00
|
|
|
|
|
|
|
#include <algorithm>
|
2024-07-04 23:15:44 +02:00
|
|
|
#include "common/string_util.h"
|
2024-02-23 22:32:32 +01:00
|
|
|
#include "core/file_sys/fs.h"
|
2023-11-19 09:22:46 +01:00
|
|
|
|
|
|
|
namespace Core::FileSys {
|
|
|
|
|
2024-02-23 21:57:57 +01:00
|
|
|
constexpr int RESERVED_HANDLES = 3; // First 3 handles are stdin,stdout,stderr
|
2023-11-19 09:22:46 +01:00
|
|
|
|
2024-02-27 23:10:34 +01:00
|
|
|
void MntPoints::Mount(const std::filesystem::path& host_folder, const std::string& guest_folder) {
|
2023-11-19 09:22:46 +01:00
|
|
|
std::scoped_lock lock{m_mutex};
|
2024-07-15 02:37:30 +02:00
|
|
|
m_mnt_pairs.emplace_back(host_folder, guest_folder);
|
2023-11-19 09:22:46 +01:00
|
|
|
}
|
2024-02-27 23:10:34 +01:00
|
|
|
|
2024-07-04 09:51:46 +02:00
|
|
|
void MntPoints::Unmount(const std::filesystem::path& host_folder, const std::string& guest_folder) {
|
2024-07-04 09:57:03 +02:00
|
|
|
auto it = std::remove_if(m_mnt_pairs.begin(), m_mnt_pairs.end(),
|
2024-07-15 02:37:30 +02:00
|
|
|
[&](const MntPair& pair) { return pair.mount == guest_folder; });
|
2024-07-04 09:51:46 +02:00
|
|
|
m_mnt_pairs.erase(it, m_mnt_pairs.end());
|
|
|
|
}
|
2024-02-27 23:10:34 +01:00
|
|
|
|
|
|
|
void MntPoints::UnmountAll() {
|
2023-11-19 09:22:46 +01:00
|
|
|
std::scoped_lock lock{m_mutex};
|
|
|
|
m_mnt_pairs.clear();
|
|
|
|
}
|
2024-02-27 23:10:34 +01:00
|
|
|
|
2024-07-15 02:37:30 +02:00
|
|
|
std::filesystem::path MntPoints::GetHostPath(const std::string& guest_directory) {
|
|
|
|
const MntPair* mount = GetMount(guest_directory);
|
|
|
|
if (!mount) {
|
|
|
|
return guest_directory;
|
|
|
|
}
|
|
|
|
|
2024-07-15 13:38:42 +02:00
|
|
|
// Nothing to do if getting the mount itself.
|
|
|
|
if (guest_directory == mount->mount) {
|
|
|
|
return mount->host_path;
|
|
|
|
}
|
|
|
|
|
2024-07-15 02:37:30 +02:00
|
|
|
// Remove device (e.g /app0) from path to retrieve relative path.
|
|
|
|
const u32 pos = mount->mount.size() + 1;
|
|
|
|
const auto rel_path = std::string_view(guest_directory).substr(pos);
|
|
|
|
const auto host_path = mount->host_path / rel_path;
|
2024-07-15 13:38:42 +02:00
|
|
|
if (!NeedsCaseInsensiveSearch) {
|
2024-07-15 02:37:30 +02:00
|
|
|
return host_path;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If the path does not exist attempt to verify this.
|
|
|
|
// Retrieve parent path until we find one that exists.
|
|
|
|
path_parts.clear();
|
|
|
|
auto current_path = host_path;
|
|
|
|
while (!std::filesystem::exists(current_path)) {
|
|
|
|
// We have probably cached this if it's a folder.
|
|
|
|
if (auto it = path_cache.find(current_path); it != path_cache.end()) {
|
|
|
|
current_path = it->second;
|
|
|
|
break;
|
2023-11-19 09:22:46 +01:00
|
|
|
}
|
2024-07-15 02:37:30 +02:00
|
|
|
path_parts.emplace_back(current_path.filename());
|
|
|
|
current_path = current_path.parent_path();
|
2023-11-19 09:22:46 +01:00
|
|
|
}
|
2024-02-27 23:10:34 +01:00
|
|
|
|
2024-07-15 02:37:30 +02:00
|
|
|
// We have found an anchor. Traverse parts we recoded and see if they
|
|
|
|
// exist in filesystem but in different case.
|
|
|
|
auto guest_path = current_path;
|
|
|
|
while (!path_parts.empty()) {
|
|
|
|
const auto& part = path_parts.back();
|
|
|
|
const auto add_match = [&](const auto& host_part) {
|
|
|
|
current_path += host_part;
|
|
|
|
guest_path += part;
|
|
|
|
path_cache[guest_path] = current_path;
|
|
|
|
path_parts.pop_back();
|
|
|
|
};
|
2023-11-19 09:22:46 +01:00
|
|
|
|
2024-07-15 02:37:30 +02:00
|
|
|
// Can happen when the mismatch is in upper folder.
|
|
|
|
if (std::filesystem::exists(current_path / part)) {
|
|
|
|
add_match(part);
|
2024-07-04 23:15:44 +02:00
|
|
|
continue;
|
|
|
|
}
|
2024-07-15 02:37:30 +02:00
|
|
|
const auto part_low = Common::ToLower(part.string());
|
|
|
|
bool found_match = false;
|
|
|
|
for (const auto& path : std::filesystem::directory_iterator(current_path)) {
|
|
|
|
const auto candidate = path.path().filename();
|
2024-07-15 13:50:23 +02:00
|
|
|
const auto filename = Common::ToLower(candidate.string());
|
2024-07-15 02:37:30 +02:00
|
|
|
// Check if a filename matches in case insensitive manner.
|
|
|
|
if (filename != part_low) {
|
|
|
|
continue;
|
2024-07-04 23:15:44 +02:00
|
|
|
}
|
2024-07-15 02:37:30 +02:00
|
|
|
// We found a match, record the actual path in the cache.
|
|
|
|
add_match(candidate);
|
|
|
|
found_match = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (!found_match) {
|
|
|
|
// Opening the guest path will surely fail but at least gives
|
|
|
|
// a better error message than the empty path.
|
2024-07-15 13:38:42 +02:00
|
|
|
return host_path;
|
2023-11-19 09:22:46 +01:00
|
|
|
}
|
|
|
|
}
|
2024-07-15 02:37:30 +02:00
|
|
|
|
|
|
|
// The path was found.
|
|
|
|
return current_path;
|
2023-11-19 09:22:46 +01:00
|
|
|
}
|
2024-02-27 23:10:34 +01:00
|
|
|
|
|
|
|
int HandleTable::CreateHandle() {
|
2023-11-19 09:22:46 +01:00
|
|
|
std::scoped_lock lock{m_mutex};
|
2024-02-27 23:10:34 +01:00
|
|
|
|
2023-11-19 09:22:46 +01:00
|
|
|
auto* file = new File{};
|
2024-02-27 23:10:34 +01:00
|
|
|
file->is_directory = false;
|
|
|
|
file->is_opened = false;
|
2023-11-19 09:22:46 +01:00
|
|
|
|
|
|
|
int existingFilesNum = m_files.size();
|
|
|
|
|
|
|
|
for (int index = 0; index < existingFilesNum; index++) {
|
|
|
|
if (m_files.at(index) == nullptr) {
|
|
|
|
m_files[index] = file;
|
|
|
|
return index + RESERVED_HANDLES;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
m_files.push_back(file);
|
|
|
|
return m_files.size() + RESERVED_HANDLES - 1;
|
|
|
|
}
|
2024-02-27 23:10:34 +01:00
|
|
|
|
|
|
|
void HandleTable::DeleteHandle(int d) {
|
2023-11-19 09:22:46 +01:00
|
|
|
std::scoped_lock lock{m_mutex};
|
|
|
|
delete m_files.at(d - RESERVED_HANDLES);
|
|
|
|
m_files[d - RESERVED_HANDLES] = nullptr;
|
|
|
|
}
|
|
|
|
|
2024-02-27 23:10:34 +01:00
|
|
|
File* HandleTable::GetFile(int d) {
|
2023-11-19 09:22:46 +01:00
|
|
|
std::scoped_lock lock{m_mutex};
|
|
|
|
return m_files.at(d - RESERVED_HANDLES);
|
|
|
|
}
|
2024-02-27 23:10:34 +01:00
|
|
|
|
2023-11-19 09:22:46 +01:00
|
|
|
File* HandleTable::getFile(const std::string& host_name) {
|
|
|
|
std::scoped_lock lock{m_mutex};
|
|
|
|
for (auto* file : m_files) {
|
|
|
|
if (file != nullptr && file->m_host_name == host_name) {
|
|
|
|
return file;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
}
|
2024-06-15 13:36:07 +02:00
|
|
|
|
2024-02-23 22:32:32 +01:00
|
|
|
} // namespace Core::FileSys
|