@@ -251,7 +251,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
251
251
this. alloc_os_str_as_wide_str ( & os_str, memkind)
252
252
}
253
253
254
- #[ allow( clippy:: get_first) ]
255
254
fn convert_path < ' a > (
256
255
& self ,
257
256
os_str : Cow < ' a , OsStr > ,
@@ -260,6 +259,65 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
260
259
let this = self . eval_context_ref ( ) ;
261
260
let target_os = & this. tcx . sess . target . os ;
262
261
262
+ /// Adjust a Windows path to Unix conventions such that it un-does everything that
263
+ /// `unix_to_windows` did, and such that if the Windows input path was absolute, then the
264
+ /// Unix output path is absolute.
265
+ fn windows_to_unix < T > ( path : & mut Vec < T > )
266
+ where
267
+ T : From < u8 > + Copy + Eq ,
268
+ {
269
+ let sep = T :: from ( b'/' ) ;
270
+ // Make sure all path separators are `/`.
271
+ for c in path. iter_mut ( ) {
272
+ if * c == b'\\' . into ( ) {
273
+ * c = sep;
274
+ }
275
+ }
276
+ // If this starts with `//?/`, it was probably produced by `unix_to_windows`` and we
277
+ // remove the `//?` that got added to get the Unix path back out.
278
+ if path. get ( 0 ..4 ) == Some ( & [ sep, sep, b'?' . into ( ) , sep] ) {
279
+ // Remove first 3 characters. It still starts with `/` so it is absolute on Unix.
280
+ path. splice ( 0 ..3 , std:: iter:: empty ( ) ) ;
281
+ }
282
+ // If it starts with a drive letter (`X:/`), convert it to an absolute Unix path.
283
+ else if path. get ( 1 ..3 ) == Some ( & [ b':' . into ( ) , sep] ) {
284
+ // We add a `/` at the beginning, to store the absolute Windows
285
+ // path in something that looks like an absolute Unix path.
286
+ path. insert ( 0 , sep) ;
287
+ }
288
+ }
289
+
290
+ /// Adjust a Unix path to Windows conventions such that it un-does everything that
291
+ /// `windows_to_unix` did, and such that if the Unix input path was absolute, then the
292
+ /// Windows output path is absolute.
293
+ fn unix_to_windows < T > ( path : & mut Vec < T > )
294
+ where
295
+ T : From < u8 > + Copy + Eq ,
296
+ {
297
+ let sep = T :: from ( b'\\' ) ;
298
+ // Make sure all path separators are `\`.
299
+ for c in path. iter_mut ( ) {
300
+ if * c == b'/' . into ( ) {
301
+ * c = sep;
302
+ }
303
+ }
304
+ // If the path is `\X:\`, the leading separator was probably added by `windows_to_unix`
305
+ // and we should get rid of it again.
306
+ if path. get ( 2 ..4 ) == Some ( & [ b':' . into ( ) , sep] ) && path[ 0 ] == sep {
307
+ // The new path is still absolute on Windows.
308
+ path. remove ( 0 ) ;
309
+ }
310
+ // If this starts withs a `\` but not a `\\`, then this was absolute on Unix but is
311
+ // relative on Windows (relative to "the root of the current directory", e.g. the
312
+ // drive letter).
313
+ else if path. first ( ) == Some ( & sep) && path. get ( 1 ) != Some ( & sep) {
314
+ // We add `\\?` so it starts with `\\?\` which is some magic path on Windows
315
+ // that *is* considered absolute. This way we store the absolute Unix path
316
+ // in something that looks like an absolute Windows path.
317
+ path. splice ( 0 ..0 , [ sep, sep, b'?' . into ( ) ] ) ;
318
+ }
319
+ }
320
+
263
321
// Below we assume that everything non-Windows works like Unix, at least
264
322
// when it comes to file system path conventions.
265
323
#[ cfg( windows) ]
@@ -268,102 +326,30 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
268
326
os_str
269
327
} else {
270
328
// Unix target, Windows host.
271
- let ( from, to) = match direction {
272
- PathConversion :: HostToTarget => ( '\\' , '/' ) ,
273
- PathConversion :: TargetToHost => ( '/' , '\\' ) ,
274
- } ;
275
- let mut converted = os_str
276
- . encode_wide ( )
277
- . map ( |wchar| if wchar == from as u16 { to as u16 } else { wchar } )
278
- . collect :: < Vec < _ > > ( ) ;
279
- // We also have to ensure that absolute paths remain absolute.
329
+ let mut path: Vec < u16 > = os_str. encode_wide ( ) . collect ( ) ;
280
330
match direction {
281
331
PathConversion :: HostToTarget => {
282
- // If this is an absolute Windows path that starts with a drive letter (`C:/...`
283
- // after separator conversion), it would not be considered absolute by Unix
284
- // target code.
285
- if converted. get ( 1 ) . copied ( ) == Some ( b':' as u16 )
286
- && converted. get ( 2 ) . copied ( ) == Some ( b'/' as u16 )
287
- {
288
- // We add a `/` at the beginning, to store the absolute Windows
289
- // path in something that looks like an absolute Unix path.
290
- converted. insert ( 0 , b'/' as u16 ) ;
291
- }
332
+ windows_to_unix ( & mut path) ;
292
333
}
293
334
PathConversion :: TargetToHost => {
294
- // If the path is `\C:\`, the leading backslash was probably added by the above code
295
- // and we should get rid of it again.
296
- if converted. get ( 0 ) . copied ( ) == Some ( b'\\' as u16 )
297
- && converted. get ( 2 ) . copied ( ) == Some ( b':' as u16 )
298
- && converted. get ( 3 ) . copied ( ) == Some ( b'\\' as u16 )
299
- {
300
- converted. remove ( 0 ) ;
301
- }
302
- // If the path starts with `\\`, it is a magic Windows path. Conveniently, paths
303
- // starting with `//` on Unix are also magic where the first component can have
304
- // "application-specific" meaning, which is reflected e.g. by `path::absolute`
305
- // leaving leading `//` alone (but normalizing leading `///` to `/`). So we
306
- // don't have to do anything, the magic Windows path should work mostly fine as
307
- // a magic Unix path.
335
+ unix_to_windows ( & mut path) ;
308
336
}
309
337
}
310
- Cow :: Owned ( OsString :: from_wide ( & converted ) )
338
+ Cow :: Owned ( OsString :: from_wide ( & path ) )
311
339
} ;
312
340
#[ cfg( unix) ]
313
341
return if target_os == "windows" {
314
342
// Windows target, Unix host.
315
- let ( from, to) = match direction {
316
- PathConversion :: HostToTarget => ( b'/' , b'\\' ) ,
317
- PathConversion :: TargetToHost => ( b'\\' , b'/' ) ,
318
- } ;
319
- let mut converted = os_str
320
- . as_bytes ( )
321
- . iter ( )
322
- . map ( |& wchar| if wchar == from { to } else { wchar } )
323
- . collect :: < Vec < _ > > ( ) ;
324
- // We also have to ensure that absolute paths remain absolute.
343
+ let mut path: Vec < u8 > = os_str. into_owned ( ) . into_encoded_bytes ( ) ;
325
344
match direction {
326
345
PathConversion :: HostToTarget => {
327
- // If the path is `/C:/`, the leading backslash was probably added by the below
328
- // driver letter handling and we should get rid of it again.
329
- if converted. get ( 0 ) . copied ( ) == Some ( b'\\' )
330
- && converted. get ( 2 ) . copied ( ) == Some ( b':' )
331
- && converted. get ( 3 ) . copied ( ) == Some ( b'\\' )
332
- {
333
- converted. remove ( 0 ) ;
334
- }
335
- // If this starts withs a `\` but not a `\\`, then for Windows this is a
336
- // relative path (relative to "the root of the current directory", e.g. the
337
- // drive letter). But the host path on Unix is absolute as it starts with `/`.
338
- else if converted. get ( 0 ) . copied ( ) == Some ( b'\\' )
339
- && converted. get ( 1 ) . copied ( ) != Some ( b'\\' )
340
- {
341
- // We add `\\?` so it starts with `\\?\` which is some magic path on Windows
342
- // that *is* considered absolute. This way we store the absolute host path
343
- // in something that looks like an absolute path to the (Windows) target.
344
- converted. splice ( 0 ..0 , b"\\ \\ ?" . iter ( ) . copied ( ) ) ;
345
- }
346
+ unix_to_windows ( & mut path) ;
346
347
}
347
348
PathConversion :: TargetToHost => {
348
- // If this starts with `//?/`, it was probably produced by the above code and we
349
- // remove the `//?` that got added to get the Unix path back out.
350
- if converted. get ( 0 ) . copied ( ) == Some ( b'/' )
351
- && converted. get ( 1 ) . copied ( ) == Some ( b'/' )
352
- && converted. get ( 2 ) . copied ( ) == Some ( b'?' )
353
- && converted. get ( 3 ) . copied ( ) == Some ( b'/' )
354
- {
355
- // Remove first 3 characters
356
- converted. splice ( 0 ..3 , std:: iter:: empty ( ) ) ;
357
- }
358
- // If it starts with a drive letter, convert it to an absolute Unix path.
359
- else if converted. get ( 1 ) . copied ( ) == Some ( b':' )
360
- && converted. get ( 2 ) . copied ( ) == Some ( b'/' )
361
- {
362
- converted. insert ( 0 , b'/' ) ;
363
- }
349
+ windows_to_unix ( & mut path) ;
364
350
}
365
351
}
366
- Cow :: Owned ( OsString :: from_vec ( converted ) )
352
+ Cow :: Owned ( OsString :: from_vec ( path ) )
367
353
} else {
368
354
// Unix-on-Unix, all is fine.
369
355
os_str
0 commit comments