From 94a8e87c714871dc80478e6636d8fc178f9abd46 Mon Sep 17 00:00:00 2001 From: gabime Date: Mon, 29 Apr 2024 19:46:59 +0300 Subject: [PATCH] Fix #3079 --- include/spdlog/details/os-inl.h | 9 +++++ tests/test_create_dir.cpp | 62 +++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+) diff --git a/include/spdlog/details/os-inl.h b/include/spdlog/details/os-inl.h index 0993c195..26cee740 100644 --- a/include/spdlog/details/os-inl.h +++ b/include/spdlog/details/os-inl.h @@ -534,6 +534,15 @@ SPDLOG_INLINE bool create_dir(const filename_t &path) { } auto subdir = path.substr(0, token_pos); +#ifdef _WIN32 + // if subdir is just a drive letter, add a slash e.g. "c:"=>"c:\", + // otherwise path_exists(subdir) returns false (issue #3079) + const bool is_drive = subdir.length() == 2 && subdir[1] == ':'; + if (is_drive) { + subdir += '\\'; + token_pos++; + } +#endif if (!subdir.empty() && !path_exists(subdir) && !mkdir_(subdir)) { return false; // return error if failed creating dir diff --git a/tests/test_create_dir.cpp b/tests/test_create_dir.cpp index f88825b0..3dbcf29c 100644 --- a/tests/test_create_dir.cpp +++ b/tests/test_create_dir.cpp @@ -81,3 +81,65 @@ TEST_CASE("dir_name", "[create_dir]") { REQUIRE(dir_name(SPDLOG_FILENAME_T("../file.txt")) == SPDLOG_FILENAME_T("..")); REQUIRE(dir_name(SPDLOG_FILENAME_T("./file.txt")) == SPDLOG_FILENAME_T(".")); } + +#ifdef _WIN32 + +// +// test windows cases when drive letter is given e.g. C:\\some-folder\ +// +#include +#include + +std::string get_full_path(const std::string &relative_folder_path) { + char full_path[MAX_PATH]; + + DWORD result = ::GetFullPathNameA(relative_folder_path.c_str(), MAX_PATH, full_path, nullptr); + // Return an empty string if failed to get full path + return result > 0 && result < MAX_PATH ? std::string(full_path) : std::string(); +} + +std::wstring get_full_path(const std::wstring &relative_folder_path) { + wchar_t full_path[MAX_PATH]; + DWORD result = ::GetFullPathNameW(relative_folder_path.c_str(), MAX_PATH, full_path, nullptr); + return result > 0 && result < MAX_PATH ? std::wstring(full_path) : std::wstring(); +} + +spdlog::filename_t::value_type find_non_existing_drive() { + for (char drive = 'A'; drive <= 'Z'; ++drive) { + std::string root_path = std::string(1, drive) + ":\\"; + UINT drive_type = GetDriveTypeA(root_path.c_str()); + if (drive_type == DRIVE_NO_ROOT_DIR) { + return static_cast (drive); + } + } + return '\0'; // No available drive found +} + +TEST_CASE("create_abs_path1", "[create_dir]") { + prepare_logdir(); + auto abs_path = get_full_path(SPDLOG_FILENAME_T("test_logs\\logdir1")); + REQUIRE(!abs_path.empty()); + REQUIRE(create_dir(abs_path) == true); +} + +TEST_CASE("create_abs_path2", "[create_dir]") { + prepare_logdir(); + auto abs_path = get_full_path(SPDLOG_FILENAME_T("test_logs/logdir2")); + REQUIRE(!abs_path.empty()); + REQUIRE(create_dir(abs_path) == true); +} + +TEST_CASE("non_existing_drive", "[create_dir]") { + prepare_logdir(); + spdlog::filename_t path; + + auto non_existing_drive = find_non_existing_drive(); + path += non_existing_drive ; + path += SPDLOG_FILENAME_T(":\\"); + REQUIRE(create_dir(path) == false); + path += SPDLOG_FILENAME_T("subdir"); + REQUIRE(create_dir(path) == false); + +} +//#endif // SPDLOG_WCHAR_FILENAMES +#endif // _WIN32