early-access version 1670
This commit is contained in:
@@ -14,8 +14,8 @@ namespace fs = std::filesystem;
|
||||
// File Operations
|
||||
|
||||
bool NewFile(const fs::path& path, u64 size) {
|
||||
if (path.empty()) {
|
||||
LOG_ERROR(Common_Filesystem, "Input path is empty, path={}", PathToUTF8String(path));
|
||||
if (!ValidatePath(path)) {
|
||||
LOG_ERROR(Common_Filesystem, "Input path is not valid, path={}", PathToUTF8String(path));
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -52,8 +52,8 @@ bool NewFile(const fs::path& path, u64 size) {
|
||||
}
|
||||
|
||||
bool RemoveFile(const fs::path& path) {
|
||||
if (path.empty()) {
|
||||
LOG_ERROR(Common_Filesystem, "Input path is empty, path={}", PathToUTF8String(path));
|
||||
if (!ValidatePath(path)) {
|
||||
LOG_ERROR(Common_Filesystem, "Input path is not valid, path={}", PathToUTF8String(path));
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -86,8 +86,9 @@ bool RemoveFile(const fs::path& path) {
|
||||
}
|
||||
|
||||
bool RenameFile(const fs::path& old_path, const fs::path& new_path) {
|
||||
if (old_path.empty() || new_path.empty()) {
|
||||
LOG_ERROR(Common_Filesystem, "One or both input path(s) is empty, old_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;
|
||||
}
|
||||
@@ -129,8 +130,8 @@ bool RenameFile(const fs::path& old_path, const fs::path& new_path) {
|
||||
|
||||
std::shared_ptr<IOFile> FileOpen(const fs::path& path, FileAccessMode mode, FileType type,
|
||||
FileShareFlag flag) {
|
||||
if (path.empty()) {
|
||||
LOG_ERROR(Common_Filesystem, "Input path is empty, path={}", PathToUTF8String(path));
|
||||
if (!ValidatePath(path)) {
|
||||
LOG_ERROR(Common_Filesystem, "Input path is not valid, path={}", PathToUTF8String(path));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -162,8 +163,8 @@ std::shared_ptr<IOFile> FileOpen(const fs::path& path, FileAccessMode mode, File
|
||||
// Directory Operations
|
||||
|
||||
bool CreateDir(const fs::path& path) {
|
||||
if (path.empty()) {
|
||||
LOG_ERROR(Common_Filesystem, "Input path is empty, path={}", PathToUTF8String(path));
|
||||
if (!ValidatePath(path)) {
|
||||
LOG_ERROR(Common_Filesystem, "Input path is not valid, path={}", PathToUTF8String(path));
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -196,8 +197,8 @@ bool CreateDir(const fs::path& path) {
|
||||
}
|
||||
|
||||
bool CreateDirs(const fs::path& path) {
|
||||
if (path.empty()) {
|
||||
LOG_ERROR(Common_Filesystem, "Input path is empty, path={}", PathToUTF8String(path));
|
||||
if (!ValidatePath(path)) {
|
||||
LOG_ERROR(Common_Filesystem, "Input path is not valid, path={}", PathToUTF8String(path));
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -232,8 +233,8 @@ bool CreateParentDirs(const fs::path& path) {
|
||||
}
|
||||
|
||||
bool RemoveDir(const fs::path& path) {
|
||||
if (path.empty()) {
|
||||
LOG_ERROR(Common_Filesystem, "Input path is empty, path={}", PathToUTF8String(path));
|
||||
if (!ValidatePath(path)) {
|
||||
LOG_ERROR(Common_Filesystem, "Input path is not valid, path={}", PathToUTF8String(path));
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -266,8 +267,8 @@ bool RemoveDir(const fs::path& path) {
|
||||
}
|
||||
|
||||
bool RemoveDirRecursively(const fs::path& path) {
|
||||
if (path.empty()) {
|
||||
LOG_ERROR(Common_Filesystem, "Input path is empty, path={}", PathToUTF8String(path));
|
||||
if (!ValidatePath(path)) {
|
||||
LOG_ERROR(Common_Filesystem, "Input path is not valid, path={}", PathToUTF8String(path));
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -301,8 +302,8 @@ bool RemoveDirRecursively(const fs::path& path) {
|
||||
}
|
||||
|
||||
bool RemoveDirContentsRecursively(const fs::path& path) {
|
||||
if (path.empty()) {
|
||||
LOG_ERROR(Common_Filesystem, "Input path is empty, path={}", PathToUTF8String(path));
|
||||
if (!ValidatePath(path)) {
|
||||
LOG_ERROR(Common_Filesystem, "Input path is not valid, path={}", PathToUTF8String(path));
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -353,8 +354,9 @@ bool RemoveDirContentsRecursively(const fs::path& path) {
|
||||
}
|
||||
|
||||
bool RenameDir(const fs::path& old_path, const fs::path& new_path) {
|
||||
if (old_path.empty() || new_path.empty()) {
|
||||
LOG_ERROR(Common_Filesystem, "One or both input path(s) is empty, old_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;
|
||||
}
|
||||
@@ -396,8 +398,8 @@ bool RenameDir(const fs::path& old_path, const fs::path& new_path) {
|
||||
|
||||
void IterateDirEntries(const std::filesystem::path& path, const DirEntryCallable& callback,
|
||||
DirEntryFilter filter) {
|
||||
if (path.empty()) {
|
||||
LOG_ERROR(Common_Filesystem, "Input path is empty, path={}", PathToUTF8String(path));
|
||||
if (!ValidatePath(path)) {
|
||||
LOG_ERROR(Common_Filesystem, "Input path is not valid, path={}", PathToUTF8String(path));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -452,8 +454,8 @@ void IterateDirEntries(const std::filesystem::path& path, const DirEntryCallable
|
||||
|
||||
void IterateDirEntriesRecursively(const std::filesystem::path& path,
|
||||
const DirEntryCallable& callback, DirEntryFilter filter) {
|
||||
if (path.empty()) {
|
||||
LOG_ERROR(Common_Filesystem, "Input path is empty, path={}", PathToUTF8String(path));
|
||||
if (!ValidatePath(path)) {
|
||||
LOG_ERROR(Common_Filesystem, "Input path is not valid, path={}", PathToUTF8String(path));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@@ -20,7 +20,7 @@ class IOFile;
|
||||
* Creates a new file at path with a specified size.
|
||||
*
|
||||
* Failures occur when:
|
||||
* - Input path is empty
|
||||
* - 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
|
||||
@@ -50,7 +50,7 @@ template <typename Path>
|
||||
* Removes a file at path.
|
||||
*
|
||||
* Failures occur when:
|
||||
* - Input path is empty
|
||||
* - Input path is not valid
|
||||
* - Filesystem object at path is not a file
|
||||
* - Filesystem at path is read only
|
||||
*
|
||||
@@ -78,7 +78,7 @@ template <typename Path>
|
||||
* Renames a file from old_path to new_path.
|
||||
*
|
||||
* Failures occur when:
|
||||
* - One or both input path(s) is empty
|
||||
* - 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 file
|
||||
* - Filesystem object at new_path exists
|
||||
@@ -117,7 +117,7 @@ template <typename Path1, typename Path2>
|
||||
* These behaviors are documented in each enum value of FileAccessMode.
|
||||
*
|
||||
* Failures occur when:
|
||||
* - Input path is empty
|
||||
* - Input path is not valid
|
||||
* - Filesystem object at path is not a file
|
||||
* - The file is not opened
|
||||
*
|
||||
@@ -158,7 +158,7 @@ template <typename Path>
|
||||
* If you intend to create the parent directory of a file, use CreateParentDir instead.
|
||||
*
|
||||
* Failures occur when:
|
||||
* - Input path is empty
|
||||
* - Input path is not valid
|
||||
* - The input path's parent directory does not exist
|
||||
* - Filesystem at path is read only
|
||||
*
|
||||
@@ -190,7 +190,7 @@ template <typename Path>
|
||||
* Unlike CreateDir, this creates all of input path's parent directories if they do not exist.
|
||||
*
|
||||
* Failures occur when:
|
||||
* - Input path is empty
|
||||
* - Input path is not valid
|
||||
* - Filesystem at path is read only
|
||||
*
|
||||
* @param path Filesystem path
|
||||
@@ -265,7 +265,7 @@ template <typename Path>
|
||||
* Removes a directory at path.
|
||||
*
|
||||
* Failures occur when:
|
||||
* - Input path is empty
|
||||
* - 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
|
||||
@@ -294,7 +294,7 @@ template <typename Path>
|
||||
* Removes all the contents within the given directory and removes the directory itself.
|
||||
*
|
||||
* Failures occur when:
|
||||
* - Input path is empty
|
||||
* - Input path is not valid
|
||||
* - Filesystem object at path is not a directory
|
||||
* - Filesystem at path is read only
|
||||
*
|
||||
@@ -322,7 +322,7 @@ template <typename Path>
|
||||
* Removes all the contents within the given directory without removing the directory itself.
|
||||
*
|
||||
* Failures occur when:
|
||||
* - Input path is empty
|
||||
* - Input path is not valid
|
||||
* - Filesystem object at path is not a directory
|
||||
* - Filesystem at path is read only
|
||||
*
|
||||
@@ -350,7 +350,7 @@ template <typename Path>
|
||||
* Renames a directory from old_path to new_path.
|
||||
*
|
||||
* Failures occur when:
|
||||
* - One or both input path(s) is empty
|
||||
* - 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
|
||||
@@ -392,7 +392,7 @@ template <typename Path1, typename Path2>
|
||||
* If the callback returns false or there is an error, the iteration is immediately halted.
|
||||
*
|
||||
* Failures occur when:
|
||||
* - Input path is empty
|
||||
* - Input path is not valid
|
||||
* - Filesystem object at path is not a directory
|
||||
*
|
||||
* @param path Filesystem path
|
||||
@@ -425,7 +425,7 @@ void IterateDirEntries(const Path& path, const DirEntryCallable& callback,
|
||||
* If the callback returns false or there is an error, the iteration is immediately halted.
|
||||
*
|
||||
* Failures occur when:
|
||||
* - Input path is empty
|
||||
* - Input path is not valid
|
||||
* - Filesystem object at path does not exist
|
||||
* - Filesystem object at path is not a directory
|
||||
*
|
||||
|
@@ -4,10 +4,6 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef MAX_PATH
|
||||
#define MAX_PATH 260
|
||||
#endif
|
||||
|
||||
// yuzu data directories
|
||||
|
||||
#define YUZU_DIR "yuzu"
|
||||
|
@@ -37,10 +37,26 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef MAX_PATH
|
||||
#ifdef _WIN32
|
||||
// This is the maximum number of UTF-16 code units permissible in Windows file paths
|
||||
#define MAX_PATH 260
|
||||
#else
|
||||
// This is the maximum number of UTF-8 code units permissible in all other OSes' file paths
|
||||
#define MAX_PATH 1024
|
||||
#endif
|
||||
#endif
|
||||
|
||||
namespace Common::FS {
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr std::array<char8_t, 7> INVALID_CHARS{u':', u'*', u'?', u'"', u'<', u'>', u'|'};
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* The PathManagerImpl is a singleton allowing to manage the mapping of
|
||||
* YuzuPath enums to real filesystem paths.
|
||||
@@ -129,6 +145,41 @@ std::string PathToUTF8String(const fs::path& path) {
|
||||
return std::string{utf8_string.begin(), utf8_string.end()};
|
||||
}
|
||||
|
||||
bool ValidatePath(const fs::path& path) {
|
||||
if (path.empty()) {
|
||||
LOG_ERROR(Common_Filesystem, "Input path is empty, path={}", PathToUTF8String(path));
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
if (path.u16string().size() >= MAX_PATH) {
|
||||
LOG_ERROR(Common_Filesystem, "Input path is too long, path={}", PathToUTF8String(path));
|
||||
return false;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
if (path.u8string().size() >= MAX_PATH) {
|
||||
LOG_ERROR(Common_Filesystem, "Input path is too long, path={}", PathToUTF8String(path));
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
for (const auto path_char : path.relative_path().u8string()) {
|
||||
for (const auto invalid_char : INVALID_CHARS) {
|
||||
if (path_char == invalid_char) {
|
||||
LOG_ERROR(Common_Filesystem, "Input path contains invalid characters, path={}",
|
||||
PathToUTF8String(path));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
fs::path ConcatPath(const fs::path& first, const fs::path& second) {
|
||||
const bool second_has_dir_sep = IsDirSeparator(second.u8string().front());
|
||||
|
||||
|
@@ -1,4 +1,4 @@
|
||||
// Copyright 2020 yuzu Emulator Project
|
||||
// Copyright 2021 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
@@ -45,6 +45,35 @@ enum class YuzuPath {
|
||||
*/
|
||||
[[nodiscard]] std::string PathToUTF8String(const std::filesystem::path& path);
|
||||
|
||||
/**
|
||||
* Validates a given path.
|
||||
*
|
||||
* A given path is valid if it meets these conditions:
|
||||
* - The path is not empty
|
||||
* - The path is not too long
|
||||
* - The path relative to the platform-specific root path does not contain
|
||||
* any of the following characters: ':', '*', '?', '"', '<', '>', '|'
|
||||
*
|
||||
* @param path Filesystem path
|
||||
*
|
||||
* @returns True if the path is valid, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] bool ValidatePath(const std::filesystem::path& path);
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
template <typename Path>
|
||||
[[nodiscard]] bool ValidatePath(const Path& path) {
|
||||
using ValueType = typename Path::value_type;
|
||||
if constexpr (IsChar<ValueType>) {
|
||||
return ValidatePath(ToU8String(path));
|
||||
} else {
|
||||
return ValidatePath(std::filesystem::path{path});
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Concatenates two filesystem paths together.
|
||||
*
|
||||
|
Reference in New Issue
Block a user