Compare commits
6 Commits
main
...
gamefixes3
Author | SHA1 | Date |
---|---|---|
georgemoralis | 193e74f750 | |
georgemoralis | a69dfda538 | |
georgemoralis | b6ffedba85 | |
georgemoralis | fc38cf0d8b | |
georgemoralis | 61920b198c | |
georgemoralis | d334083c2b |
|
@ -225,6 +225,8 @@ set(COMMON src/common/logging/backend.cpp
|
||||||
src/common/io_file.h
|
src/common/io_file.h
|
||||||
src/common/error.cpp
|
src/common/error.cpp
|
||||||
src/common/error.h
|
src/common/error.h
|
||||||
|
src/common/fs.cpp
|
||||||
|
src/common/fs.h
|
||||||
src/common/scope_exit.h
|
src/common/scope_exit.h
|
||||||
src/common/func_traits.h
|
src/common/func_traits.h
|
||||||
src/common/native_clock.cpp
|
src/common/native_clock.cpp
|
||||||
|
|
|
@ -0,0 +1,666 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include "fs.h"
|
||||||
|
#include "io_file.h"
|
||||||
|
|
||||||
|
#include "logging/log.h"
|
||||||
|
#include "path_util.h"
|
||||||
|
|
||||||
|
namespace Common::FS {
|
||||||
|
|
||||||
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
|
// File Operations
|
||||||
|
|
||||||
|
bool NewFile(const fs::path& path, u64 size) {
|
||||||
|
if (!ValidatePath(path)) {
|
||||||
|
// LOG_ERROR(Common_Filesystem, "Input path is not valid, path={}", PathToUTF8String(path));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Exists(path.parent_path())) {
|
||||||
|
// LOG_ERROR(Common_Filesystem, "Parent directory of path={} does not exist",
|
||||||
|
// PathToUTF8String(path));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Exists(path)) {
|
||||||
|
// LOG_ERROR(Common_Filesystem, "Filesystem object at path={} exists",
|
||||||
|
// PathToUTF8String(path));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
IOFile io_file{path, FileAccessMode::Write};
|
||||||
|
|
||||||
|
if (!io_file.IsOpen()) {
|
||||||
|
// LOG_ERROR(Common_Filesystem, "Failed to create a file at path={}",
|
||||||
|
// PathToUTF8String(path));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!io_file.SetSize(size)) {
|
||||||
|
// LOG_ERROR(Common_Filesystem, "Failed to resize the file at path={} to size={}",
|
||||||
|
// PathToUTF8String(path), size);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
io_file.Close();
|
||||||
|
|
||||||
|
// LOG_DEBUG(Common_Filesystem, "Successfully created a file at path={} with size={}",
|
||||||
|
// PathToUTF8String(path), size);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RemoveFile(const fs::path& path) {
|
||||||
|
if (!ValidatePath(path)) {
|
||||||
|
// LOG_ERROR(Common_Filesystem, "Input path is not valid, path={}",
|
||||||
|
// PathToUTF8String(path));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Exists(path)) {
|
||||||
|
// LOG_DEBUG(Common_Filesystem, "Filesystem object at path={} does not exist",
|
||||||
|
// PathToUTF8String(path));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!IsFile(path)) {
|
||||||
|
// LOG_ERROR(Common_Filesystem, "Filesystem object at path={} is not a file",
|
||||||
|
// PathToUTF8String(path));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::error_code ec;
|
||||||
|
|
||||||
|
fs::remove(path, ec);
|
||||||
|
|
||||||
|
if (ec) {
|
||||||
|
// LOG_ERROR(Common_Filesystem, "Failed to remove the file at path={}, ec_message={}",
|
||||||
|
// PathToUTF8String(path), ec.message());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// LOG_DEBUG(Common_Filesystem, "Successfully removed the file at path={}",
|
||||||
|
// PathToUTF8String(path));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RenameFile(const fs::path& old_path, const fs::path& new_path) {
|
||||||
|
if (!ValidatePath(old_path) || !ValidatePath(new_path)) {
|
||||||
|
// LOG_ERROR(Common_Filesystem,
|
||||||
|
// "One or both input path(s) is not valid, old_path={}, new_path={}",
|
||||||
|
// PathToUTF8String(old_path), PathToUTF8String(new_path));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Exists(old_path)) {
|
||||||
|
// LOG_ERROR(Common_Filesystem, "Filesystem object at old_path={} does not exist",
|
||||||
|
// PathToUTF8String(old_path));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!IsFile(old_path)) {
|
||||||
|
// LOG_ERROR(Common_Filesystem, "Filesystem object at old_path={} is not a file",
|
||||||
|
// PathToUTF8String(old_path));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Exists(new_path)) {
|
||||||
|
// LOG_ERROR(Common_Filesystem, "Filesystem object at new_path={} exists",
|
||||||
|
// PathToUTF8String(new_path));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::error_code ec;
|
||||||
|
|
||||||
|
fs::rename(old_path, new_path, ec);
|
||||||
|
|
||||||
|
if (ec) {
|
||||||
|
// LOG_ERROR(Common_Filesystem,
|
||||||
|
// "Failed to rename the file from old_path={} to new_path={}, ec_message={}",
|
||||||
|
// PathToUTF8String(old_path), PathToUTF8String(new_path), ec.message());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// LOG_DEBUG(Common_Filesystem, "Successfully renamed the file from old_path={} to new_path={}",
|
||||||
|
// PathToUTF8String(old_path), PathToUTF8String(new_path));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<IOFile> FileOpen(const fs::path& path, FileAccessMode mode, FileType type,
|
||||||
|
FileShareFlag flag) {
|
||||||
|
if (!ValidatePath(path)) {
|
||||||
|
// LOG_ERROR(Common_Filesystem, "Input path is not valid, path={}", PathToUTF8String(path));
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Exists(path) && !IsFile(path)) {
|
||||||
|
// LOG_ERROR(Common_Filesystem,
|
||||||
|
// "Filesystem object at path={} exists and is not a regular file",
|
||||||
|
// PathToUTF8String(path));
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto io_file = std::make_shared<IOFile>(path, mode, type, flag);
|
||||||
|
|
||||||
|
if (!io_file->IsOpen()) {
|
||||||
|
io_file.reset();
|
||||||
|
|
||||||
|
// LOG_ERROR(Common_Filesystem,
|
||||||
|
// "Failed to open the file at path={} with mode={}, type={}, flag={}",
|
||||||
|
// PathToUTF8String(path), mode, type, flag);
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// LOG_DEBUG(Common_Filesystem,
|
||||||
|
// "Successfully opened the file at path={} with mode={}, type={}, flag={}",
|
||||||
|
// PathToUTF8String(path), mode, type, flag);
|
||||||
|
|
||||||
|
return io_file;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Directory Operations
|
||||||
|
|
||||||
|
bool CreateDir(const fs::path& path) {
|
||||||
|
if (!ValidatePath(path)) {
|
||||||
|
// LOG_ERROR(Common_Filesystem, "Input path is not valid, path={}",
|
||||||
|
// PathToUTF8String(path));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Exists(path.parent_path())) {
|
||||||
|
// LOG_ERROR(Common_Filesystem, "Parent directory of path={} does not exist",
|
||||||
|
// PathToUTF8String(path));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsDir(path)) {
|
||||||
|
// LOG_DEBUG(Common_Filesystem, "Filesystem object at path={} exists and is a directory",
|
||||||
|
// PathToUTF8String(path));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::error_code ec;
|
||||||
|
|
||||||
|
fs::create_directory(path, ec);
|
||||||
|
|
||||||
|
if (ec) {
|
||||||
|
// LOG_ERROR(Common_Filesystem, "Failed to create the directory at path={}, ec_message={}",
|
||||||
|
// PathToUTF8String(path), ec.message());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// LOG_DEBUG(Common_Filesystem, "Successfully created the directory at path={}",
|
||||||
|
// PathToUTF8String(path));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CreateDirs(const fs::path& path) {
|
||||||
|
if (!ValidatePath(path)) {
|
||||||
|
// LOG_ERROR(Common_Filesystem, "Input path is not valid, path={}", PathToUTF8String(path));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsDir(path)) {
|
||||||
|
// LOG_DEBUG(Common_Filesystem, "Filesystem object at path={} exists and is a directory",
|
||||||
|
// PathToUTF8String(path));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::error_code ec;
|
||||||
|
|
||||||
|
fs::create_directories(path, ec);
|
||||||
|
|
||||||
|
if (ec) {
|
||||||
|
// LOG_ERROR(Common_Filesystem, "Failed to create the directories at path={},
|
||||||
|
// ec_message={}",
|
||||||
|
// PathToUTF8String(path), ec.message());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// LOG_DEBUG(Common_Filesystem, "Successfully created the directories at path={}",
|
||||||
|
// PathToUTF8String(path));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CreateParentDir(const fs::path& path) {
|
||||||
|
return CreateDir(path.parent_path());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CreateParentDirs(const fs::path& path) {
|
||||||
|
return CreateDirs(path.parent_path());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RemoveDir(const fs::path& path) {
|
||||||
|
if (!ValidatePath(path)) {
|
||||||
|
// LOG_ERROR(Common_Filesystem, "Input path is not valid, path={}", PathToUTF8String(path));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Exists(path)) {
|
||||||
|
// LOG_DEBUG(Common_Filesystem, "Filesystem object at path={} does not exist",
|
||||||
|
// PathToUTF8String(path));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!IsDir(path)) {
|
||||||
|
// LOG_ERROR(Common_Filesystem, "Filesystem object at path={} is not a directory",
|
||||||
|
// PathToUTF8String(path));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::error_code ec;
|
||||||
|
|
||||||
|
fs::remove(path, ec);
|
||||||
|
|
||||||
|
if (ec) {
|
||||||
|
// LOG_ERROR(Common_Filesystem, "Failed to remove the directory at path={}, ec_message={}",
|
||||||
|
// PathToUTF8String(path), ec.message());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// LOG_DEBUG(Common_Filesystem, "Successfully removed the directory at path={}",
|
||||||
|
// PathToUTF8String(path));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RemoveDirRecursively(const fs::path& path) {
|
||||||
|
if (!ValidatePath(path)) {
|
||||||
|
// LOG_ERROR(Common_Filesystem, "Input path is not valid, path={}", PathToUTF8String(path));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Exists(path)) {
|
||||||
|
// LOG_DEBUG(Common_Filesystem, "Filesystem object at path={} does not exist",
|
||||||
|
// PathToUTF8String(path));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!IsDir(path)) {
|
||||||
|
// LOG_ERROR(Common_Filesystem, "Filesystem object at path={} is not a directory",
|
||||||
|
// PathToUTF8String(path));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::error_code ec;
|
||||||
|
|
||||||
|
fs::remove_all(path, ec);
|
||||||
|
|
||||||
|
if (ec) {
|
||||||
|
// LOG_ERROR(Common_Filesystem,
|
||||||
|
// "Failed to remove the directory and its contents at path={}, ec_message={}",
|
||||||
|
// PathToUTF8String(path), ec.message());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// LOG_DEBUG(Common_Filesystem, "Successfully removed the directory and its contents at
|
||||||
|
// path={}",
|
||||||
|
// PathToUTF8String(path));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RemoveDirContentsRecursively(const fs::path& path) {
|
||||||
|
if (!ValidatePath(path)) {
|
||||||
|
// LOG_ERROR(Common_Filesystem, "Input path is not valid, path={}",
|
||||||
|
// PathToUTF8String(path));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Exists(path)) {
|
||||||
|
// LOG_DEBUG(Common_Filesystem, "Filesystem object at path={} does not exist",
|
||||||
|
// PathToUTF8String(path));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!IsDir(path)) {
|
||||||
|
// LOG_ERROR(Common_Filesystem, "Filesystem object at path={} is not a directory",
|
||||||
|
// PathToUTF8String(path));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::error_code ec;
|
||||||
|
|
||||||
|
// TODO (Morph): Replace this with recursive_directory_iterator once it's fixed in MSVC.
|
||||||
|
for (const auto& entry : fs::directory_iterator(path, ec)) {
|
||||||
|
if (ec) {
|
||||||
|
// LOG_ERROR(Common_Filesystem,
|
||||||
|
// "Failed to completely enumerate the directory at path={}, ec_message={}",
|
||||||
|
// PathToUTF8String(path), ec.message());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
fs::remove(entry.path(), ec);
|
||||||
|
|
||||||
|
if (ec) {
|
||||||
|
// LOG_ERROR(Common_Filesystem,
|
||||||
|
// "Failed to remove the filesystem object at path={}, ec_message={}",
|
||||||
|
// PathToUTF8String(entry.path()), ec.message());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO (Morph): Remove this when MSVC fixes recursive_directory_iterator.
|
||||||
|
// recursive_directory_iterator throws an exception despite passing in a std::error_code.
|
||||||
|
if (entry.status().type() == fs::file_type::directory) {
|
||||||
|
return RemoveDirContentsRecursively(entry.path());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ec) {
|
||||||
|
// LOG_ERROR(Common_Filesystem,
|
||||||
|
// "Failed to remove all the contents of the directory at path={}, ec_message={}",
|
||||||
|
// PathToUTF8String(path), ec.message());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// LOG_DEBUG(Common_Filesystem,
|
||||||
|
// "Successfully removed all the contents of the directory at path={}",
|
||||||
|
// PathToUTF8String(path));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RenameDir(const fs::path& old_path, const fs::path& new_path) {
|
||||||
|
if (!ValidatePath(old_path) || !ValidatePath(new_path)) {
|
||||||
|
// LOG_ERROR(Common_Filesystem,
|
||||||
|
// "One or both input path(s) is not valid, old_path={}, new_path={}",
|
||||||
|
// PathToUTF8String(old_path), PathToUTF8String(new_path));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Exists(old_path)) {
|
||||||
|
// LOG_ERROR(Common_Filesystem, "Filesystem object at old_path={} does not exist",
|
||||||
|
// PathToUTF8String(old_path));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!IsDir(old_path)) {
|
||||||
|
// LOG_ERROR(Common_Filesystem, "Filesystem object at old_path={} is not a directory",
|
||||||
|
// PathToUTF8String(old_path));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Exists(new_path)) {
|
||||||
|
// LOG_ERROR(Common_Filesystem, "Filesystem object at new_path={} exists",
|
||||||
|
// PathToUTF8String(new_path));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::error_code ec;
|
||||||
|
|
||||||
|
fs::rename(old_path, new_path, ec);
|
||||||
|
|
||||||
|
if (ec) {
|
||||||
|
// LOG_ERROR(Common_Filesystem,
|
||||||
|
// "Failed to rename the file from old_path={} to new_path={}, ec_message={}",
|
||||||
|
// PathToUTF8String(old_path), PathToUTF8String(new_path), ec.message());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// LOG_DEBUG(Common_Filesystem, "Successfully renamed the file from old_path={} to new_path={}",
|
||||||
|
// PathToUTF8String(old_path), PathToUTF8String(new_path));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IterateDirEntries(const std::filesystem::path& path, const DirEntryCallable& callback,
|
||||||
|
DirEntryFilter filter) {
|
||||||
|
if (!ValidatePath(path)) {
|
||||||
|
// LOG_ERROR(Common_Filesystem, "Input path is not valid, path={}", PathToUTF8String(path));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Exists(path)) {
|
||||||
|
// LOG_ERROR(Common_Filesystem, "Filesystem object at path={} does not exist",
|
||||||
|
// PathToUTF8String(path));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!IsDir(path)) {
|
||||||
|
// LOG_ERROR(Common_Filesystem, "Filesystem object at path={} is not a directory",
|
||||||
|
// PathToUTF8String(path));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool callback_error = false;
|
||||||
|
|
||||||
|
std::error_code ec;
|
||||||
|
|
||||||
|
for (const auto& entry : fs::directory_iterator(path, ec)) {
|
||||||
|
if (ec) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (True(filter & DirEntryFilter::File) &&
|
||||||
|
entry.status().type() == fs::file_type::regular) {
|
||||||
|
if (!callback(entry)) {
|
||||||
|
callback_error = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (True(filter & DirEntryFilter::Directory) &&
|
||||||
|
entry.status().type() == fs::file_type::directory) {
|
||||||
|
if (!callback(entry)) {
|
||||||
|
callback_error = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (callback_error || ec) {
|
||||||
|
// LOG_ERROR(Common_Filesystem,
|
||||||
|
// "Failed to visit all the directory entries of path={}, ec_message={}",
|
||||||
|
// PathToUTF8String(path), ec.message());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//LOG_DEBUG(Common_Filesystem, "Successfully visited all the directory entries of path={}",
|
||||||
|
// PathToUTF8String(path));
|
||||||
|
}
|
||||||
|
|
||||||
|
void IterateDirEntriesRecursively(const std::filesystem::path& path,
|
||||||
|
const DirEntryCallable& callback, DirEntryFilter filter) {
|
||||||
|
if (!ValidatePath(path)) {
|
||||||
|
// LOG_ERROR(Common_Filesystem, "Input path is not valid, path={}", PathToUTF8String(path));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Exists(path)) {
|
||||||
|
// LOG_ERROR(Common_Filesystem, "Filesystem object at path={} does not exist",
|
||||||
|
// PathToUTF8String(path));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!IsDir(path)) {
|
||||||
|
// LOG_ERROR(Common_Filesystem, "Filesystem object at path={} is not a directory",
|
||||||
|
// PathToUTF8String(path));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool callback_error = false;
|
||||||
|
|
||||||
|
std::error_code ec;
|
||||||
|
|
||||||
|
// TODO (Morph): Replace this with recursive_directory_iterator once it's fixed in MSVC.
|
||||||
|
for (const auto& entry : fs::directory_iterator(path, ec)) {
|
||||||
|
if (ec) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (True(filter & DirEntryFilter::File) &&
|
||||||
|
entry.status().type() == fs::file_type::regular) {
|
||||||
|
if (!callback(entry)) {
|
||||||
|
callback_error = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (True(filter & DirEntryFilter::Directory) &&
|
||||||
|
entry.status().type() == fs::file_type::directory) {
|
||||||
|
if (!callback(entry)) {
|
||||||
|
callback_error = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO (Morph): Remove this when MSVC fixes recursive_directory_iterator.
|
||||||
|
// recursive_directory_iterator throws an exception despite passing in a std::error_code.
|
||||||
|
if (entry.status().type() == fs::file_type::directory) {
|
||||||
|
IterateDirEntriesRecursively(entry.path(), callback, filter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (callback_error || ec) {
|
||||||
|
//LOG_ERROR(Common_Filesystem,
|
||||||
|
// "Failed to visit all the directory entries of path={}, ec_message={}",
|
||||||
|
// PathToUTF8String(path), ec.message());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//LOG_DEBUG(Common_Filesystem, "Successfully visited all the directory entries of path={}",
|
||||||
|
// PathToUTF8String(path));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generic Filesystem Operations
|
||||||
|
|
||||||
|
bool Exists(const fs::path& path) {
|
||||||
|
std::error_code ec;
|
||||||
|
#ifdef ANDROID
|
||||||
|
if (Android::IsContentUri(path)) {
|
||||||
|
return Android::Exists(path);
|
||||||
|
} else {
|
||||||
|
return fs::exists(path, ec);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
return fs::exists(path, ec);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsFile(const fs::path& path) {
|
||||||
|
std::error_code ec;
|
||||||
|
#ifdef ANDROID
|
||||||
|
if (Android::IsContentUri(path)) {
|
||||||
|
return !Android::IsDirectory(path);
|
||||||
|
} else {
|
||||||
|
return fs::is_regular_file(path, ec);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
return fs::is_regular_file(path, ec);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsDir(const fs::path& path) {
|
||||||
|
std::error_code ec;
|
||||||
|
#ifdef ANDROID
|
||||||
|
if (Android::IsContentUri(path)) {
|
||||||
|
return Android::IsDirectory(path);
|
||||||
|
} else {
|
||||||
|
return fs::is_directory(path, ec);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
return fs::is_directory(path, ec);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
fs::path GetCurrentDir() {
|
||||||
|
std::error_code ec;
|
||||||
|
|
||||||
|
const auto current_path = fs::current_path(ec);
|
||||||
|
|
||||||
|
if (ec) {
|
||||||
|
// LOG_ERROR(Common_Filesystem, "Failed to get the current path, ec_message={}", ec.message());
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
return current_path;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SetCurrentDir(const fs::path& path) {
|
||||||
|
std::error_code ec;
|
||||||
|
|
||||||
|
fs::current_path(path, ec);
|
||||||
|
|
||||||
|
if (ec) {
|
||||||
|
// LOG_ERROR(Common_Filesystem, "Failed to set the current path to path={}, ec_message={}",
|
||||||
|
// PathToUTF8String(path), ec.message());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
fs::file_type GetEntryType(const fs::path& path) {
|
||||||
|
std::error_code ec;
|
||||||
|
|
||||||
|
const auto file_status = fs::status(path, ec);
|
||||||
|
|
||||||
|
if (ec) {
|
||||||
|
// LOG_ERROR(Common_Filesystem, "Failed to retrieve the entry type of path={}, ec_message={}",
|
||||||
|
// PathToUTF8String(path), ec.message());
|
||||||
|
return fs::file_type::not_found;
|
||||||
|
}
|
||||||
|
|
||||||
|
return file_status.type();
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
u64 GetSize(const fs::path& path) {
|
||||||
|
#ifdef ANDROID
|
||||||
|
if (Android::IsContentUri(path)) {
|
||||||
|
return Android::GetSize(path);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
std::error_code ec;
|
||||||
|
|
||||||
|
const auto file_size = fs::file_size(path, ec);
|
||||||
|
|
||||||
|
if (ec) {
|
||||||
|
LOG_ERROR(Common_Filesystem, "Failed to retrieve the file size of path={}, ec_message={}",
|
||||||
|
PathToUTF8String(path), ec.message());
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return file_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 GetFreeSpaceSize(const fs::path& path) {
|
||||||
|
std::error_code ec;
|
||||||
|
|
||||||
|
const auto space_info = fs::space(path, ec);
|
||||||
|
|
||||||
|
if (ec) {
|
||||||
|
LOG_ERROR(Common_Filesystem,
|
||||||
|
"Failed to retrieve the available free space of path={}, ec_message={}",
|
||||||
|
PathToUTF8String(path), ec.message());
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return space_info.free;
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 GetTotalSpaceSize(const fs::path& path) {
|
||||||
|
std::error_code ec;
|
||||||
|
|
||||||
|
const auto space_info = fs::space(path, ec);
|
||||||
|
|
||||||
|
if (ec) {
|
||||||
|
LOG_ERROR(Common_Filesystem,
|
||||||
|
"Failed to retrieve the total capacity of path={}, ec_message={}",
|
||||||
|
PathToUTF8String(path), ec.message());
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return space_info.capacity;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
} // namespace Common::FS
|
|
@ -0,0 +1,658 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
|
#include <memory>
|
||||||
|
#include <functional>
|
||||||
|
#include "io_file.h"
|
||||||
|
|
||||||
|
namespace Common::FS {
|
||||||
|
|
||||||
|
#define DECLARE_ENUM_FLAG_OPERATORS(type) \
|
||||||
|
[[nodiscard]] constexpr type operator|(type a, type b) noexcept { \
|
||||||
|
using T = std::underlying_type_t<type>; \
|
||||||
|
return static_cast<type>(static_cast<T>(a) | static_cast<T>(b)); \
|
||||||
|
} \
|
||||||
|
[[nodiscard]] constexpr type operator&(type a, type b) noexcept { \
|
||||||
|
using T = std::underlying_type_t<type>; \
|
||||||
|
return static_cast<type>(static_cast<T>(a) & static_cast<T>(b)); \
|
||||||
|
} \
|
||||||
|
[[nodiscard]] constexpr type operator^(type a, type b) noexcept { \
|
||||||
|
using T = std::underlying_type_t<type>; \
|
||||||
|
return static_cast<type>(static_cast<T>(a) ^ static_cast<T>(b)); \
|
||||||
|
} \
|
||||||
|
[[nodiscard]] constexpr type operator<<(type a, type b) noexcept { \
|
||||||
|
using T = std::underlying_type_t<type>; \
|
||||||
|
return static_cast<type>(static_cast<T>(a) << static_cast<T>(b)); \
|
||||||
|
} \
|
||||||
|
[[nodiscard]] constexpr type operator>>(type a, type b) noexcept { \
|
||||||
|
using T = std::underlying_type_t<type>; \
|
||||||
|
return static_cast<type>(static_cast<T>(a) >> static_cast<T>(b)); \
|
||||||
|
} \
|
||||||
|
constexpr type& operator|=(type& a, type b) noexcept { \
|
||||||
|
a = a | b; \
|
||||||
|
return a; \
|
||||||
|
} \
|
||||||
|
constexpr type& operator&=(type& a, type b) noexcept { \
|
||||||
|
a = a & b; \
|
||||||
|
return a; \
|
||||||
|
} \
|
||||||
|
constexpr type& operator^=(type& a, type b) noexcept { \
|
||||||
|
a = a ^ b; \
|
||||||
|
return a; \
|
||||||
|
} \
|
||||||
|
constexpr type& operator<<=(type& a, type b) noexcept { \
|
||||||
|
a = a << b; \
|
||||||
|
return a; \
|
||||||
|
} \
|
||||||
|
constexpr type& operator>>=(type& a, type b) noexcept { \
|
||||||
|
a = a >> b; \
|
||||||
|
return a; \
|
||||||
|
} \
|
||||||
|
[[nodiscard]] constexpr type operator~(type key) noexcept { \
|
||||||
|
using T = std::underlying_type_t<type>; \
|
||||||
|
return static_cast<type>(~static_cast<T>(key)); \
|
||||||
|
} \
|
||||||
|
[[nodiscard]] constexpr bool True(type key) noexcept { \
|
||||||
|
using T = std::underlying_type_t<type>; \
|
||||||
|
return static_cast<T>(key) != 0; \
|
||||||
|
} \
|
||||||
|
[[nodiscard]] constexpr bool False(type key) noexcept { \
|
||||||
|
using T = std::underlying_type_t<type>; \
|
||||||
|
return static_cast<T>(key) == 0; \
|
||||||
|
}
|
||||||
|
|
||||||
|
class IOFile;
|
||||||
|
|
||||||
|
enum class DirEntryFilter {
|
||||||
|
File = 1 << 0,
|
||||||
|
Directory = 1 << 1,
|
||||||
|
All = File | Directory,
|
||||||
|
};
|
||||||
|
DECLARE_ENUM_FLAG_OPERATORS(DirEntryFilter);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A callback function which takes in the path of a directory entry.
|
||||||
|
*
|
||||||
|
* @param path The path of a directory entry
|
||||||
|
*
|
||||||
|
* @returns A boolean value.
|
||||||
|
* Return true to indicate whether the callback is successful, false otherwise.
|
||||||
|
*/
|
||||||
|
using DirEntryCallable = std::function<bool(const std::filesystem::directory_entry& entry)>;
|
||||||
|
|
||||||
|
|
||||||
|
// File Operations
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new file at path with the specified size.
|
||||||
|
*
|
||||||
|
* Failures occur when:
|
||||||
|
* - Input path is not valid
|
||||||
|
* - The input path's parent directory does not exist
|
||||||
|
* - Filesystem object at path exists
|
||||||
|
* - Filesystem at path is read only
|
||||||
|
*
|
||||||
|
* @param path Filesystem path
|
||||||
|
* @param size File size
|
||||||
|
*
|
||||||
|
* @returns True if the file creation succeeds, false otherwise.
|
||||||
|
*/
|
||||||
|
[[nodiscard]] bool NewFile(const std::filesystem::path& path, u64 size = 0);
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
template <typename Path>
|
||||||
|
[[nodiscard]] bool NewFile(const Path& path, u64 size = 0) {
|
||||||
|
if constexpr (IsChar<typename Path::value_type>) {
|
||||||
|
return NewFile(ToU8String(path), size);
|
||||||
|
} else {
|
||||||
|
return NewFile(std::filesystem::path{path}, size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes a file at path.
|
||||||
|
*
|
||||||
|
* Failures occur when:
|
||||||
|
* - Input path is not valid
|
||||||
|
* - Filesystem object at path is not a regular file
|
||||||
|
* - Filesystem at path is read only
|
||||||
|
*
|
||||||
|
* @param path Filesystem path
|
||||||
|
*
|
||||||
|
* @returns True if file removal succeeds or file does not exist, false otherwise.
|
||||||
|
*/
|
||||||
|
bool RemoveFile(const std::filesystem::path& path);
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
template <typename Path>
|
||||||
|
bool RemoveFile(const Path& path) {
|
||||||
|
if constexpr (IsChar<typename Path::value_type>) {
|
||||||
|
return RemoveFile(ToU8String(path));
|
||||||
|
} else {
|
||||||
|
return RemoveFile(std::filesystem::path{path});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renames a file from old_path to new_path.
|
||||||
|
*
|
||||||
|
* Failures occur when:
|
||||||
|
* - One or both input path(s) is not valid
|
||||||
|
* - Filesystem object at old_path does not exist
|
||||||
|
* - Filesystem object at old_path is not a regular file
|
||||||
|
* - Filesystem object at new_path exists
|
||||||
|
* - Filesystem at either path is read only
|
||||||
|
*
|
||||||
|
* @param old_path Old filesystem path
|
||||||
|
* @param new_path New filesystem path
|
||||||
|
*
|
||||||
|
* @returns True if file rename succeeds, false otherwise.
|
||||||
|
*/
|
||||||
|
[[nodiscard]] bool RenameFile(const std::filesystem::path& old_path,
|
||||||
|
const std::filesystem::path& new_path);
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
template <typename Path1, typename Path2>
|
||||||
|
[[nodiscard]] bool RenameFile(const Path1& old_path, const Path2& new_path) {
|
||||||
|
using ValueType1 = typename Path1::value_type;
|
||||||
|
using ValueType2 = typename Path2::value_type;
|
||||||
|
if constexpr (IsChar<ValueType1> && IsChar<ValueType2>) {
|
||||||
|
return RenameFile(ToU8String(old_path), ToU8String(new_path));
|
||||||
|
} else if constexpr (IsChar<ValueType1> && !IsChar<ValueType2>) {
|
||||||
|
return RenameFile(ToU8String(old_path), new_path);
|
||||||
|
} else if constexpr (!IsChar<ValueType1> && IsChar<ValueType2>) {
|
||||||
|
return RenameFile(old_path, ToU8String(new_path));
|
||||||
|
} else {
|
||||||
|
return RenameFile(std::filesystem::path{old_path}, std::filesystem::path{new_path});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opens a file at path with the specified file access mode.
|
||||||
|
* This function behaves differently depending on the FileAccessMode.
|
||||||
|
* These behaviors are documented in each enum value of FileAccessMode.
|
||||||
|
*
|
||||||
|
* Failures occur when:
|
||||||
|
* - Input path is not valid
|
||||||
|
* - Filesystem object at path exists and is not a regular file
|
||||||
|
* - The file is not open
|
||||||
|
*
|
||||||
|
* @param path Filesystem path
|
||||||
|
* @param mode File access mode
|
||||||
|
* @param type File type, default is BinaryFile. Use TextFile to open the file as a text file
|
||||||
|
* @param flag (Windows only) File-share access flag, default is ShareReadOnly
|
||||||
|
*
|
||||||
|
* @returns A shared pointer to the opened file. Returns nullptr on failure.
|
||||||
|
*/
|
||||||
|
[[nodiscard]] std::shared_ptr<IOFile> FileOpen(const std::filesystem::path& path,
|
||||||
|
FileAccessMode mode,
|
||||||
|
FileType type = FileType::BinaryFile,
|
||||||
|
FileShareFlag flag = FileShareFlag::ShareReadOnly);
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
template <typename Path>
|
||||||
|
[[nodiscard]] std::shared_ptr<IOFile> FileOpen(const Path& path, FileAccessMode mode,
|
||||||
|
FileType type = FileType::BinaryFile,
|
||||||
|
FileShareFlag flag = FileShareFlag::ShareReadOnly) {
|
||||||
|
if constexpr (IsChar<typename Path::value_type>) {
|
||||||
|
return FileOpen(ToU8String(path), mode, type, flag);
|
||||||
|
} else {
|
||||||
|
return FileOpen(std::filesystem::path{path}, mode, type, flag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Directory Operations
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a directory at path.
|
||||||
|
* Note that this function will *always* assume that the input path is a directory. For example,
|
||||||
|
* if the input path is /path/to/directory/file.txt, it will create a directory called "file.txt".
|
||||||
|
* If you intend to create the parent directory of a file, use CreateParentDir instead.
|
||||||
|
*
|
||||||
|
* Failures occur when:
|
||||||
|
* - Input path is not valid
|
||||||
|
* - The input path's parent directory does not exist
|
||||||
|
* - Filesystem at path is read only
|
||||||
|
*
|
||||||
|
* @param path Filesystem path
|
||||||
|
*
|
||||||
|
* @returns True if directory creation succeeds or directory already exists, false otherwise.
|
||||||
|
*/
|
||||||
|
[[nodiscard]] bool CreateDir(const std::filesystem::path& path);
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
template <typename Path>
|
||||||
|
[[nodiscard]] bool CreateDir(const Path& path) {
|
||||||
|
if constexpr (IsChar<typename Path::value_type>) {
|
||||||
|
return CreateDir(ToU8String(path));
|
||||||
|
} else {
|
||||||
|
return CreateDir(std::filesystem::path{path});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recursively creates a directory at path.
|
||||||
|
* Note that this function will *always* assume that the input path is a directory. For example,
|
||||||
|
* if the input path is /path/to/directory/file.txt, it will create a directory called "file.txt".
|
||||||
|
* If you intend to create the parent directory of a file, use CreateParentDirs instead.
|
||||||
|
* Unlike CreateDir, this creates all of input path's parent directories if they do not exist.
|
||||||
|
*
|
||||||
|
* Failures occur when:
|
||||||
|
* - Input path is not valid
|
||||||
|
* - Filesystem at path is read only
|
||||||
|
*
|
||||||
|
* @param path Filesystem path
|
||||||
|
*
|
||||||
|
* @returns True if directory creation succeeds or directory already exists, false otherwise.
|
||||||
|
*/
|
||||||
|
[[nodiscard]] bool CreateDirs(const std::filesystem::path& path);
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
template <typename Path>
|
||||||
|
[[nodiscard]] bool CreateDirs(const Path& path) {
|
||||||
|
if constexpr (IsChar<typename Path::value_type>) {
|
||||||
|
return CreateDirs(ToU8String(path));
|
||||||
|
} else {
|
||||||
|
return CreateDirs(std::filesystem::path{path});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the parent directory of a given path.
|
||||||
|
* This function calls CreateDir(path.parent_path()), see CreateDir for more details.
|
||||||
|
*
|
||||||
|
* @param path Filesystem path
|
||||||
|
*
|
||||||
|
* @returns True if directory creation succeeds or directory already exists, false otherwise.
|
||||||
|
*/
|
||||||
|
[[nodiscard]] bool CreateParentDir(const std::filesystem::path& path);
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
template <typename Path>
|
||||||
|
[[nodiscard]] bool CreateParentDir(const Path& path) {
|
||||||
|
if constexpr (IsChar<typename Path::value_type>) {
|
||||||
|
return CreateParentDir(ToU8String(path));
|
||||||
|
} else {
|
||||||
|
return CreateParentDir(std::filesystem::path{path});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recursively creates the parent directory of a given path.
|
||||||
|
* This function calls CreateDirs(path.parent_path()), see CreateDirs for more details.
|
||||||
|
*
|
||||||
|
* @param path Filesystem path
|
||||||
|
*
|
||||||
|
* @returns True if directory creation succeeds or directory already exists, false otherwise.
|
||||||
|
*/
|
||||||
|
[[nodiscard]] bool CreateParentDirs(const std::filesystem::path& path);
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
template <typename Path>
|
||||||
|
[[nodiscard]] bool CreateParentDirs(const Path& path) {
|
||||||
|
if constexpr (IsChar<typename Path::value_type>) {
|
||||||
|
return CreateParentDirs(ToU8String(path));
|
||||||
|
} else {
|
||||||
|
return CreateParentDirs(std::filesystem::path{path});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes a directory at path.
|
||||||
|
*
|
||||||
|
* Failures occur when:
|
||||||
|
* - Input path is not valid
|
||||||
|
* - Filesystem object at path is not a directory
|
||||||
|
* - The given directory is not empty
|
||||||
|
* - Filesystem at path is read only
|
||||||
|
*
|
||||||
|
* @param path Filesystem path
|
||||||
|
*
|
||||||
|
* @returns True if directory removal succeeds or directory does not exist, false otherwise.
|
||||||
|
*/
|
||||||
|
bool RemoveDir(const std::filesystem::path& path);
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
template <typename Path>
|
||||||
|
bool RemoveDir(const Path& path) {
|
||||||
|
if constexpr (IsChar<typename Path::value_type>) {
|
||||||
|
return RemoveDir(ToU8String(path));
|
||||||
|
} else {
|
||||||
|
return RemoveDir(std::filesystem::path{path});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes all the contents within the given directory and removes the directory itself.
|
||||||
|
*
|
||||||
|
* Failures occur when:
|
||||||
|
* - Input path is not valid
|
||||||
|
* - Filesystem object at path is not a directory
|
||||||
|
* - Filesystem at path is read only
|
||||||
|
*
|
||||||
|
* @param path Filesystem path
|
||||||
|
*
|
||||||
|
* @returns True if the directory and all of its contents are removed successfully, false otherwise.
|
||||||
|
*/
|
||||||
|
bool RemoveDirRecursively(const std::filesystem::path& path);
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
template <typename Path>
|
||||||
|
bool RemoveDirRecursively(const Path& path) {
|
||||||
|
if constexpr (IsChar<typename Path::value_type>) {
|
||||||
|
return RemoveDirRecursively(ToU8String(path));
|
||||||
|
} else {
|
||||||
|
return RemoveDirRecursively(std::filesystem::path{path});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes all the contents within the given directory without removing the directory itself.
|
||||||
|
*
|
||||||
|
* Failures occur when:
|
||||||
|
* - Input path is not valid
|
||||||
|
* - Filesystem object at path is not a directory
|
||||||
|
* - Filesystem at path is read only
|
||||||
|
*
|
||||||
|
* @param path Filesystem path
|
||||||
|
*
|
||||||
|
* @returns True if all of the directory's contents are removed successfully, false otherwise.
|
||||||
|
*/
|
||||||
|
bool RemoveDirContentsRecursively(const std::filesystem::path& path);
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
template <typename Path>
|
||||||
|
bool RemoveDirContentsRecursively(const Path& path) {
|
||||||
|
if constexpr (IsChar<typename Path::value_type>) {
|
||||||
|
return RemoveDirContentsRecursively(ToU8String(path));
|
||||||
|
} else {
|
||||||
|
return RemoveDirContentsRecursively(std::filesystem::path{path});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renames a directory from old_path to new_path.
|
||||||
|
*
|
||||||
|
* Failures occur when:
|
||||||
|
* - One or both input path(s) is not valid
|
||||||
|
* - Filesystem object at old_path does not exist
|
||||||
|
* - Filesystem object at old_path is not a directory
|
||||||
|
* - Filesystem object at new_path exists
|
||||||
|
* - Filesystem at either path is read only
|
||||||
|
*
|
||||||
|
* @param old_path Old filesystem path
|
||||||
|
* @param new_path New filesystem path
|
||||||
|
*
|
||||||
|
* @returns True if directory rename succeeds, false otherwise.
|
||||||
|
*/
|
||||||
|
[[nodiscard]] bool RenameDir(const std::filesystem::path& old_path,
|
||||||
|
const std::filesystem::path& new_path);
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
template <typename Path1, typename Path2>
|
||||||
|
[[nodiscard]] bool RenameDir(const Path1& old_path, const Path2& new_path) {
|
||||||
|
using ValueType1 = typename Path1::value_type;
|
||||||
|
using ValueType2 = typename Path2::value_type;
|
||||||
|
if constexpr (IsChar<ValueType1> && IsChar<ValueType2>) {
|
||||||
|
return RenameDir(ToU8String(old_path), ToU8String(new_path));
|
||||||
|
} else if constexpr (IsChar<ValueType1> && !IsChar<ValueType2>) {
|
||||||
|
return RenameDir(ToU8String(old_path), new_path);
|
||||||
|
} else if constexpr (!IsChar<ValueType1> && IsChar<ValueType2>) {
|
||||||
|
return RenameDir(old_path, ToU8String(new_path));
|
||||||
|
} else {
|
||||||
|
return RenameDir(std::filesystem::path{old_path}, std::filesystem::path{new_path});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Iterates over the directory entries of a given directory.
|
||||||
|
* This does not iterate over the sub-directories of the given directory.
|
||||||
|
* The DirEntryCallable callback is called for each visited directory entry.
|
||||||
|
* A filter can be set to control which directory entries are visited based on their type.
|
||||||
|
* By default, both files and directories are visited.
|
||||||
|
* If the callback returns false or there is an error, the iteration is immediately halted.
|
||||||
|
*
|
||||||
|
* Failures occur when:
|
||||||
|
* - Input path is not valid
|
||||||
|
* - Filesystem object at path is not a directory
|
||||||
|
*
|
||||||
|
* @param path Filesystem path
|
||||||
|
* @param callback Callback to be called for each visited directory entry
|
||||||
|
* @param filter Directory entry type filter
|
||||||
|
*/
|
||||||
|
void IterateDirEntries(const std::filesystem::path& path, const DirEntryCallable& callback,
|
||||||
|
DirEntryFilter filter = DirEntryFilter::All);
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
template <typename Path>
|
||||||
|
void IterateDirEntries(const Path& path, const DirEntryCallable& callback,
|
||||||
|
DirEntryFilter filter = DirEntryFilter::All) {
|
||||||
|
if constexpr (IsChar<typename Path::value_type>) {
|
||||||
|
IterateDirEntries(ToU8String(path), callback, filter);
|
||||||
|
} else {
|
||||||
|
IterateDirEntries(std::filesystem::path{path}, callback, filter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Iterates over the directory entries of a given directory and its sub-directories.
|
||||||
|
* The DirEntryCallable callback is called for each visited directory entry.
|
||||||
|
* A filter can be set to control which directory entries are visited based on their type.
|
||||||
|
* By default, both files and directories are visited.
|
||||||
|
* If the callback returns false or there is an error, the iteration is immediately halted.
|
||||||
|
*
|
||||||
|
* Failures occur when:
|
||||||
|
* - Input path is not valid
|
||||||
|
* - Filesystem object at path does not exist
|
||||||
|
* - Filesystem object at path is not a directory
|
||||||
|
*
|
||||||
|
* @param path Filesystem path
|
||||||
|
* @param callback Callback to be called for each visited directory entry
|
||||||
|
* @param filter Directory entry type filter
|
||||||
|
*/
|
||||||
|
void IterateDirEntriesRecursively(const std::filesystem::path& path,
|
||||||
|
const DirEntryCallable& callback,
|
||||||
|
DirEntryFilter filter = DirEntryFilter::All);
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
template <typename Path>
|
||||||
|
void IterateDirEntriesRecursively(const Path& path, const DirEntryCallable& callback,
|
||||||
|
DirEntryFilter filter = DirEntryFilter::All) {
|
||||||
|
if constexpr (IsChar<typename Path::value_type>) {
|
||||||
|
IterateDirEntriesRecursively(ToU8String(path), callback, filter);
|
||||||
|
} else {
|
||||||
|
IterateDirEntriesRecursively(std::filesystem::path{path}, callback, filter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Generic Filesystem Operations
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether a filesystem object at path exists.
|
||||||
|
*
|
||||||
|
* @param path Filesystem path
|
||||||
|
*
|
||||||
|
* @returns True if a filesystem object at path exists, false otherwise.
|
||||||
|
*/
|
||||||
|
[[nodiscard]] bool Exists(const std::filesystem::path& path);
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
template <typename Path>
|
||||||
|
[[nodiscard]] bool Exists(const Path& path) {
|
||||||
|
if constexpr (IsChar<typename Path::value_type>) {
|
||||||
|
return Exists(ToU8String(path));
|
||||||
|
} else {
|
||||||
|
return Exists(std::filesystem::path{path});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether a filesystem object at path is a regular file.
|
||||||
|
* A regular file is a file that stores text or binary data.
|
||||||
|
* It is not a directory, symlink, FIFO, socket, block device, or character device.
|
||||||
|
*
|
||||||
|
* @param path Filesystem path
|
||||||
|
*
|
||||||
|
* @returns True if a filesystem object at path is a regular file, false otherwise.
|
||||||
|
*/
|
||||||
|
[[nodiscard]] bool IsFile(const std::filesystem::path& path);
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
template <typename Path>
|
||||||
|
[[nodiscard]] bool IsFile(const Path& path) {
|
||||||
|
if constexpr (IsChar<typename Path::value_type>) {
|
||||||
|
return IsFile(ToU8String(path));
|
||||||
|
} else {
|
||||||
|
return IsFile(std::filesystem::path{path});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether a filesystem object at path is a directory.
|
||||||
|
*
|
||||||
|
* @param path Filesystem path
|
||||||
|
*
|
||||||
|
* @returns True if a filesystem object at path is a directory, false otherwise.
|
||||||
|
*/
|
||||||
|
[[nodiscard]] bool IsDir(const std::filesystem::path& path);
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
template <typename Path>
|
||||||
|
[[nodiscard]] bool IsDir(const Path& path) {
|
||||||
|
if constexpr (IsChar<typename Path::value_type>) {
|
||||||
|
return IsDir(ToU8String(path));
|
||||||
|
} else {
|
||||||
|
return IsDir(std::filesystem::path{path});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the current working directory.
|
||||||
|
*
|
||||||
|
* @returns The current working directory. Returns an empty path on failure.
|
||||||
|
*/
|
||||||
|
[[nodiscard]] std::filesystem::path GetCurrentDir();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the current working directory to path.
|
||||||
|
*
|
||||||
|
* @returns True if the current working directory is successfully set, false otherwise.
|
||||||
|
*/
|
||||||
|
[[nodiscard]] bool SetCurrentDir(const std::filesystem::path& path);
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
template <typename Path>
|
||||||
|
[[nodiscard]] bool SetCurrentDir(const Path& path) {
|
||||||
|
if constexpr (IsChar<typename Path::value_type>) {
|
||||||
|
return SetCurrentDir(ToU8String(path));
|
||||||
|
} else {
|
||||||
|
return SetCurrentDir(std::filesystem::path{path});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the entry type of the filesystem object at path.
|
||||||
|
*
|
||||||
|
* @param path Filesystem path
|
||||||
|
*
|
||||||
|
* @returns The entry type of the filesystem object. Returns file_type::not_found on failure.
|
||||||
|
*/
|
||||||
|
[[nodiscard]] std::filesystem::file_type GetEntryType(const std::filesystem::path& path);
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
template <typename Path>
|
||||||
|
[[nodiscard]] std::filesystem::file_type GetEntryType(const Path& path) {
|
||||||
|
if constexpr (IsChar<typename Path::value_type>) {
|
||||||
|
return GetEntryType(ToU8String(path));
|
||||||
|
} else {
|
||||||
|
return GetEntryType(std::filesystem::path{path});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
/**
|
||||||
|
* Gets the size of the filesystem object at path.
|
||||||
|
*
|
||||||
|
* @param path Filesystem path
|
||||||
|
*
|
||||||
|
* @returns The size in bytes of the filesystem object. Returns 0 on failure.
|
||||||
|
*/
|
||||||
|
[[nodiscard]] u64 GetSize(const std::filesystem::path& path);
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
template <typename Path>
|
||||||
|
[[nodiscard]] u64 GetSize(const Path& path) {
|
||||||
|
if constexpr (IsChar<typename Path::value_type>) {
|
||||||
|
return GetSize(ToU8String(path));
|
||||||
|
} else {
|
||||||
|
return GetSize(std::filesystem::path{path});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the free space size of the filesystem at path.
|
||||||
|
*
|
||||||
|
* @param path Filesystem path
|
||||||
|
*
|
||||||
|
* @returns The free space size in bytes of the filesystem at path. Returns 0 on failure.
|
||||||
|
*/
|
||||||
|
[[nodiscard]] u64 GetFreeSpaceSize(const std::filesystem::path& path);
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
template <typename Path>
|
||||||
|
[[nodiscard]] u64 GetFreeSpaceSize(const Path& path) {
|
||||||
|
if constexpr (IsChar<typename Path::value_type>) {
|
||||||
|
return GetFreeSpaceSize(ToU8String(path));
|
||||||
|
} else {
|
||||||
|
return GetFreeSpaceSize(std::filesystem::path{path});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the total capacity of the filesystem at path.
|
||||||
|
*
|
||||||
|
* @param path Filesystem path
|
||||||
|
*
|
||||||
|
* @returns The total capacity in bytes of the filesystem at path. Returns 0 on failure.
|
||||||
|
*/
|
||||||
|
[[nodiscard]] u64 GetTotalSpaceSize(const std::filesystem::path& path);
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
template <typename Path>
|
||||||
|
[[nodiscard]] u64 GetTotalSpaceSize(const Path& path) {
|
||||||
|
if constexpr (IsChar<typename Path::value_type>) {
|
||||||
|
return GetTotalSpaceSize(ToU8String(path));
|
||||||
|
} else {
|
||||||
|
return GetTotalSpaceSize(std::filesystem::path{path});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} // namespace Common::FS
|
|
@ -27,16 +27,15 @@ void MntPoints::UnmountAll() {
|
||||||
|
|
||||||
std::string MntPoints::GetHostDirectory(const std::string& guest_directory) {
|
std::string MntPoints::GetHostDirectory(const std::string& guest_directory) {
|
||||||
std::scoped_lock lock{m_mutex};
|
std::scoped_lock lock{m_mutex};
|
||||||
|
|
||||||
for (auto& pair : m_mnt_pairs) {
|
for (auto& pair : m_mnt_pairs) {
|
||||||
if (pair.guest_path.starts_with(guest_directory)) {
|
// horrible code but it works :D
|
||||||
return pair.host_path + guest_directory;
|
int find = guest_directory.find(pair.guest_path);
|
||||||
}
|
if (find == 0) {
|
||||||
}
|
std::string npath =
|
||||||
// hack for relative path , get app0 and assuming it goes from there
|
guest_directory.substr(pair.guest_path.size(), guest_directory.size() - 1);
|
||||||
for (auto& pair : m_mnt_pairs) {
|
|
||||||
if (pair.guest_path.starts_with("/app0")) {
|
|
||||||
std::replace(pair.host_path.begin(), pair.host_path.end(), '\\', '/');
|
std::replace(pair.host_path.begin(), pair.host_path.end(), '\\', '/');
|
||||||
return pair.host_path + guest_directory;
|
return pair.host_path + npath;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
|
|
|
@ -30,12 +30,23 @@ int PS4_SYSV_ABI sceKernelOpen(const char* path, int flags, u16 mode) {
|
||||||
bool dsync = (flags & ORBIS_KERNEL_O_DSYNC) != 0;
|
bool dsync = (flags & ORBIS_KERNEL_O_DSYNC) != 0;
|
||||||
bool direct = (flags & ORBIS_KERNEL_O_DIRECT) != 0;
|
bool direct = (flags & ORBIS_KERNEL_O_DIRECT) != 0;
|
||||||
bool directory = (flags & ORBIS_KERNEL_O_DIRECTORY) != 0;
|
bool directory = (flags & ORBIS_KERNEL_O_DIRECTORY) != 0;
|
||||||
|
|
||||||
if (directory) {
|
|
||||||
UNREACHABLE(); // not supported yet
|
|
||||||
} else {
|
|
||||||
u32 handle = h->CreateHandle();
|
u32 handle = h->CreateHandle();
|
||||||
auto* file = h->GetFile(handle);
|
auto* file = h->GetFile(handle);
|
||||||
|
if (directory) {
|
||||||
|
file->is_directory = true;
|
||||||
|
file->m_guest_name = path;
|
||||||
|
file->m_host_name = mnt->GetHostDirectory(file->m_guest_name);
|
||||||
|
if (!std::filesystem::is_directory(file->m_host_name)) { // directory doesn't exist
|
||||||
|
UNREACHABLE(); // not supported yet
|
||||||
|
} else {
|
||||||
|
if (create) {
|
||||||
|
return handle; // dir already exists
|
||||||
|
} else {
|
||||||
|
// get dirents TODO
|
||||||
|
file->dirents_index = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
file->m_guest_name = path;
|
file->m_guest_name = path;
|
||||||
file->m_host_name = mnt->GetHostFile(file->m_guest_name);
|
file->m_host_name = mnt->GetHostFile(file->m_guest_name);
|
||||||
if (read) {
|
if (read) {
|
||||||
|
@ -49,11 +60,10 @@ int PS4_SYSV_ABI sceKernelOpen(const char* path, int flags, u16 mode) {
|
||||||
h->DeleteHandle(handle);
|
h->DeleteHandle(handle);
|
||||||
return SCE_KERNEL_ERROR_EACCES;
|
return SCE_KERNEL_ERROR_EACCES;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
file->is_opened = true;
|
file->is_opened = true;
|
||||||
return handle;
|
return handle;
|
||||||
}
|
}
|
||||||
return -1; // dummy
|
|
||||||
}
|
|
||||||
|
|
||||||
int PS4_SYSV_ABI posix_open(const char* path, int flags, /* SceKernelMode*/ u16 mode) {
|
int PS4_SYSV_ABI posix_open(const char* path, int flags, /* SceKernelMode*/ u16 mode) {
|
||||||
LOG_INFO(Kernel_Fs, "posix open redirect to sceKernelOpen\n");
|
LOG_INFO(Kernel_Fs, "posix open redirect to sceKernelOpen\n");
|
||||||
|
|
|
@ -56,6 +56,11 @@ void PS4_SYSV_ABI sceKernelUsleep(u32 microseconds) {
|
||||||
std::this_thread::sleep_for(std::chrono::microseconds(microseconds));
|
std::this_thread::sleep_for(std::chrono::microseconds(microseconds));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI posix_usleep(u32 microseconds) {
|
||||||
|
std::this_thread::sleep_for(std::chrono::microseconds(microseconds));
|
||||||
|
return SCE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
struct iovec {
|
struct iovec {
|
||||||
void* iov_base; /* Base address. */
|
void* iov_base; /* Base address. */
|
||||||
size_t iov_len; /* Length. */
|
size_t iov_len; /* Length. */
|
||||||
|
@ -205,6 +210,7 @@ void LibKernel_Register(Core::Loader::SymbolsResolver* sym) {
|
||||||
// memory
|
// memory
|
||||||
LIB_FUNCTION("rTXw65xmLIA", "libkernel", 1, "libkernel", 1, 1, sceKernelAllocateDirectMemory);
|
LIB_FUNCTION("rTXw65xmLIA", "libkernel", 1, "libkernel", 1, 1, sceKernelAllocateDirectMemory);
|
||||||
LIB_FUNCTION("pO96TwzOm5E", "libkernel", 1, "libkernel", 1, 1, sceKernelGetDirectMemorySize);
|
LIB_FUNCTION("pO96TwzOm5E", "libkernel", 1, "libkernel", 1, 1, sceKernelGetDirectMemorySize);
|
||||||
|
LIB_FUNCTION("NcaWUxfMNIQ", "libkernel", 1, "libkernel", 1, 1, sceKernelMapNamedDirectMemory);
|
||||||
LIB_FUNCTION("L-Q3LEjIbgA", "libkernel", 1, "libkernel", 1, 1, sceKernelMapDirectMemory);
|
LIB_FUNCTION("L-Q3LEjIbgA", "libkernel", 1, "libkernel", 1, 1, sceKernelMapDirectMemory);
|
||||||
LIB_FUNCTION("WFcfL2lzido", "libkernel", 1, "libkernel", 1, 1, sceKernelQueryMemoryProtection);
|
LIB_FUNCTION("WFcfL2lzido", "libkernel", 1, "libkernel", 1, 1, sceKernelQueryMemoryProtection);
|
||||||
LIB_FUNCTION("BHouLQzh0X0", "libkernel", 1, "libkernel", 1, 1, sceKernelDirectMemoryQuery);
|
LIB_FUNCTION("BHouLQzh0X0", "libkernel", 1, "libkernel", 1, 1, sceKernelDirectMemoryQuery);
|
||||||
|
@ -229,6 +235,7 @@ void LibKernel_Register(Core::Loader::SymbolsResolver* sym) {
|
||||||
LIB_FUNCTION("-o5uEDpN+oY", "libkernel", 1, "libkernel", 1, 1, sceKernelConvertUtcToLocaltime);
|
LIB_FUNCTION("-o5uEDpN+oY", "libkernel", 1, "libkernel", 1, 1, sceKernelConvertUtcToLocaltime);
|
||||||
LIB_FUNCTION("WB66evu8bsU", "libkernel", 1, "libkernel", 1, 1, sceKernelGetCompiledSdkVersion);
|
LIB_FUNCTION("WB66evu8bsU", "libkernel", 1, "libkernel", 1, 1, sceKernelGetCompiledSdkVersion);
|
||||||
LIB_FUNCTION("DRuBt2pvICk", "libkernel", 1, "libkernel", 1, 1, ps4__read);
|
LIB_FUNCTION("DRuBt2pvICk", "libkernel", 1, "libkernel", 1, 1, ps4__read);
|
||||||
|
LIB_FUNCTION("QcteRwbsnV0", "libScePosix", 1, "libkernel", 1, 1, posix_usleep);
|
||||||
|
|
||||||
Libraries::Kernel::fileSystemSymbolsRegister(sym);
|
Libraries::Kernel::fileSystemSymbolsRegister(sym);
|
||||||
Libraries::Kernel::timeSymbolsRegister(sym);
|
Libraries::Kernel::timeSymbolsRegister(sym);
|
||||||
|
|
|
@ -47,9 +47,9 @@ int PS4_SYSV_ABI sceKernelAllocateDirectMemory(s64 searchStart, s64 searchEnd, u
|
||||||
|
|
||||||
return SCE_OK;
|
return SCE_OK;
|
||||||
}
|
}
|
||||||
|
int PS4_SYSV_ABI sceKernelMapNamedDirectMemory(void** addr, u64 len, int prot, int flags,
|
||||||
int PS4_SYSV_ABI sceKernelMapDirectMemory(void** addr, u64 len, int prot, int flags,
|
s64 directMemoryStart, u64 alignment,
|
||||||
s64 directMemoryStart, u64 alignment) {
|
const char* name) {
|
||||||
LOG_INFO(
|
LOG_INFO(
|
||||||
Kernel_Vmm,
|
Kernel_Vmm,
|
||||||
"len = {:#x}, prot = {:#x}, flags = {:#x}, directMemoryStart = {:#x}, alignment = {:#x}",
|
"len = {:#x}, prot = {:#x}, flags = {:#x}, directMemoryStart = {:#x}, alignment = {:#x}",
|
||||||
|
@ -74,8 +74,12 @@ int PS4_SYSV_ABI sceKernelMapDirectMemory(void** addr, u64 len, int prot, int fl
|
||||||
const auto mem_prot = static_cast<Core::MemoryProt>(prot);
|
const auto mem_prot = static_cast<Core::MemoryProt>(prot);
|
||||||
const auto map_flags = static_cast<Core::MemoryMapFlags>(flags);
|
const auto map_flags = static_cast<Core::MemoryMapFlags>(flags);
|
||||||
auto* memory = Core::Memory::Instance();
|
auto* memory = Core::Memory::Instance();
|
||||||
return memory->MapMemory(addr, in_addr, len, mem_prot, map_flags, Core::VMAType::Direct, "",
|
return memory->MapMemory(addr, in_addr, len, mem_prot, map_flags, Core::VMAType::Direct,
|
||||||
directMemoryStart, alignment);
|
std::string_view(name), directMemoryStart, alignment);
|
||||||
|
}
|
||||||
|
int PS4_SYSV_ABI sceKernelMapDirectMemory(void** addr, u64 len, int prot, int flags,
|
||||||
|
s64 directMemoryStart, u64 alignment) {
|
||||||
|
return sceKernelMapNamedDirectMemory(addr, len, prot, flags, directMemoryStart, alignment, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 PS4_SYSV_ABI sceKernelMapNamedFlexibleMemory(void** addr_in_out, std::size_t len, int prot,
|
s32 PS4_SYSV_ABI sceKernelMapNamedFlexibleMemory(void** addr_in_out, std::size_t len, int prot,
|
||||||
|
|
|
@ -39,6 +39,9 @@ struct OrbisQueryInfo {
|
||||||
u64 PS4_SYSV_ABI sceKernelGetDirectMemorySize();
|
u64 PS4_SYSV_ABI sceKernelGetDirectMemorySize();
|
||||||
int PS4_SYSV_ABI sceKernelAllocateDirectMemory(s64 searchStart, s64 searchEnd, u64 len,
|
int PS4_SYSV_ABI sceKernelAllocateDirectMemory(s64 searchStart, s64 searchEnd, u64 len,
|
||||||
u64 alignment, int memoryType, s64* physAddrOut);
|
u64 alignment, int memoryType, s64* physAddrOut);
|
||||||
|
int PS4_SYSV_ABI sceKernelMapNamedDirectMemory(void** addr, u64 len, int prot, int flags,
|
||||||
|
s64 directMemoryStart, u64 alignment,
|
||||||
|
const char* name);
|
||||||
int PS4_SYSV_ABI sceKernelMapDirectMemory(void** addr, u64 len, int prot, int flags,
|
int PS4_SYSV_ABI sceKernelMapDirectMemory(void** addr, u64 len, int prot, int flags,
|
||||||
s64 directMemoryStart, u64 alignment);
|
s64 directMemoryStart, u64 alignment);
|
||||||
s32 PS4_SYSV_ABI sceKernelMapNamedFlexibleMemory(void** addrInOut, std::size_t len, int prot,
|
s32 PS4_SYSV_ABI sceKernelMapNamedFlexibleMemory(void** addrInOut, std::size_t len, int prot,
|
||||||
|
|
|
@ -1022,6 +1022,148 @@ int PS4_SYSV_ABI scePthreadEqual(ScePthread thread1, ScePthread thread2) {
|
||||||
return (thread1 == thread2 ? 1 : 0);
|
return (thread1 == thread2 ? 1 : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI posix_pthread_mutexattr_init(ScePthreadMutexattr* attr) {
|
||||||
|
int result = scePthreadMutexattrInit(attr);
|
||||||
|
if (result < 0) {
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
int PS4_SYSV_ABI posix_pthread_mutexattr_destroy(ScePthreadMutexattr* attr) {
|
||||||
|
int result = scePthreadMutexattrDestroy(attr);
|
||||||
|
if (result < 0) {
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI posix_pthread_create(ScePthread* thread, const ScePthreadAttr* attr,
|
||||||
|
pthreadEntryFunc start_routine, void* arg) {
|
||||||
|
int result = scePthreadCreate(thread, attr, start_routine, arg, "");
|
||||||
|
if (result < 0) {
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI posix_pthread_cond_init(ScePthreadCond* cond, const ScePthreadCondattr* attr) {
|
||||||
|
int result = scePthreadCondInit(cond, attr, "");
|
||||||
|
if (result < 0) {
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI posix_pthread_attr_init(ScePthreadAttr* attr) {
|
||||||
|
int result = scePthreadAttrInit(attr);
|
||||||
|
if (result < 0) {
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI posix_pthread_attr_setstacksize(ScePthreadAttr* attr, size_t stack_size) {
|
||||||
|
int result = scePthreadAttrSetstacksize(attr, stack_size);
|
||||||
|
if (result < 0) {
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI posix_pthread_cond_wait(ScePthreadCond* cond, ScePthreadMutex* mutex) {
|
||||||
|
int result = scePthreadCondWait(cond, mutex);
|
||||||
|
if (result < 0) {
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI posix_pthread_mutexattr_setprotocol(ScePthreadMutexattr* attr, u32 protocol) {
|
||||||
|
int result = scePthreadMutexattrSetprotocol(attr, protocol);
|
||||||
|
if (result < 0) {
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
int PS4_SYSV_ABI posix_pthread_mutex_trylock(ScePthreadMutex* mutex) {
|
||||||
|
int result = scePthreadMutexTrylock(mutex);
|
||||||
|
if (result < 0) {
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI posix_pthread_condattr_init(ScePthreadCondattr* attr) {
|
||||||
|
int result = scePthreadCondattrInit(attr);
|
||||||
|
if (result < 0) {
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI posix_pthread_condattr_destroy(ScePthreadCondattr* attr) {
|
||||||
|
int result = scePthreadCondattrDestroy(attr);
|
||||||
|
if (result < 0) {
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
int PS4_SYSV_ABI posix_pthread_attr_destroy(ScePthreadAttr* attr) {
|
||||||
|
int result = scePthreadAttrDestroy(attr);
|
||||||
|
if (result < 0) {
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
int PS4_SYSV_ABI posix_pthread_cond_signal(ScePthreadCond* cond) {
|
||||||
|
int result = scePthreadCondSignal(cond);
|
||||||
|
if (result < 0) {
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI scePthreadCondDestroy(ScePthreadCond* cond) {
|
||||||
|
if (cond == nullptr) {
|
||||||
|
return SCE_KERNEL_ERROR_EINVAL;
|
||||||
|
}
|
||||||
|
int result = pthread_cond_destroy(&(*cond)->cond);
|
||||||
|
|
||||||
|
LOG_INFO(Kernel_Pthread, "scePthreadCondDestroy, result={}", result);
|
||||||
|
|
||||||
|
switch (result) {
|
||||||
|
case 0:
|
||||||
|
return SCE_OK;
|
||||||
|
case EBUSY:
|
||||||
|
return SCE_KERNEL_ERROR_EBUSY;
|
||||||
|
default:
|
||||||
|
return SCE_KERNEL_ERROR_EINVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI posix_pthread_cond_destroy(ScePthreadCond* cond) {
|
||||||
|
int result = scePthreadCondDestroy(cond);
|
||||||
|
if (result < 0) {
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceKernelGettimeofday(SceKernelTimespec* tp) {
|
||||||
|
if (tp == nullptr) {
|
||||||
|
return ORBIS_KERNEL_ERROR_EINVAL;
|
||||||
|
}
|
||||||
|
auto now = std::chrono::system_clock::now();
|
||||||
|
auto duration = now.time_since_epoch();
|
||||||
|
auto seconds = std::chrono::duration_cast<std::chrono::seconds>(duration);
|
||||||
|
auto nanoseconds = std::chrono::duration_cast<std::chrono::nanoseconds>(duration - seconds);
|
||||||
|
|
||||||
|
tp->tv_sec = static_cast<long>(seconds.count());
|
||||||
|
tp->tv_nsec = static_cast<long>(nanoseconds.count());
|
||||||
|
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
void pthreadSymbolsRegister(Core::Loader::SymbolsResolver* sym) {
|
void pthreadSymbolsRegister(Core::Loader::SymbolsResolver* sym) {
|
||||||
LIB_FUNCTION("4+h9EzwKF4I", "libkernel", 1, "libkernel", 1, 1, scePthreadAttrSetschedpolicy);
|
LIB_FUNCTION("4+h9EzwKF4I", "libkernel", 1, "libkernel", 1, 1, scePthreadAttrSetschedpolicy);
|
||||||
LIB_FUNCTION("-Wreprtu0Qs", "libkernel", 1, "libkernel", 1, 1, scePthreadAttrSetdetachstate);
|
LIB_FUNCTION("-Wreprtu0Qs", "libkernel", 1, "libkernel", 1, 1, scePthreadAttrSetdetachstate);
|
||||||
|
@ -1053,6 +1195,22 @@ void pthreadSymbolsRegister(Core::Loader::SymbolsResolver* sym) {
|
||||||
LIB_FUNCTION("9UK1vLZQft4", "libkernel", 1, "libkernel", 1, 1, scePthreadMutexLock);
|
LIB_FUNCTION("9UK1vLZQft4", "libkernel", 1, "libkernel", 1, 1, scePthreadMutexLock);
|
||||||
LIB_FUNCTION("tn3VlD0hG60", "libkernel", 1, "libkernel", 1, 1, scePthreadMutexUnlock);
|
LIB_FUNCTION("tn3VlD0hG60", "libkernel", 1, "libkernel", 1, 1, scePthreadMutexUnlock);
|
||||||
LIB_FUNCTION("upoVrzMHFeE", "libkernel", 1, "libkernel", 1, 1, scePthreadMutexTrylock);
|
LIB_FUNCTION("upoVrzMHFeE", "libkernel", 1, "libkernel", 1, 1, scePthreadMutexTrylock);
|
||||||
|
LIB_FUNCTION("dQHWEsJtoE4", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_mutexattr_init);
|
||||||
|
LIB_FUNCTION("HF7lK46xzjY", "libScePosix", 1, "libkernel", 1, 1,
|
||||||
|
posix_pthread_mutexattr_destroy);
|
||||||
|
LIB_FUNCTION("OxhIB8LB-PQ", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_create);
|
||||||
|
LIB_FUNCTION("0TyVk4MSLt0", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_cond_init);
|
||||||
|
LIB_FUNCTION("wtkt-teR1so", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_attr_init);
|
||||||
|
LIB_FUNCTION("2Q0z6rnBrTE", "libScePosix", 1, "libkernel", 1, 1,
|
||||||
|
posix_pthread_attr_setstacksize);
|
||||||
|
LIB_FUNCTION("Op8TBGY5KHg", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_cond_wait);
|
||||||
|
LIB_FUNCTION("mKoTx03HRWA", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_condattr_init);
|
||||||
|
LIB_FUNCTION("dJcuQVn6-Iw", "libScePosix", 1, "libkernel", 1, 1,
|
||||||
|
posix_pthread_condattr_destroy);
|
||||||
|
LIB_FUNCTION("5txKfcMUAok", "libScePosix", 1, "libkernel", 1, 1,
|
||||||
|
posix_pthread_mutexattr_setprotocol);
|
||||||
|
LIB_FUNCTION("K-jXhbt2gn4", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_mutex_trylock);
|
||||||
|
LIB_FUNCTION("zHchY8ft5pk", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_attr_destroy);
|
||||||
// cond calls
|
// cond calls
|
||||||
LIB_FUNCTION("2Tb92quprl0", "libkernel", 1, "libkernel", 1, 1, scePthreadCondInit);
|
LIB_FUNCTION("2Tb92quprl0", "libkernel", 1, "libkernel", 1, 1, scePthreadCondInit);
|
||||||
LIB_FUNCTION("m5-2bsNfv7s", "libkernel", 1, "libkernel", 1, 1, scePthreadCondattrInit);
|
LIB_FUNCTION("m5-2bsNfv7s", "libkernel", 1, "libkernel", 1, 1, scePthreadCondattrInit);
|
||||||
|
@ -1061,16 +1219,21 @@ void pthreadSymbolsRegister(Core::Loader::SymbolsResolver* sym) {
|
||||||
LIB_FUNCTION("waPcxYiR3WA", "libkernel", 1, "libkernel", 1, 1, scePthreadCondattrDestroy);
|
LIB_FUNCTION("waPcxYiR3WA", "libkernel", 1, "libkernel", 1, 1, scePthreadCondattrDestroy);
|
||||||
LIB_FUNCTION("kDh-NfxgMtE", "libkernel", 1, "libkernel", 1, 1, scePthreadCondSignal);
|
LIB_FUNCTION("kDh-NfxgMtE", "libkernel", 1, "libkernel", 1, 1, scePthreadCondSignal);
|
||||||
LIB_FUNCTION("BmMjYxmew1w", "libkernel", 1, "libkernel", 1, 1, scePthreadCondTimedwait);
|
LIB_FUNCTION("BmMjYxmew1w", "libkernel", 1, "libkernel", 1, 1, scePthreadCondTimedwait);
|
||||||
|
LIB_FUNCTION("g+PZd2hiacg", "libkernel", 1, "libkernel", 1, 1, scePthreadCondDestroy);
|
||||||
|
LIB_FUNCTION("RXXqi4CtF8w", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_cond_destroy);
|
||||||
|
|
||||||
// posix calls
|
// posix calls
|
||||||
LIB_FUNCTION("ttHNfU+qDBU", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_mutex_init);
|
LIB_FUNCTION("ttHNfU+qDBU", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_mutex_init);
|
||||||
LIB_FUNCTION("7H0iTOciTLo", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_mutex_lock);
|
LIB_FUNCTION("7H0iTOciTLo", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_mutex_lock);
|
||||||
LIB_FUNCTION("2Z+PpY6CaJg", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_mutex_unlock);
|
LIB_FUNCTION("2Z+PpY6CaJg", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_mutex_unlock);
|
||||||
LIB_FUNCTION("mkx2fVhNMsg", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_cond_broadcast);
|
LIB_FUNCTION("mkx2fVhNMsg", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_cond_broadcast);
|
||||||
|
LIB_FUNCTION("2MOy+rUfuhQ", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_cond_signal);
|
||||||
|
|
||||||
LIB_FUNCTION("QBi7HCK03hw", "libkernel", 1, "libkernel", 1, 1, sceKernelClockGettime);
|
LIB_FUNCTION("QBi7HCK03hw", "libkernel", 1, "libkernel", 1, 1, sceKernelClockGettime);
|
||||||
LIB_FUNCTION("lLMT9vJAck0", "libkernel", 1, "libkernel", 1, 1, clock_gettime);
|
LIB_FUNCTION("lLMT9vJAck0", "libkernel", 1, "libkernel", 1, 1, clock_gettime);
|
||||||
LIB_FUNCTION("lLMT9vJAck0", "libScePosix", 1, "libkernel", 1, 1, clock_gettime);
|
LIB_FUNCTION("lLMT9vJAck0", "libScePosix", 1, "libkernel", 1, 1, clock_gettime);
|
||||||
LIB_FUNCTION("yS8U2TGCe1A", "libScePosix", 1, "libkernel", 1, 1, nanosleep);
|
LIB_FUNCTION("yS8U2TGCe1A", "libScePosix", 1, "libkernel", 1, 1, nanosleep);
|
||||||
|
LIB_FUNCTION("ejekcaNQNq0", "libkernel", 1, "libkernel", 1, 1, sceKernelGettimeofday);
|
||||||
|
|
||||||
// openorbis weird functions
|
// openorbis weird functions
|
||||||
LIB_FUNCTION("7H0iTOciTLo", "libkernel", 1, "libkernel", 1, 1, posix_pthread_mutex_lock);
|
LIB_FUNCTION("7H0iTOciTLo", "libkernel", 1, "libkernel", 1, 1, posix_pthread_mutex_lock);
|
||||||
|
|
|
@ -113,12 +113,15 @@ s32 PS4_SYSV_ABI scePadSetMotionSensorState(s32 handle, bool enable) {
|
||||||
return SCE_OK;
|
return SCE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI scePadGetHandle(s32 userId, int32_t type, int32_t index) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
void padSymbolsRegister(Core::Loader::SymbolsResolver* sym) {
|
void padSymbolsRegister(Core::Loader::SymbolsResolver* sym) {
|
||||||
LIB_FUNCTION("hv1luiJrqQM", "libScePad", 1, "libScePad", 1, 1, scePadInit);
|
LIB_FUNCTION("hv1luiJrqQM", "libScePad", 1, "libScePad", 1, 1, scePadInit);
|
||||||
LIB_FUNCTION("xk0AcarP3V4", "libScePad", 1, "libScePad", 1, 1, scePadOpen);
|
LIB_FUNCTION("xk0AcarP3V4", "libScePad", 1, "libScePad", 1, 1, scePadOpen);
|
||||||
LIB_FUNCTION("YndgXqQVV7c", "libScePad", 1, "libScePad", 1, 1, scePadReadState);
|
LIB_FUNCTION("YndgXqQVV7c", "libScePad", 1, "libScePad", 1, 1, scePadReadState);
|
||||||
LIB_FUNCTION("q1cHNfGycLI", "libScePad", 1, "libScePad", 1, 1, scePadRead);
|
LIB_FUNCTION("q1cHNfGycLI", "libScePad", 1, "libScePad", 1, 1, scePadRead);
|
||||||
|
LIB_FUNCTION("u1GRHp+oWoY", "libScePad", 1, "libScePad", 1, 1, scePadGetHandle);
|
||||||
LIB_FUNCTION("gjP9-KQzoUk", "libScePad", 1, "libScePad", 1, 1, scePadGetControllerInformation);
|
LIB_FUNCTION("gjP9-KQzoUk", "libScePad", 1, "libScePad", 1, 1, scePadGetControllerInformation);
|
||||||
LIB_FUNCTION("clVvL4ZDntw", "libScePad", 1, "libScePad", 1, 1, scePadSetMotionSensorState);
|
LIB_FUNCTION("clVvL4ZDntw", "libScePad", 1, "libScePad", 1, 1, scePadSetMotionSensorState);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue