@@ -220,6 +220,19 @@ fn parse_next_component(path: &OsStr, verbatim: bool) -> (&OsStr, &OsStr) {
220220///
221221/// This path may or may not have a verbatim prefix.
222222pub ( crate ) fn maybe_verbatim ( path : & Path ) -> io:: Result < Vec < u16 > > {
223+ let path = to_u16s ( path) ?;
224+ get_long_path ( path, true )
225+ }
226+
227+ /// Get a normalized absolute path that can bypass path length limits.
228+ ///
229+ /// Setting prefer_verbatim to true suggests a stronger preference for verbatim
230+ /// paths even when not strictly necessary. This allows the Windows API to avoid
231+ /// repeating our work. However, if the path may be given back to users or
232+ /// passed to other application then it's preferable to use non-verbatim paths
233+ /// when possible. Non-verbatim paths are better understood by users and handled
234+ /// by more software.
235+ pub ( crate ) fn get_long_path ( mut path : Vec < u16 > , prefer_verbatim : bool ) -> io:: Result < Vec < u16 > > {
223236 // Normally the MAX_PATH is 260 UTF-16 code units (including the NULL).
224237 // However, for APIs such as CreateDirectory[1], the limit is 248.
225238 //
@@ -243,7 +256,6 @@ pub(crate) fn maybe_verbatim(path: &Path) -> io::Result<Vec<u16>> {
243256 // \\?\UNC\
244257 const UNC_PREFIX : & [ u16 ] = & [ SEP , SEP , QUERY , SEP , U , N , C , SEP ] ;
245258
246- let mut path = to_u16s ( path) ?;
247259 if path. starts_with ( VERBATIM_PREFIX ) || path. starts_with ( NT_PREFIX ) || path == & [ 0 ] {
248260 // Early return for paths that are already verbatim or empty.
249261 return Ok ( path) ;
@@ -275,29 +287,34 @@ pub(crate) fn maybe_verbatim(path: &Path) -> io::Result<Vec<u16>> {
275287 |mut absolute| {
276288 path. clear ( ) ;
277289
278- // Secondly, add the verbatim prefix. This is easier here because we know the
279- // path is now absolute and fully normalized (e.g. `/` has been changed to `\`).
280- let prefix = match absolute {
281- // C:\ => \\?\C:\
282- [ _, COLON , SEP , ..] => VERBATIM_PREFIX ,
283- // \\.\ => \\?\
284- [ SEP , SEP , DOT , SEP , ..] => {
285- absolute = & absolute[ 4 ..] ;
286- VERBATIM_PREFIX
287- }
288- // Leave \\?\ and \??\ as-is.
289- [ SEP , SEP , QUERY , SEP , ..] | [ SEP , QUERY , QUERY , SEP , ..] => & [ ] ,
290- // \\ => \\?\UNC\
291- [ SEP , SEP , ..] => {
292- absolute = & absolute[ 2 ..] ;
293- UNC_PREFIX
294- }
295- // Anything else we leave alone.
296- _ => & [ ] ,
297- } ;
298-
299- path. reserve_exact ( prefix. len ( ) + absolute. len ( ) + 1 ) ;
300- path. extend_from_slice ( prefix) ;
290+ // Only prepend the prefix if needed.
291+ if prefer_verbatim || absolute. len ( ) + 1 >= LEGACY_MAX_PATH {
292+ // Secondly, add the verbatim prefix. This is easier here because we know the
293+ // path is now absolute and fully normalized (e.g. `/` has been changed to `\`).
294+ let prefix = match absolute {
295+ // C:\ => \\?\C:\
296+ [ _, COLON , SEP , ..] => VERBATIM_PREFIX ,
297+ // \\.\ => \\?\
298+ [ SEP , SEP , DOT , SEP , ..] => {
299+ absolute = & absolute[ 4 ..] ;
300+ VERBATIM_PREFIX
301+ }
302+ // Leave \\?\ and \??\ as-is.
303+ [ SEP , SEP , QUERY , SEP , ..] | [ SEP , QUERY , QUERY , SEP , ..] => & [ ] ,
304+ // \\ => \\?\UNC\
305+ [ SEP , SEP , ..] => {
306+ absolute = & absolute[ 2 ..] ;
307+ UNC_PREFIX
308+ }
309+ // Anything else we leave alone.
310+ _ => & [ ] ,
311+ } ;
312+
313+ path. reserve_exact ( prefix. len ( ) + absolute. len ( ) + 1 ) ;
314+ path. extend_from_slice ( prefix) ;
315+ } else {
316+ path. reserve_exact ( absolute. len ( ) + 1 ) ;
317+ }
301318 path. extend_from_slice ( absolute) ;
302319 path. push ( 0 ) ;
303320 } ,
0 commit comments