Skip to content

Commit

Permalink
Fix long path support for UNC paths
Browse files Browse the repository at this point in the history
Close issue #240
  • Loading branch information
rikyoz committed Nov 3, 2024
1 parent 1739c61 commit a0e4831
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 1 deletion.
10 changes: 9 additions & 1 deletion src/internal/fsutil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,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;
Expand All @@ -311,14 +313,20 @@ 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<std::size_t>( MAX_PATH - kMaxDosFilenameSize ) ) {
return false;
}
return !starts_with( pathStr, kLongPathPrefix );
}

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;
}
Expand Down
34 changes: 34 additions & 0 deletions tests/src/test_fsutil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,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" );
Expand Down

0 comments on commit a0e4831

Please sign in to comment.