From 58c373188be62816daf0a8f22cc9a542642e23ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Steffen=20Schu=CC=88mann?= Date: Sat, 11 Jul 2026 20:40:28 +0200 Subject: [PATCH] Add support for device UNC paths in `canonical()` (#171) --- README.md | 2 ++ include/ghc/filesystem.hpp | 13 +++++++++++++ test/filesystem_test.cpp | 8 ++++++++ 3 files changed, 23 insertions(+) diff --git a/README.md b/README.md index fb3ef3c..2886610 100644 --- a/README.md +++ b/README.md @@ -655,6 +655,8 @@ to the expected behavior. to a host-only UNC path now inserts the missing separator. * Fix for [#170](https://github.com/gulrak/filesystem/issues/170), `lexically_normal()` now preserves IPv6 components in device UNC paths. +* Fix for [#171](https://github.com/gulrak/filesystem/issues/171), `canonical()` + now supports device UNC paths. * Fix for [#185](https://github.com/gulrak/filesystem/issues/185), `lexically_normal()` now preserves unresolved parent components in relative paths. diff --git a/include/ghc/filesystem.hpp b/include/ghc/filesystem.hpp index 463cf4f..58f6ba8 100644 --- a/include/ghc/filesystem.hpp +++ b/include/ghc/filesystem.hpp @@ -3753,6 +3753,19 @@ GHC_INLINE path canonical(const path& p, std::error_code& ec) return path(); } path work = p.is_absolute() ? p : absolute(p, ec); +#ifdef GHC_OS_WINDOWS + const path::impl_string_type deviceUncPrefix(GHC_PLATFORM_LITERAL("\\\\.\\UNC\\")); + const path::impl_string_type extendedUncPrefix(GHC_PLATFORM_LITERAL("\\\\?\\UNC\\")); + auto hasPrefix = [&work](const path::impl_string_type& prefix) { + return work._path.length() > prefix.length() && + std::equal(prefix.begin(), prefix.end(), work._path.begin(), [](path::value_type lhs, path::value_type rhs) { + return std::toupper(static_cast(lhs)) == std::toupper(static_cast(rhs)); + }); + }; + if (hasPrefix(deviceUncPrefix) || hasPrefix(extendedUncPrefix)) { + work = path(GHC_PLATFORM_LITERAL("\\\\") + work._path.substr(deviceUncPrefix.length()), path::native_format); + } +#endif path result; auto fs = status(work, ec); diff --git a/test/filesystem_test.cpp b/test/filesystem_test.cpp index 7752673..6761db2 100644 --- a/test/filesystem_test.cpp +++ b/test/filesystem_test.cpp @@ -2945,6 +2945,14 @@ TEST_CASE("Windows: path namespace handling", "[filesystem][path][fs.path.win.na auto p2 = fs::canonical(p, ec); CHECK(!ec); CHECK(p2 == p); + + auto p3 = fs::canonical(R"(\\.\UNC\localhost\c$\Windows)", ec); + CHECK(!ec); + CHECK(p3 == p); + + auto p4 = fs::canonical(R"(\\?\UNC\localhost\c$\Windows)", ec); + CHECK(!ec); + CHECK(p4 == p); } struct TestInfo