@@ -649,35 +649,44 @@ impl BoxFileReader {
649649 let symlinks_start = Instant :: now ( ) ;
650650 for ( path, record) in symlinks {
651651 if let Record :: Link ( link) = & record {
652- let link_target = self
653- . resolve_link ( link)
654- . map_err ( |e| ExtractError :: ResolveLinkFailed ( e, link. clone ( ) . into_owned ( ) ) ) ?;
652+ let link_path = output_path. join ( path. to_path_buf ( ) ) ;
653+
654+ // Create parent directory if needed
655+ if let Some ( parent) = link_path. parent ( ) {
656+ fs:: create_dir_all ( parent)
657+ . await
658+ . map_err ( |e| ExtractError :: CreateDirFailed ( e, parent. to_path_buf ( ) ) ) ?;
659+ }
655660
656- let source = output_path . join ( path . to_path_buf ( ) ) ;
657- let destination = output_path . join ( link_target . path . to_path_buf ( ) ) ;
661+ // Use the target as-is (may be relative or absolute)
662+ let target = link . target . to_path_buf ( ) ;
658663
659664 #[ cfg( unix) ]
660665 {
661- tokio:: fs:: symlink ( & destination, & source)
662- . await
663- . map_err ( |e| {
664- ExtractError :: CreateLinkFailed ( e, source. clone ( ) , destination)
665- } ) ?;
666+ tokio:: fs:: symlink ( & target, & link_path) . await . map_err ( |e| {
667+ ExtractError :: CreateLinkFailed ( e, link_path. clone ( ) , target)
668+ } ) ?;
666669 }
667670
668671 #[ cfg( windows) ]
669672 {
670- if link_target. record . as_directory ( ) . is_some ( ) {
671- tokio:: fs:: symlink_dir ( & destination, & source)
673+ // On Windows, we need to know if it's a dir or file symlink
674+ let is_dir = self
675+ . resolve_link ( link)
676+ . map ( |r| r. record . as_directory ( ) . is_some ( ) )
677+ . unwrap_or ( false ) ;
678+
679+ if is_dir {
680+ tokio:: fs:: symlink_dir ( & target, & link_path)
672681 . await
673682 . map_err ( |e| {
674- ExtractError :: CreateLinkFailed ( e, source . clone ( ) , destination )
683+ ExtractError :: CreateLinkFailed ( e, link_path . clone ( ) , target )
675684 } ) ?;
676685 } else {
677- tokio:: fs:: symlink_file ( & destination , & source )
686+ tokio:: fs:: symlink_file ( & target , & link_path )
678687 . await
679688 . map_err ( |e| {
680- ExtractError :: CreateLinkFailed ( e, source . clone ( ) , destination )
689+ ExtractError :: CreateLinkFailed ( e, link_path . clone ( ) , target )
681690 } ) ?;
682691 }
683692 }
@@ -939,34 +948,51 @@ impl BoxFileReader {
939948 }
940949 #[ cfg( unix) ]
941950 Record :: Link ( link) => {
942- let link_target = self
943- . resolve_link ( link)
944- . map_err ( |e| ExtractError :: ResolveLinkFailed ( e, link. clone ( ) . into_owned ( ) ) ) ?;
951+ let link_path = output_path. join ( path. to_path_buf ( ) ) ;
945952
946- let source = output_path. join ( path. to_path_buf ( ) ) ;
947- let destination = output_path. join ( link_target. path . to_path_buf ( ) ) ;
953+ // Create parent directory if needed
954+ if let Some ( parent) = link_path. parent ( ) {
955+ fs:: create_dir_all ( parent)
956+ . await
957+ . map_err ( |e| ExtractError :: CreateDirFailed ( e, parent. to_path_buf ( ) ) ) ?;
958+ }
959+
960+ // Use the target as-is (may be relative or absolute)
961+ let target = link. target . to_path_buf ( ) ;
948962
949- tokio:: fs:: symlink ( & source , & destination )
963+ tokio:: fs:: symlink ( & target , & link_path )
950964 . await
951- . map_err ( |e| ExtractError :: CreateLinkFailed ( e, source , destination ) )
965+ . map_err ( |e| ExtractError :: CreateLinkFailed ( e, link_path , target ) )
952966 }
953967 #[ cfg( windows) ]
954968 Record :: Link ( link) => {
955- let link_target = self
956- . resolve_link ( link)
957- . map_err ( |e| ExtractError :: ResolveLinkFailed ( e, link. clone ( ) . into_owned ( ) ) ) ?;
969+ let link_path = output_path. join ( path. to_path_buf ( ) ) ;
970+
971+ // Create parent directory if needed
972+ if let Some ( parent) = link_path. parent ( ) {
973+ fs:: create_dir_all ( parent)
974+ . await
975+ . map_err ( |e| ExtractError :: CreateDirFailed ( e, parent. to_path_buf ( ) ) ) ?;
976+ }
958977
959- let source = output_path . join ( path . to_path_buf ( ) ) ;
960- let destination = output_path . join ( link_target . path . to_path_buf ( ) ) ;
978+ // Use the target as-is
979+ let target = link . target . to_path_buf ( ) ;
961980
962- if link_target. record . as_directory ( ) . is_some ( ) {
963- tokio:: fs:: symlink_dir ( & source, & destination)
981+ // On Windows, we need to know if it's a dir or file symlink
982+ // Try to resolve to check, but fall back to file symlink
983+ let is_dir = self
984+ . resolve_link ( link)
985+ . map ( |r| r. record . as_directory ( ) . is_some ( ) )
986+ . unwrap_or ( false ) ;
987+
988+ if is_dir {
989+ tokio:: fs:: symlink_dir ( & target, & link_path)
964990 . await
965- . map_err ( |e| ExtractError :: CreateLinkFailed ( e, source , destination ) )
991+ . map_err ( |e| ExtractError :: CreateLinkFailed ( e, link_path , target ) )
966992 } else {
967- tokio:: fs:: symlink_file ( & source , & destination )
993+ tokio:: fs:: symlink_file ( & target , & link_path )
968994 . await
969- . map_err ( |e| ExtractError :: CreateLinkFailed ( e, source , destination ) )
995+ . map_err ( |e| ExtractError :: CreateLinkFailed ( e, link_path , target ) )
970996 }
971997 }
972998 }
@@ -1041,36 +1067,52 @@ impl BoxFileReader {
10411067 }
10421068 #[ cfg( unix) ]
10431069 Record :: Link ( link) => {
1044- let link_target = self
1045- . resolve_link ( link)
1046- . map_err ( |e| ExtractError :: ResolveLinkFailed ( e, link. clone ( ) . into_owned ( ) ) ) ?;
1070+ let link_path = output_path. join ( path. to_path_buf ( ) ) ;
1071+
1072+ // Create parent directory if needed
1073+ if let Some ( parent) = link_path. parent ( ) {
1074+ fs:: create_dir_all ( parent)
1075+ . await
1076+ . map_err ( |e| ExtractError :: CreateDirFailed ( e, parent. to_path_buf ( ) ) ) ?;
1077+ }
10471078
1048- let source = output_path . join ( path . to_path_buf ( ) ) ;
1049- let destination = output_path . join ( link_target . path . to_path_buf ( ) ) ;
1079+ // Use the target as-is (may be relative or absolute)
1080+ let target = link . target . to_path_buf ( ) ;
10501081
1051- tokio:: fs:: symlink ( & source , & destination )
1082+ tokio:: fs:: symlink ( & target , & link_path )
10521083 . await
1053- . map_err ( |e| ExtractError :: CreateLinkFailed ( e, source , destination ) ) ?;
1084+ . map_err ( |e| ExtractError :: CreateLinkFailed ( e, link_path , target ) ) ?;
10541085 stats. links_created += 1 ;
10551086 Ok ( ( ) )
10561087 }
10571088 #[ cfg( windows) ]
10581089 Record :: Link ( link) => {
1059- let link_target = self
1060- . resolve_link ( link)
1061- . map_err ( |e| ExtractError :: ResolveLinkFailed ( e, link. clone ( ) . into_owned ( ) ) ) ?;
1090+ let link_path = output_path. join ( path. to_path_buf ( ) ) ;
1091+
1092+ // Create parent directory if needed
1093+ if let Some ( parent) = link_path. parent ( ) {
1094+ fs:: create_dir_all ( parent)
1095+ . await
1096+ . map_err ( |e| ExtractError :: CreateDirFailed ( e, parent. to_path_buf ( ) ) ) ?;
1097+ }
1098+
1099+ // Use the target as-is
1100+ let target = link. target . to_path_buf ( ) ;
10621101
1063- let source = output_path. join ( path. to_path_buf ( ) ) ;
1064- let destination = output_path. join ( link_target. path . to_path_buf ( ) ) ;
1102+ // On Windows, we need to know if it's a dir or file symlink
1103+ let is_dir = self
1104+ . resolve_link ( link)
1105+ . map ( |r| r. record . as_directory ( ) . is_some ( ) )
1106+ . unwrap_or ( false ) ;
10651107
1066- if link_target . record . as_directory ( ) . is_some ( ) {
1067- tokio:: fs:: symlink_dir ( & source , & destination )
1108+ if is_dir {
1109+ tokio:: fs:: symlink_dir ( & target , & link_path )
10681110 . await
1069- . map_err ( |e| ExtractError :: CreateLinkFailed ( e, source , destination ) ) ?;
1111+ . map_err ( |e| ExtractError :: CreateLinkFailed ( e, link_path , target ) ) ?;
10701112 } else {
1071- tokio:: fs:: symlink_file ( & source , & destination )
1113+ tokio:: fs:: symlink_file ( & target , & link_path )
10721114 . await
1073- . map_err ( |e| ExtractError :: CreateLinkFailed ( e, source , destination ) ) ?;
1115+ . map_err ( |e| ExtractError :: CreateLinkFailed ( e, link_path , target ) ) ?;
10741116 }
10751117 stats. links_created += 1 ;
10761118 Ok ( ( ) )
0 commit comments