@@ -220,6 +220,19 @@ fn parse_next_component(path: &OsStr, verbatim: bool) -> (&OsStr, &OsStr) {
220
220
///
221
221
/// This path may or may not have a verbatim prefix.
222
222
pub ( 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 > > {
223
236
// Normally the MAX_PATH is 260 UTF-16 code units (including the NULL).
224
237
// However, for APIs such as CreateDirectory[1], the limit is 248.
225
238
//
@@ -243,7 +256,6 @@ pub(crate) fn maybe_verbatim(path: &Path) -> io::Result<Vec<u16>> {
243
256
// \\?\UNC\
244
257
const UNC_PREFIX : & [ u16 ] = & [ SEP , SEP , QUERY , SEP , U , N , C , SEP ] ;
245
258
246
- let mut path = to_u16s ( path) ?;
247
259
if path. starts_with ( VERBATIM_PREFIX ) || path. starts_with ( NT_PREFIX ) || path == & [ 0 ] {
248
260
// Early return for paths that are already verbatim or empty.
249
261
return Ok ( path) ;
@@ -275,29 +287,34 @@ pub(crate) fn maybe_verbatim(path: &Path) -> io::Result<Vec<u16>> {
275
287
|mut absolute| {
276
288
path. clear ( ) ;
277
289
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
+ }
301
318
path. extend_from_slice ( absolute) ;
302
319
path. push ( 0 ) ;
303
320
} ,
0 commit comments