diff --git a/src/common/fs/fs.cpp b/src/common/fs/fs.cpp index 3dca11fe96..d492480d94 100644 --- a/src/common/fs/fs.cpp +++ b/src/common/fs/fs.cpp @@ -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 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 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; } diff --git a/src/common/fs/fs.h b/src/common/fs/fs.h index 917eaf51b5..f6f2563490 100644 --- a/src/common/fs/fs.h +++ b/src/common/fs/fs.h @@ -20,7 +20,7 @@ class IOFile; * Creates a new file at path with the 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 @@ -47,7 +47,7 @@ template * 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 * @@ -72,7 +72,7 @@ template * 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 @@ -109,7 +109,7 @@ template * 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 * @@ -147,7 +147,7 @@ template * 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 * @@ -176,7 +176,7 @@ template * 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 @@ -242,7 +242,7 @@ template * 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 @@ -268,7 +268,7 @@ template * 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 * @@ -293,7 +293,7 @@ template * 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 * @@ -318,7 +318,7 @@ template * 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 @@ -358,7 +358,7 @@ template * 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 @@ -388,7 +388,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 * diff --git a/src/common/fs/fs_paths.h b/src/common/fs/fs_paths.h index 58366bc7b8..b32614797c 100644 --- a/src/common/fs/fs_paths.h +++ b/src/common/fs/fs_paths.h @@ -4,10 +4,6 @@ #pragma once -#ifndef MAX_PATH -#define MAX_PATH 260 -#endif - // yuzu data directories #define YUZU_DIR "yuzu" diff --git a/src/common/fs/path_util.cpp b/src/common/fs/path_util.cpp index d9c5ee3fb7..8b732a21c3 100644 --- a/src/common/fs/path_util.cpp +++ b/src/common/fs/path_util.cpp @@ -37,6 +37,16 @@ #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; @@ -125,6 +135,27 @@ 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 + + return true; +} + fs::path ConcatPath(const fs::path& first, const fs::path& second) { const bool second_has_dir_sep = IsDirSeparator(second.u8string().front()); diff --git a/src/common/fs/path_util.h b/src/common/fs/path_util.h index 7fa848c1ae..a9fadbceb9 100644 --- a/src/common/fs/path_util.h +++ b/src/common/fs/path_util.h @@ -34,6 +34,30 @@ 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 + * + * @param path Filesystem path + * + * @returns True if the path is valid, false otherwise. + */ +[[nodiscard]] bool ValidatePath(const std::filesystem::path& path); + +#ifdef _WIN32 +template +[[nodiscard]] bool ValidatePath(const Path& path) { + if constexpr (IsChar) { + return ValidatePath(ToU8String(path)); + } else { + return ValidatePath(std::filesystem::path{path}); + } +} +#endif + /** * Concatenates two filesystem paths together. *