diff --git a/src/internal/fsutil.cpp b/src/internal/fsutil.cpp index 0c9db1e2..04b99f7a 100644 --- a/src/internal/fsutil.cpp +++ b/src/internal/fsutil.cpp @@ -307,7 +307,9 @@ auto fsutil::get_file_attributes_ex( const fs::path& filePath, #if defined( _WIN32 ) && defined( BIT7Z_AUTO_PREFIX_LONG_PATHS ) +namespace { constexpr auto kLongPathPrefix = BIT7Z_NATIVE_STRING( R"(\\?\)" ); +} // namespace auto fsutil::should_format_long_path( const fs::path& path ) -> bool { constexpr auto kMaxDosFilenameSize = 12; @@ -316,7 +318,7 @@ auto fsutil::should_format_long_path( const fs::path& path ) -> bool { return false; } const auto& pathStr = path.native(); - if ( pathStr.size() < ( MAX_PATH - kMaxDosFilenameSize ) ) { + if ( pathStr.size() < static_cast( MAX_PATH - kMaxDosFilenameSize ) ) { return false; } return !starts_with( pathStr, kLongPathPrefix ); @@ -324,6 +326,12 @@ auto fsutil::should_format_long_path( const fs::path& path ) -> bool { auto fsutil::format_long_path( const fs::path& path ) -> fs::path { fs::path longPath = kLongPathPrefix; + // Note: we call this function after checking if we should format the given path as a long path. + // This means that if the path starts with the \\ prefix, + // it is a UNC path and not a long path prefixed with \\?\. + if ( starts_with( path.native(), BIT7Z_NATIVE_STRING( R"(\\)" ) ) ) { + longPath += L"UNC\\"; + } longPath += path; return longPath; } diff --git a/tests/src/test_fsutil.cpp b/tests/src/test_fsutil.cpp index 1751be27..cbadd328 100644 --- a/tests/src/test_fsutil.cpp +++ b/tests/src/test_fsutil.cpp @@ -234,6 +234,40 @@ TEST_CASE( "fsutil: In-archive path computation", "[fsutil][in_archive_path]" ) #endif +#if defined( _WIN32 ) && defined( BIT7Z_AUTO_PREFIX_LONG_PATHS ) +TEST_CASE( "fsutil: Format long Windows paths", "[fsutil][format_long_path]" ) { + const std::wstring kLongPathPrefix = BIT7Z_NATIVE_STRING( R"(\\?\)" ); + + constexpr auto short_path = L"short_path\\file.txt"; + REQUIRE_FALSE( should_format_long_path( short_path ) ); + + constexpr auto very_long_path = LR"(C:\very\long\dummy\path\)" + LR"(ABCDEFGHIJKLMNOPQRSTUVWXYZ\abcdefghijklmnopqrstuvwxyz\0123456789\)" + LR"(Lorem ipsum dolor sit amet\consectetur adipiscing elit\)" + LR"(Mauris ac leo dui\Morbi non elit lacus\)" + LR"(Ut ullamcorper sapien eget commodo eleifend\Curabitur varius magna sit\)" + LR"(Hello_World.txt)"; + REQUIRE( should_format_long_path( very_long_path ) ); + REQUIRE( format_long_path( very_long_path ) == ( kLongPathPrefix + very_long_path ) ); + + + const auto prefixed_very_long_path = std::wstring{ LR"(\\?\)" } + very_long_path; + REQUIRE_FALSE( should_format_long_path( prefixed_very_long_path ) ); + + constexpr auto very_long_unc_path = LR"(\\very\long\dummy\UNC\path\)" + LR"(ABCDEFGHIJKLMNOPQRSTUVWXYZ\abcdefghijklmnopqrstuvwxyz\0123456789\)" + LR"(Lorem ipsum dolor sit amet\consectetur adipiscing elit\)" + LR"(Mauris ac leo dui\Morbi non elit lacus\)" + LR"(Ut ullamcorper sapien eget commodo eleifend\Curabitur varius magna sit\)" + LR"(Hello_World.txt)"; + REQUIRE( should_format_long_path( very_long_unc_path ) ); + REQUIRE( format_long_path( very_long_unc_path ) == ( kLongPathPrefix + L"UNC\\" + very_long_unc_path ) ); + + const auto prefixed_very_long_unc_path = std::wstring{ LR"(\\?\UNC\)" } + very_long_unc_path; + REQUIRE_FALSE( should_format_long_path( prefixed_very_long_unc_path ) ); +} +#endif + #if defined( _WIN32 ) && defined( BIT7Z_PATH_SANITIZATION ) TEST_CASE( "fsutil: Sanitizing Windows paths", "[fsutil][sanitize_path]" ) { REQUIRE( sanitize_path( L"hello world.txt" ) == L"hello world.txt" );