@@ -95,7 +95,7 @@ pub enum ExtractError {
9595 #[ error( "Creating link failed. Path: '{}' -> '{}'" , . 1 . display( ) , . 2 . display( ) ) ]
9696 CreateLinkFailed ( #[ source] std:: io:: Error , PathBuf , PathBuf ) ,
9797
98- #[ error( "Resolving link failed: Path: '{}' -> '{}' " , . 1 . name, . 1 . target) ]
98+ #[ error( "Resolving link failed: Path: '{}' -> index {} " , . 1 . name, . 1 . target. get ( ) ) ]
9999 ResolveLinkFailed ( #[ source] std:: io:: Error , LinkRecord < ' static > ) ,
100100
101101 #[ error( "Could not convert to a valid Box path. Path suffix: '{}'" , . 1 ) ]
@@ -658,8 +658,17 @@ impl BoxFileReader {
658658 . map_err ( |e| ExtractError :: CreateDirFailed ( e, parent. to_path_buf ( ) ) ) ?;
659659 }
660660
661- // Use the target as-is (may be relative or absolute)
662- let target = link. target . to_path_buf ( ) ;
661+ // Resolve target index to path and compute relative symlink target
662+ let target_path = self . meta . path_for_index ( link. target ) . ok_or_else ( || {
663+ ExtractError :: ResolveLinkFailed (
664+ std:: io:: Error :: new (
665+ std:: io:: ErrorKind :: NotFound ,
666+ format ! ( "No path for target index: {}" , link. target. get( ) ) ,
667+ ) ,
668+ link. clone ( ) . into_owned ( ) ,
669+ )
670+ } ) ?;
671+ let target = self . compute_relative_symlink_target ( & path, & target_path) ;
663672
664673 #[ cfg( unix) ]
665674 {
@@ -874,17 +883,43 @@ impl BoxFileReader {
874883 }
875884
876885 pub fn resolve_link ( & self , link : & LinkRecord < ' _ > ) -> std:: io:: Result < RecordsItem < ' _ , ' static > > {
877- match self . meta . index ( & link. target ) {
878- Some ( index) => Ok ( RecordsItem {
879- index,
880- path : link. target . clone ( ) . into_owned ( ) ,
881- record : self . meta . record ( index) . unwrap ( ) ,
882- } ) ,
883- None => Err ( std:: io:: Error :: new (
886+ let index = link. target ;
887+ let record = self . meta . record ( index) . ok_or_else ( || {
888+ std:: io:: Error :: new (
884889 std:: io:: ErrorKind :: NotFound ,
885- format ! ( "No record for link target: {}" , link. target) ,
886- ) ) ,
887- }
890+ format ! ( "No record for link target index: {}" , index. get( ) ) ,
891+ )
892+ } ) ?;
893+ let path = self . meta . path_for_index ( index) . ok_or_else ( || {
894+ std:: io:: Error :: new (
895+ std:: io:: ErrorKind :: NotFound ,
896+ format ! ( "Could not find path for link target index: {}" , index. get( ) ) ,
897+ )
898+ } ) ?;
899+ Ok ( RecordsItem {
900+ index,
901+ path,
902+ record,
903+ } )
904+ }
905+
906+ /// Compute the relative path from a link's location to its target.
907+ ///
908+ /// Given the link's path and target's path, computes the relative symlink target
909+ /// (e.g., "../x86_64-unknown-linux-musl/libclang_rt.builtins.a").
910+ fn compute_relative_symlink_target (
911+ & self ,
912+ link_path : & BoxPath < ' _ > ,
913+ target_path : & BoxPath < ' _ > ,
914+ ) -> PathBuf {
915+ let link_parent = link_path
916+ . parent ( )
917+ . map ( |p| p. to_path_buf ( ) )
918+ . unwrap_or_default ( ) ;
919+ let target = target_path. to_path_buf ( ) ;
920+
921+ // Use pathdiff to compute relative path, or fall back to target if it fails
922+ pathdiff:: diff_paths ( & target, & link_parent) . unwrap_or ( target)
888923 }
889924
890925 pub async fn read_bytes (
@@ -957,8 +992,17 @@ impl BoxFileReader {
957992 . map_err ( |e| ExtractError :: CreateDirFailed ( e, parent. to_path_buf ( ) ) ) ?;
958993 }
959994
960- // Use the target as-is (may be relative or absolute)
961- let target = link. target . to_path_buf ( ) ;
995+ // Resolve target index to path and compute relative symlink target
996+ let target_path = self . meta . path_for_index ( link. target ) . ok_or_else ( || {
997+ ExtractError :: ResolveLinkFailed (
998+ std:: io:: Error :: new (
999+ std:: io:: ErrorKind :: NotFound ,
1000+ format ! ( "No path for target index: {}" , link. target. get( ) ) ,
1001+ ) ,
1002+ link. clone ( ) . into_owned ( ) ,
1003+ )
1004+ } ) ?;
1005+ let target = self . compute_relative_symlink_target ( path, & target_path) ;
9621006
9631007 tokio:: fs:: symlink ( & target, & link_path)
9641008 . await
@@ -975,11 +1019,19 @@ impl BoxFileReader {
9751019 . map_err ( |e| ExtractError :: CreateDirFailed ( e, parent. to_path_buf ( ) ) ) ?;
9761020 }
9771021
978- // Use the target as-is
979- let target = link. target . to_path_buf ( ) ;
1022+ // Resolve target index to path and compute relative symlink target
1023+ let target_path = self . meta . path_for_index ( link. target ) . ok_or_else ( || {
1024+ ExtractError :: ResolveLinkFailed (
1025+ std:: io:: Error :: new (
1026+ std:: io:: ErrorKind :: NotFound ,
1027+ format ! ( "No path for target index: {}" , link. target. get( ) ) ,
1028+ ) ,
1029+ link. clone ( ) . into_owned ( ) ,
1030+ )
1031+ } ) ?;
1032+ let target = self . compute_relative_symlink_target ( path, & target_path) ;
9801033
9811034 // 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
9831035 let is_dir = self
9841036 . resolve_link ( link)
9851037 . map ( |r| r. record . as_directory ( ) . is_some ( ) )
@@ -1076,8 +1128,17 @@ impl BoxFileReader {
10761128 . map_err ( |e| ExtractError :: CreateDirFailed ( e, parent. to_path_buf ( ) ) ) ?;
10771129 }
10781130
1079- // Use the target as-is (may be relative or absolute)
1080- let target = link. target . to_path_buf ( ) ;
1131+ // Resolve target index to path and compute relative symlink target
1132+ let target_path = self . meta . path_for_index ( link. target ) . ok_or_else ( || {
1133+ ExtractError :: ResolveLinkFailed (
1134+ std:: io:: Error :: new (
1135+ std:: io:: ErrorKind :: NotFound ,
1136+ format ! ( "No path for target index: {}" , link. target. get( ) ) ,
1137+ ) ,
1138+ link. clone ( ) . into_owned ( ) ,
1139+ )
1140+ } ) ?;
1141+ let target = self . compute_relative_symlink_target ( path, & target_path) ;
10811142
10821143 tokio:: fs:: symlink ( & target, & link_path)
10831144 . await
@@ -1096,8 +1157,17 @@ impl BoxFileReader {
10961157 . map_err ( |e| ExtractError :: CreateDirFailed ( e, parent. to_path_buf ( ) ) ) ?;
10971158 }
10981159
1099- // Use the target as-is
1100- let target = link. target . to_path_buf ( ) ;
1160+ // Resolve target index to path and compute relative symlink target
1161+ let target_path = self . meta . path_for_index ( link. target ) . ok_or_else ( || {
1162+ ExtractError :: ResolveLinkFailed (
1163+ std:: io:: Error :: new (
1164+ std:: io:: ErrorKind :: NotFound ,
1165+ format ! ( "No path for target index: {}" , link. target. get( ) ) ,
1166+ ) ,
1167+ link. clone ( ) . into_owned ( ) ,
1168+ )
1169+ } ) ?;
1170+ let target = self . compute_relative_symlink_target ( path, & target_path) ;
11011171
11021172 // On Windows, we need to know if it's a dir or file symlink
11031173 let is_dir = self
0 commit comments