@@ -299,8 +299,8 @@ where
299
299
////////////////////////////////////////////////////////////////////////////////
300
300
301
301
/// Says whether the first byte after the prefix is a separator.
302
- fn has_physical_root ( s : & [ u8 ] , prefix : Option < Prefix < ' _ > > ) -> bool {
303
- let path = if let Some ( p) = prefix { & s[ p. len ( ) ..] } else { s } ;
302
+ fn has_physical_root ( s : & [ u8 ] , prefix : Option < Prefix < ' _ > > , pre_prefix_len : usize ) -> bool {
303
+ let path = if let Some ( p) = prefix { & s[ p. len ( ) + pre_prefix_len ..] } else { s } ;
304
304
!path. is_empty ( ) && is_sep_byte ( path[ 0 ] )
305
305
}
306
306
@@ -600,6 +600,9 @@ pub struct Components<'a> {
600
600
// The prefix as it was originally parsed, if any
601
601
prefix : Option < Prefix < ' a > > ,
602
602
603
+ // The length of `./` in `//./` on Cygwin
604
+ pre_prefix_len : usize ,
605
+
603
606
// true if path *physically* has a root separator; for most Windows
604
607
// prefixes, it may have a "logical" root separator for the purposes of
605
608
// normalization, e.g., \\server\share == \\server\share\.
@@ -643,7 +646,7 @@ impl<'a> Components<'a> {
643
646
// how long is the prefix, if any?
644
647
#[ inline]
645
648
fn prefix_len ( & self ) -> usize {
646
- self . prefix . as_ref ( ) . map ( Prefix :: len) . unwrap_or ( 0 )
649
+ self . prefix . as_ref ( ) . map ( Prefix :: len) . unwrap_or ( 0 ) + self . pre_prefix_len
647
650
}
648
651
649
652
#[ inline]
@@ -989,7 +992,14 @@ impl FusedIterator for Components<'_> {}
989
992
impl < ' a > PartialEq for Components < ' a > {
990
993
#[ inline]
991
994
fn eq ( & self , other : & Components < ' a > ) -> bool {
992
- let Components { path : _, front : _, back : _, has_physical_root : _, prefix : _ } = self ;
995
+ let Components {
996
+ path : _,
997
+ front : _,
998
+ back : _,
999
+ has_physical_root : _,
1000
+ prefix : _,
1001
+ pre_prefix_len : _,
1002
+ } = self ;
993
1003
994
1004
// Fast path for exact matches, e.g. for hashmap lookups.
995
1005
// Don't explicitly compare the prefix or has_physical_root fields since they'll
@@ -999,6 +1009,7 @@ impl<'a> PartialEq for Components<'a> {
999
1009
&& self . back == State :: Body
1000
1010
&& other. back == State :: Body
1001
1011
&& self . prefix_verbatim ( ) == other. prefix_verbatim ( )
1012
+ && self . pre_prefix_len == other. pre_prefix_len
1002
1013
{
1003
1014
// possible future improvement: this could bail out earlier if there were a
1004
1015
// reverse memcmp/bcmp comparing back to front
@@ -1315,8 +1326,17 @@ impl PathBuf {
1315
1326
need_sep = false
1316
1327
}
1317
1328
1329
+ let need_clear = if cfg ! ( target_os = "cygwin" ) {
1330
+ // If path is absolute and its prefix is none, it is like `/foo`,
1331
+ // and will be handled below.
1332
+ path. prefix ( ) . is_some ( )
1333
+ } else {
1334
+ // On Unix: prefix is always None.
1335
+ path. is_absolute ( ) || path. prefix ( ) . is_some ( )
1336
+ } ;
1337
+
1318
1338
// absolute `path` replaces `self`
1319
- if path . is_absolute ( ) || path . prefix ( ) . is_some ( ) {
1339
+ if need_clear {
1320
1340
self . inner . truncate ( 0 ) ;
1321
1341
1322
1342
// verbatim paths need . and .. removed
@@ -2862,11 +2882,15 @@ impl Path {
2862
2882
/// [`CurDir`]: Component::CurDir
2863
2883
#[ stable( feature = "rust1" , since = "1.0.0" ) ]
2864
2884
pub fn components ( & self ) -> Components < ' _ > {
2865
- let prefix = parse_prefix ( self . as_os_str ( ) ) ;
2885
+ let ( pre_prefix_len, prefix) = match parse_prefix ( self . as_os_str ( ) ) {
2886
+ Some ( ( pre_prefix_len, prefix) ) => ( pre_prefix_len, Some ( prefix) ) ,
2887
+ None => ( 0 , None ) ,
2888
+ } ;
2866
2889
Components {
2867
2890
path : self . as_u8_slice ( ) ,
2868
2891
prefix,
2869
- has_physical_root : has_physical_root ( self . as_u8_slice ( ) , prefix) ,
2892
+ pre_prefix_len,
2893
+ has_physical_root : has_physical_root ( self . as_u8_slice ( ) , prefix, pre_prefix_len) ,
2870
2894
front : State :: Prefix ,
2871
2895
back : State :: Body ,
2872
2896
}
@@ -3330,9 +3354,9 @@ impl Hash for Path {
3330
3354
fn hash < H : Hasher > ( & self , h : & mut H ) {
3331
3355
let bytes = self . as_u8_slice ( ) ;
3332
3356
let ( prefix_len, verbatim) = match parse_prefix ( & self . inner ) {
3333
- Some ( prefix) => {
3357
+ Some ( ( pre_prefix_len , prefix) ) => {
3334
3358
prefix. hash ( h) ;
3335
- ( prefix. len ( ) , prefix. is_verbatim ( ) )
3359
+ ( prefix. len ( ) + pre_prefix_len , prefix. is_verbatim ( ) )
3336
3360
}
3337
3361
None => ( 0 , false ) ,
3338
3362
} ;
@@ -3615,6 +3639,9 @@ impl Error for NormalizeError {}
3615
3639
/// paths, this is currently equivalent to calling
3616
3640
/// [`GetFullPathNameW`][windows-path].
3617
3641
///
3642
+ /// On Cygwin, this is currently equivalent to calling [`cygwin_conv_path`][cygwin-path]
3643
+ /// with mode `CCP_WIN_A_TO_POSIX`.
3644
+ ///
3618
3645
/// Note that these [may change in the future][changes].
3619
3646
///
3620
3647
/// # Errors
@@ -3667,11 +3694,36 @@ impl Error for NormalizeError {}
3667
3694
/// # fn main() {}
3668
3695
/// ```
3669
3696
///
3697
+ /// ## Cygwin paths
3698
+ ///
3699
+ /// ```
3700
+ /// # #[cfg(target_os = "cygwin")]
3701
+ /// fn main() -> std::io::Result<()> {
3702
+ /// use std::path::{self, Path};
3703
+ ///
3704
+ /// // Relative to absolute
3705
+ /// let absolute = path::absolute("foo/./bar")?;
3706
+ /// assert!(absolute.ends_with(r"foo/bar"));
3707
+ ///
3708
+ /// // Windows absolute to absolute
3709
+ /// let absolute = path::absolute(r"C:\foo//test\..\./bar.rs")?;
3710
+ /// assert!(absolute.ends_with("/c/foo/bar.rs"));
3711
+ ///
3712
+ /// // POSIX absolute to absolute
3713
+ /// let absolute = path::absolute("/foo//test/.././bar.rs")?;
3714
+ /// assert_eq!(absolute, Path::new("/foo//test/.././bar.rs"));
3715
+ /// Ok(())
3716
+ /// }
3717
+ /// # #[cfg(not(target_os = "cygwin"))]
3718
+ /// # fn main() {}
3719
+ /// ```
3720
+ ///
3670
3721
/// Note that this [may change in the future][changes].
3671
3722
///
3672
3723
/// [changes]: io#platform-specific-behavior
3673
3724
/// [posix-semantics]: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_13
3674
3725
/// [windows-path]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfullpathnamew
3726
+ /// [cygwin-path]: https://cygwin.com/cygwin-api/func-cygwin-conv-path.html
3675
3727
#[ stable( feature = "absolute_path" , since = "1.79.0" ) ]
3676
3728
pub fn absolute < P : AsRef < Path > > ( path : P ) -> io:: Result < PathBuf > {
3677
3729
let path = path. as_ref ( ) ;
0 commit comments