@@ -14,7 +14,11 @@ use cast::BytesAsReparseDataBuffer;
1414
1515/// This prefix indicates to NTFS that the path is to be treated as a non-interpreted
1616/// path in the virtual file system.
17- const NON_INTERPRETED_PATH_PREFIX : [ u16 ; 4 ] = helpers:: utf16s ( br"\??\" ) ;
17+ /// Ref: <https://learn.microsoft.com/windows-hardware/drivers/kernel/object-manager>
18+ const NT_PREFIX : [ u16 ; 4 ] = helpers:: utf16s ( br"\??\" ) ;
19+ /// Disables normalization and bypasses MAX_PATH.
20+ /// Ref: <https://learn.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation?tabs=registry>
21+ const VERBATIM_PREFIX : [ u16 ; 4 ] = helpers:: utf16s ( br"\\?\" ) ;
1822
1923const WCHAR_SIZE : u16 = size_of :: < u16 > ( ) as _ ;
2024
@@ -30,13 +34,12 @@ pub fn create(target: &Path, junction: &Path) -> io::Result<()> {
3034 // canonicalize the path first.
3135 let target = helpers:: get_full_path ( target) ?;
3236 // Strip Win32 verbatim prefix (\\?\) if present - we add NT prefix (\??\) ourselves
33- const VERBATIM_PREFIX : [ u16 ; 4 ] = helpers:: utf16s ( br"\\?\" ) ;
3437 let target = target. strip_prefix ( VERBATIM_PREFIX . as_slice ( ) ) . unwrap_or ( & target) ;
3538 fs:: create_dir ( junction) ?;
3639 let file = helpers:: open_reparse_point ( junction, true ) ?;
3740 let target_len_in_bytes = {
3841 // "\??\" + target
39- let len = NON_INTERPRETED_PATH_PREFIX . len ( ) . saturating_add ( target. len ( ) ) ;
42+ let len = NT_PREFIX . len ( ) . saturating_add ( target. len ( ) ) ;
4043 let min_len = cmp:: min ( len, u16:: MAX as usize ) as u16 ;
4144 // Len without `UNICODE_NULL` at the end
4245 let target_len_in_bytes = min_len. saturating_mul ( WCHAR_SIZE ) ;
@@ -65,14 +68,10 @@ pub fn create(target: &Path, junction: &Path) -> io::Result<()> {
6568
6669 let mut path_buffer_ptr: * mut u16 = addr_of_mut ! ( ( * rdb) . ReparseBuffer . PathBuffer ) . cast ( ) ;
6770 // Safe because we checked `MAX_AVAILABLE_PATH_BUFFER`
68- copy_nonoverlapping (
69- NON_INTERPRETED_PATH_PREFIX . as_ptr ( ) ,
70- path_buffer_ptr,
71- NON_INTERPRETED_PATH_PREFIX . len ( ) ,
72- ) ;
71+ copy_nonoverlapping ( NT_PREFIX . as_ptr ( ) , path_buffer_ptr, NT_PREFIX . len ( ) ) ;
7372 // TODO: Do we need to write the NULL-terminator byte?
7473 // It looks like libuv does that.
75- path_buffer_ptr = path_buffer_ptr. add ( NON_INTERPRETED_PATH_PREFIX . len ( ) ) ;
74+ path_buffer_ptr = path_buffer_ptr. add ( NT_PREFIX . len ( ) ) ;
7675 copy_nonoverlapping ( target. as_ptr ( ) , path_buffer_ptr, target. len ( ) ) ;
7776
7877 // Set the total size of the data buffer
@@ -123,7 +122,7 @@ pub fn get_target(junction: &Path) -> io::Result<PathBuf> {
123122 slice:: from_raw_parts ( buf, len as usize )
124123 } ;
125124 // In case of "\??\C:\foo\bar"
126- let wide = wide. strip_prefix ( & NON_INTERPRETED_PATH_PREFIX ) . unwrap_or ( wide) ;
125+ let wide = wide. strip_prefix ( & NT_PREFIX ) . unwrap_or ( wide) ;
127126 Ok ( PathBuf :: from ( OsString :: from_wide ( wide) ) )
128127 } else {
129128 Err ( io:: Error :: new ( io:: ErrorKind :: Other , "not a reparse tag mount point" ) )
0 commit comments