@@ -534,4 +534,111 @@ mod tests {
534534 let editor = PathnameEditor :: new ( Some ( 2 ) , None , false , true ) ;
535535 assert ! ( editor. edit_entry_name( Path :: new( "./a" ) ) . is_none( ) ) ;
536536 }
537+
538+ // --- Windows path prefix stripping (bsdtar test_windows compat) ---
539+ //
540+ // bsdtar's strip_absolute_path() strips Windows API prefixes, drive letters,
541+ // and leading separators. On Windows, Rust's Path::components() correctly
542+ // parses these as Prefix/RootDir components, which sanitize_preserve_curdir
543+ // filters out — producing the same result as bsdtar.
544+ //
545+ // These 8 types correspond to bsdtar's test_windows.c mkfullpath() types.
546+
547+ #[ cfg( windows) ]
548+ #[ test]
549+ fn editor_windows_type0_forward_slash_absolute ( ) {
550+ // Type 0: /path/to/file — leading / stripped
551+ let editor = PathnameEditor :: new ( None , None , false , true ) ;
552+ let name = editor
553+ . edit_entry_name ( Path :: new ( "/msys64/tmp/file" ) )
554+ . unwrap ( ) ;
555+ assert_eq ! ( name. as_str( ) , "msys64/tmp/file" ) ;
556+ }
557+
558+ #[ cfg( windows) ]
559+ #[ test]
560+ fn editor_windows_type1_backslash_absolute ( ) {
561+ // Type 1: \path\to\file — leading \ stripped
562+ let editor = PathnameEditor :: new ( None , None , false , true ) ;
563+ let name = editor
564+ . edit_entry_name ( Path :: new ( "\\ msys64\\ tmp\\ file" ) )
565+ . unwrap ( ) ;
566+ assert_eq ! ( name. as_str( ) , "msys64/tmp/file" ) ;
567+ }
568+
569+ #[ cfg( windows) ]
570+ #[ test]
571+ fn editor_windows_type2_drive_forward_slash ( ) {
572+ // Type 2: C:/path/to/file — C: and / stripped
573+ let editor = PathnameEditor :: new ( None , None , false , true ) ;
574+ let name = editor
575+ . edit_entry_name ( Path :: new ( "C:/msys64/tmp/file" ) )
576+ . unwrap ( ) ;
577+ assert_eq ! ( name. as_str( ) , "msys64/tmp/file" ) ;
578+ }
579+
580+ #[ cfg( windows) ]
581+ #[ test]
582+ fn editor_windows_type3_drive_backslash ( ) {
583+ // Type 3: C:\path\to\file — C: and \ stripped
584+ let editor = PathnameEditor :: new ( None , None , false , true ) ;
585+ let name = editor
586+ . edit_entry_name ( Path :: new ( "C:\\ msys64\\ tmp\\ file" ) )
587+ . unwrap ( ) ;
588+ assert_eq ! ( name. as_str( ) , "msys64/tmp/file" ) ;
589+ }
590+
591+ #[ cfg( windows) ]
592+ #[ test]
593+ fn editor_windows_type4_device_forward_slash ( ) {
594+ // Type 4: //./C:/path/to/file — //./ and C: and / stripped
595+ let editor = PathnameEditor :: new ( None , None , false , true ) ;
596+ let name = editor
597+ . edit_entry_name ( Path :: new ( "//./C:/msys64/tmp/file" ) )
598+ . unwrap ( ) ;
599+ assert_eq ! ( name. as_str( ) , "msys64/tmp/file" ) ;
600+ }
601+
602+ #[ cfg( windows) ]
603+ #[ test]
604+ fn editor_windows_type5_device_backslash ( ) {
605+ // Type 5: \\.\C:\path\to\file — \\.\ and C: and \ stripped
606+ let editor = PathnameEditor :: new ( None , None , false , true ) ;
607+ let name = editor
608+ . edit_entry_name ( Path :: new ( "\\ \\ .\\ C:\\ msys64\\ tmp\\ file" ) )
609+ . unwrap ( ) ;
610+ assert_eq ! ( name. as_str( ) , "msys64/tmp/file" ) ;
611+ }
612+
613+ #[ cfg( windows) ]
614+ #[ test]
615+ fn editor_windows_type6_verbatim_forward_slash ( ) {
616+ // Type 6: //?/C:/path/to/file — //?/ and C: and / stripped
617+ let editor = PathnameEditor :: new ( None , None , false , true ) ;
618+ let name = editor
619+ . edit_entry_name ( Path :: new ( "//?/C:/msys64/tmp/file" ) )
620+ . unwrap ( ) ;
621+ assert_eq ! ( name. as_str( ) , "msys64/tmp/file" ) ;
622+ }
623+
624+ #[ cfg( windows) ]
625+ #[ test]
626+ fn editor_windows_type7_verbatim_backslash ( ) {
627+ // Type 7: \\?\C:\path\to\file — \\?\ and C: and \ stripped
628+ let editor = PathnameEditor :: new ( None , None , false , true ) ;
629+ let name = editor
630+ . edit_entry_name ( Path :: new ( "\\ \\ ?\\ C:\\ msys64\\ tmp\\ file" ) )
631+ . unwrap ( ) ;
632+ assert_eq ! ( name. as_str( ) , "msys64/tmp/file" ) ;
633+ }
634+
635+ #[ cfg( windows) ]
636+ #[ test]
637+ fn editor_windows_backslash_to_forward_slash_conversion ( ) {
638+ // bsdtar converts \ to / in entry names; pna's join_components_forward_slash
639+ // achieves the same by reconstructing paths with / separators.
640+ let editor = PathnameEditor :: new ( None , None , false , true ) ;
641+ let name = editor. edit_entry_name ( Path :: new ( "C:\\ a\\ b\\ c" ) ) . unwrap ( ) ;
642+ assert_eq ! ( name. as_str( ) , "a/b/c" ) ;
643+ }
537644}
0 commit comments