@@ -359,14 +359,29 @@ impl Header {
359359 /// in the appropriate format. May fail if the path is too long or if the
360360 /// path specified is not Unicode and this is a Windows platform.
361361 pub fn set_path < P : AsRef < Path > > ( & mut self , p : P ) -> io:: Result < ( ) > {
362- self . _set_path ( p. as_ref ( ) )
362+ self . set_path_inner ( p. as_ref ( ) , false )
363363 }
364364
365- fn _set_path ( & mut self , path : & Path ) -> io:: Result < ( ) > {
365+ // Sets the truncated path for GNU header
366+ //
367+ // Same as `set_path`` but skips some validations.
368+ pub ( crate ) fn set_truncated_path_for_gnu_header < P : AsRef < Path > > (
369+ & mut self ,
370+ p : P ,
371+ ) -> io:: Result < ( ) > {
372+ self . set_path_inner ( p. as_ref ( ) , true )
373+ }
374+
375+ fn set_path_inner ( & mut self , path : & Path , is_truncated_gnu_long_path : bool ) -> io:: Result < ( ) > {
366376 if let Some ( ustar) = self . as_ustar_mut ( ) {
367377 return ustar. set_path ( path) ;
368378 }
369- copy_path_into ( & mut self . as_old_mut ( ) . name , path, false ) . map_err ( |err| {
379+ if is_truncated_gnu_long_path {
380+ copy_path_into_gnu_long ( & mut self . as_old_mut ( ) . name , path, false )
381+ } else {
382+ copy_path_into ( & mut self . as_old_mut ( ) . name , path, false )
383+ }
384+ . map_err ( |err| {
370385 io:: Error :: new (
371386 err. kind ( ) ,
372387 format ! ( "{} when setting path for {}" , err, self . path_lossy( ) ) ,
@@ -1465,25 +1480,29 @@ fn copy_into(slot: &mut [u8], bytes: &[u8]) -> io::Result<()> {
14651480 }
14661481}
14671482
1468- /// Copies `path` into the `slot` provided
1469- ///
1470- /// Returns an error if:
1471- ///
1472- /// * the path is too long to fit
1473- /// * a nul byte was found
1474- /// * an invalid path component is encountered (e.g. a root path or parent dir)
1475- /// * the path itself is empty
1476- fn copy_path_into ( mut slot : & mut [ u8 ] , path : & Path , is_link_name : bool ) -> io:: Result < ( ) > {
1483+ fn copy_path_into_inner (
1484+ mut slot : & mut [ u8 ] ,
1485+ path : & Path ,
1486+ is_link_name : bool ,
1487+ is_truncated_gnu_long_path : bool ,
1488+ ) -> io:: Result < ( ) > {
14771489 let mut emitted = false ;
14781490 let mut needs_slash = false ;
1479- for component in path. components ( ) {
1491+ let mut iter = path. components ( ) . peekable ( ) ;
1492+ while let Some ( component) = iter. next ( ) {
14801493 let bytes = path2bytes ( Path :: new ( component. as_os_str ( ) ) ) ?;
14811494 match ( component, is_link_name) {
14821495 ( Component :: Prefix ( ..) , false ) | ( Component :: RootDir , false ) => {
14831496 return Err ( other ( "paths in archives must be relative" ) ) ;
14841497 }
14851498 ( Component :: ParentDir , false ) => {
1486- return Err ( other ( "paths in archives must not have `..`" ) ) ;
1499+ if is_truncated_gnu_long_path && iter. peek ( ) . is_none ( ) {
1500+ // If it's last component of a gnu long path we know that there might be more
1501+ // to the component than .. (the rest is stored elsewhere)
1502+ { }
1503+ } else {
1504+ return Err ( other ( "paths in archives must not have `..`" ) ) ;
1505+ }
14871506 }
14881507 // Allow "./" as the path
14891508 ( Component :: CurDir , false ) if path. components ( ) . count ( ) == 1 => { }
@@ -1520,6 +1539,32 @@ fn copy_path_into(mut slot: &mut [u8], path: &Path, is_link_name: bool) -> io::R
15201539 }
15211540}
15221541
1542+ /// Copies `path` into the `slot` provided
1543+ ///
1544+ /// Returns an error if:
1545+ ///
1546+ /// * the path is too long to fit
1547+ /// * a nul byte was found
1548+ /// * an invalid path component is encountered (e.g. a root path or parent dir)
1549+ /// * the path itself is empty
1550+ fn copy_path_into ( slot : & mut [ u8 ] , path : & Path , is_link_name : bool ) -> io:: Result < ( ) > {
1551+ copy_path_into_inner ( slot, path, is_link_name, false )
1552+ }
1553+
1554+ /// Copies `path` into the `slot` provided
1555+ ///
1556+ /// Returns an error if:
1557+ ///
1558+ /// * the path is too long to fit
1559+ /// * a nul byte was found
1560+ /// * an invalid path component is encountered (e.g. a root path or parent dir)
1561+ /// * the path itself is empty
1562+ ///
1563+ /// This is less restrictive version meant to be used for truncated GNU paths.
1564+ fn copy_path_into_gnu_long ( slot : & mut [ u8 ] , path : & Path , is_link_name : bool ) -> io:: Result < ( ) > {
1565+ copy_path_into_inner ( slot, path, is_link_name, true )
1566+ }
1567+
15231568#[ cfg( target_arch = "wasm32" ) ]
15241569fn ends_with_slash ( p : & Path ) -> bool {
15251570 p. to_string_lossy ( ) . ends_with ( '/' )
0 commit comments