@@ -148,6 +148,11 @@ impl AbsolutePath {
148148
149149 /// Returns a path that, when joined onto base, yields self.
150150 ///
151+ /// On Windows, path namespace prefixes (`\\?\`, `\\.\`, and `\??\`) are
152+ /// ignored before matching. In that case the returned path round-trips
153+ /// against the prefix-normalized paths rather than necessarily preserving
154+ /// the original namespace prefix.
155+ ///
151156 /// If `base` is not a prefix of `self`, returns [`None`].
152157 ///
153158 /// If the stripped path is not a valid `RelativePath`. Returns an error with the reason and the stripped path.
@@ -160,18 +165,12 @@ impl AbsolutePath {
160165 base : P ,
161166 ) -> Result < Option < RelativePathBuf > , StripPrefixError < ' _ > > {
162167 let base = base. as_ref ( ) ;
163- let Ok ( stripped_path) = self . 0 . strip_prefix ( & base. 0 ) else {
168+ let Ok ( stripped_path) =
169+ crate :: strip_path_prefix ( self . as_path ( ) . as_os_str ( ) , base. as_path ( ) . as_os_str ( ) )
170+ else {
164171 return Ok ( None ) ;
165172 } ;
166- match RelativePathBuf :: new ( stripped_path) {
167- Ok ( relative_path) => Ok ( Some ( relative_path) ) ,
168- Err ( FromPathError :: NonRelative ) => {
169- unreachable ! ( "stripped path should always be relative" )
170- }
171- Err ( FromPathError :: InvalidPathData ( invalid_path_data_error) ) => {
172- Err ( StripPrefixError { stripped_path, invalid_path_data_error } )
173- }
174- }
173+ stripped_path_to_relative ( stripped_path) . map ( Some )
175174 }
176175
177176 /// Creates an owned [`AbsolutePathBuf`] with `path` adjoined to `self`.
@@ -220,6 +219,20 @@ impl AbsolutePath {
220219 }
221220}
222221
222+ fn stripped_path_to_relative (
223+ stripped_path : & Path ,
224+ ) -> Result < RelativePathBuf , StripPrefixError < ' _ > > {
225+ match RelativePathBuf :: new ( stripped_path) {
226+ Ok ( relative_path) => Ok ( relative_path) ,
227+ Err ( FromPathError :: NonRelative ) => {
228+ unreachable ! ( "stripped path should always be relative" )
229+ }
230+ Err ( FromPathError :: InvalidPathData ( invalid_path_data_error) ) => {
231+ Err ( StripPrefixError { stripped_path, invalid_path_data_error } )
232+ }
233+ }
234+ }
235+
223236/// An Error returned from [`AbsolutePath::strip_prefix`] if the stripped path is not a valid `RelativePath`
224237#[ derive( thiserror:: Error , Debug ) ]
225238pub struct StripPrefixError < ' a > {
@@ -397,6 +410,17 @@ mod tests {
397410 assert ! ( rel_path. is_none( ) ) ;
398411 }
399412
413+ #[ cfg( windows) ]
414+ #[ test]
415+ fn strip_prefix_ignores_windows_namespace_prefixes ( ) {
416+ let abs_path = AbsolutePath :: new ( Path :: new ( r"\\?\C:\Users\foo\bar" ) ) . unwrap ( ) ;
417+ let prefix = AbsolutePath :: new ( Path :: new ( r"C:\Users" ) ) . unwrap ( ) ;
418+
419+ let rel_path = abs_path. strip_prefix ( prefix) . unwrap ( ) . unwrap ( ) ;
420+
421+ assert_eq ! ( rel_path. as_str( ) , "foo/bar" ) ;
422+ }
423+
400424 #[ cfg( unix) ]
401425 #[ test]
402426 fn strip_prefix_invalid_relative ( ) {
0 commit comments