33#[ cfg( unix) ]
44use std:: os:: unix:: fs:: PermissionsExt ;
55use std:: {
6- env,
76 io:: { self , prelude:: * } ,
87 path:: { Path , PathBuf } ,
98} ;
@@ -15,6 +14,8 @@ use same_file::Handle;
1514use time:: OffsetDateTime ;
1615use zip:: { self , DateTime , ZipArchive , read:: ZipFile } ;
1716
17+ #[ cfg( unix) ]
18+ use crate :: utils:: sanitize_archive_mode;
1819use crate :: {
1920 Result ,
2021 error:: FinalError ,
@@ -23,7 +24,7 @@ use crate::{
2324 utils:: {
2425 BytesFmt , FileType , FileVisibilityPolicy , PathFmt , canonicalize, cd_into_same_dir_as, create_symlink,
2526 ensure_parent_dir_exists, get_invalid_utf8_paths, is_same_file_as_output, pretty_format_list_of_paths,
26- read_file_type, strip_cur_dir,
27+ read_file_type, strip_cur_dir, validate_symlink_target ,
2728 } ,
2829 warning,
2930} ;
@@ -42,12 +43,12 @@ where
4243 Some ( password) => archive. by_index_decrypt ( idx, password) ?,
4344 None => archive. by_index ( idx) ?,
4445 } ;
45- let file_path = match file. enclosed_name ( ) {
46+ let relpath = match file. enclosed_name ( ) {
4647 Some ( path) => path. to_owned ( ) ,
4748 None => continue ,
4849 } ;
4950
50- let file_path = output_folder. join ( file_path ) ;
51+ let file_path = output_folder. join ( & relpath ) ;
5152
5253 display_zip_comment_if_exists ( & file) ;
5354
6263 let mut target = String :: new ( ) ;
6364 file. read_to_string ( & mut target) ?;
6465
66+ validate_symlink_target ( & relpath, std:: path:: Path :: new ( & target) ) ?;
6567 #[ cfg( unix) ]
6668 std:: os:: unix:: fs:: symlink ( & target, & file_path) ?;
6769 #[ cfg( windows) ]
@@ -81,10 +83,23 @@ where
8183 let mut target = String :: new ( ) ;
8284 file. read_to_string ( & mut target) ?;
8385
86+ validate_symlink_target ( & relpath, std:: path:: Path :: new ( & target) ) ?;
8487 info ! ( "linking {} -> \" {}\" " , PathFmt ( file_path) , target) ;
8588
8689 create_symlink ( Path :: new ( & target) , file_path) ?;
8790 } else {
91+ #[ cfg( unix) ]
92+ let mut output_file = {
93+ use fs_err:: os:: unix:: fs:: OpenOptionsExt ;
94+ let mode = file. unix_mode ( ) . map ( sanitize_archive_mode) . unwrap_or ( 0o644 ) ;
95+ fs:: OpenOptions :: new ( )
96+ . write ( true )
97+ . create ( true )
98+ . truncate ( true )
99+ . mode ( mode)
100+ . open ( file_path) ?
101+ } ;
102+ #[ cfg( not( unix) ) ]
88103 let mut output_file = fs:: File :: create ( file_path) ?;
89104 io:: copy ( & mut file, & mut output_file) ?;
90105 set_last_modified_time ( & file, file_path) ?;
@@ -182,6 +197,7 @@ where
182197
183198 for explicit_path in input_filenames {
184199 let previous_location = cd_into_same_dir_as ( explicit_path) ?;
200+ let _cwd_guard = crate :: utils:: CwdGuard :: new ( previous_location) ;
185201
186202 // Unwrap safety:
187203 // paths should be canonicalized by now, and the root directory rejected.
@@ -255,8 +271,6 @@ where
255271 }
256272 }
257273 }
258-
259- env:: set_current_dir ( previous_location) ?;
260274 }
261275
262276 let bytes = writer. finish ( ) ?;
@@ -311,7 +325,7 @@ fn unix_set_permissions<R: Read>(file_path: &Path, file: &ZipFile<'_, R>) -> Res
311325 use std:: fs:: Permissions ;
312326
313327 if let Some ( mode) = file. unix_mode ( ) {
314- fs:: set_permissions ( file_path, Permissions :: from_mode ( mode) ) ?;
328+ fs:: set_permissions ( file_path, Permissions :: from_mode ( sanitize_archive_mode ( mode) ) ) ?;
315329 }
316330
317331 Ok ( ( ) )
0 commit comments