Skip to content

Commit

Permalink
Fix path sanitization edge cases
Browse files Browse the repository at this point in the history
  • Loading branch information
rikyoz committed Jan 23, 2025
1 parent c8a6426 commit 413a2bc
Show file tree
Hide file tree
Showing 4 changed files with 332 additions and 13 deletions.
4 changes: 2 additions & 2 deletions src/internal/fileextractcallback.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,11 +87,11 @@ auto FileExtractCallback::getOutStream( uint32_t index, ISequentialOutStream** o
filePath = tstring_to_path( mRenameCallback( index, filePathString ) );
}

if ( filePath.empty() ) {
if ( filePath.empty() || ( isItemFolder( index ) && filePath == L"/" ) ) {
return S_OK;
}
#if defined( _WIN32 ) && defined( BIT7Z_PATH_SANITIZATION )
mFilePathOnDisk = mDirectoryPath / filesystem::fsutil::sanitize_path( filePath );
mFilePathOnDisk = filesystem::fsutil::sanitized_extraction_path( mDirectoryPath, filePath );
#else
mFilePathOnDisk = mDirectoryPath / filePath;
#endif
Expand Down
26 changes: 22 additions & 4 deletions src/internal/fsutil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -359,7 +359,8 @@ void fsutil::increase_opened_files_limit() {
}

#if defined( _WIN32 ) && defined( BIT7Z_PATH_SANITIZATION )
inline auto is_windows_reserved_name( const std::wstring& component ) -> bool {
namespace {
auto is_windows_reserved_name( const std::wstring& component ) -> bool {
// Reserved file names that can't be used on Windows: CON, PRN, AUX, and NUL.
if ( component == L"CON" || component == L"PRN" || component == L"AUX" || component == L"NUL" ) {
return true;
Expand All @@ -373,7 +374,15 @@ inline auto is_windows_reserved_name( const std::wstring& component ) -> bool {
std::iswdigit( component.back() ) != 0;
}

inline auto sanitize_path_component( std::wstring component ) -> std::wstring {
auto sanitize_path_component( std::wstring component ) -> std::wstring {
const auto firstNonSlash = component.find_first_not_of( L"/\\" );
if ( firstNonSlash == std::wstring::npos ) {
return L"";
}
if ( firstNonSlash != 0 ) {
component.erase( 0, firstNonSlash );
}

// If the component is a reserved name on Windows, we prepend it with a '_' character.
if ( is_windows_reserved_name( component ) ) {
component.insert( 0, 1, L'_' );
Expand All @@ -388,15 +397,24 @@ inline auto sanitize_path_component( std::wstring component ) -> std::wstring {
}, L'_' );
return component;
}
} // namespace

auto fsutil::sanitize_path( const fs::path& path ) -> fs::path {
fs::path sanitizedPath = path.root_path().make_preferred();
for( const auto& pathComponent : path.relative_path() ) {
if ( path == L"/" ) {
return L"_";
}

fs::path sanitizedPath;
for( const auto& pathComponent : path ) {
// cppcheck-suppress useStlAlgorithm
sanitizedPath /= sanitize_path_component( pathComponent.wstring() );
}
return sanitizedPath;
}

auto fsutil::sanitized_extraction_path( const fs::path& outDir, const fs::path& itemPath ) -> fs::path {
return outDir / sanitize_path( itemPath );
}
#endif

} // namespace filesystem
Expand Down
2 changes: 2 additions & 0 deletions src/internal/fsutil.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ void increase_opened_files_limit();
* @return the sanitized path, where illegal characters are replaced with the '_' character.
*/
auto sanitize_path( const fs::path& path ) -> fs::path;

auto sanitized_extraction_path( const fs::path& outDir, const fs::path& itemPath ) -> fs::path;
#endif

} // namespace fsutil
Expand Down
Loading

0 comments on commit 413a2bc

Please sign in to comment.