1
1
use std:: ffi:: OsStr ;
2
+ use std:: io;
2
3
use std:: iter;
4
+ use std:: path:: { self , Path , PathBuf } ;
3
5
use std:: str;
4
6
5
7
use rustc_span:: Symbol ;
@@ -21,6 +23,61 @@ fn is_dyn_sym(name: &str) -> bool {
21
23
)
22
24
}
23
25
26
+ #[ cfg( windows) ]
27
+ fn win_absolute < ' tcx > ( path : & Path ) -> InterpResult < ' tcx , io:: Result < PathBuf > > {
28
+ // We are on Windows so we can simply lte the host do this.
29
+ return Ok ( path:: absolute ( path) ) ;
30
+ }
31
+
32
+ #[ cfg( unix) ]
33
+ #[ allow( clippy:: get_first, clippy:: arithmetic_side_effects) ]
34
+ fn win_absolute < ' tcx > ( path : & Path ) -> InterpResult < ' tcx , io:: Result < PathBuf > > {
35
+ // We are on Unix, so we need to implement parts of the logic ourselves.
36
+ let bytes = path. as_os_str ( ) . as_encoded_bytes ( ) ;
37
+ // If it starts with `//` (these were backslashes but are already converted)
38
+ // then this is a magic special path, we just leave it unchanged.
39
+ if bytes. get ( 0 ) . copied ( ) == Some ( b'/' ) && bytes. get ( 1 ) . copied ( ) == Some ( b'/' ) {
40
+ return Ok ( Ok ( path. into ( ) ) ) ;
41
+ } ;
42
+ // Special treatment for Windows' magic filenames: they are treated as being relative to `\\.\`.
43
+ let magic_filenames = & [
44
+ "CON" , "PRN" , "AUX" , "NUL" , "COM1" , "COM2" , "COM3" , "COM4" , "COM5" , "COM6" , "COM7" , "COM8" ,
45
+ "COM9" , "LPT1" , "LPT2" , "LPT3" , "LPT4" , "LPT5" , "LPT6" , "LPT7" , "LPT8" , "LPT9" ,
46
+ ] ;
47
+ if magic_filenames. iter ( ) . any ( |m| m. as_bytes ( ) == bytes) {
48
+ let mut result: Vec < u8 > = br"//./" . into ( ) ;
49
+ result. extend ( bytes) ;
50
+ return Ok ( Ok ( bytes_to_os_str ( & result) ?. into ( ) ) ) ;
51
+ }
52
+ // Otherwise we try to do something kind of close to what Windows does, but this is probably not
53
+ // right in all cases. We iterate over the components between `/`, and remove trailing `.`,
54
+ // except that trailing `..` remain unchanged.
55
+ let mut result = vec ! [ ] ;
56
+ let mut bytes = bytes; // the remaining bytes to process
57
+ loop {
58
+ let len = bytes. iter ( ) . position ( |& b| b == b'/' ) . unwrap_or ( bytes. len ( ) ) ;
59
+ let mut component = & bytes[ ..len] ;
60
+ if len >= 2 && component[ len - 1 ] == b'.' && component[ len - 2 ] != b'.' {
61
+ // Strip trailing `.`
62
+ component = & component[ ..len - 1 ] ;
63
+ }
64
+ // Add this component to output.
65
+ result. extend ( component) ;
66
+ // Prepare next iteration.
67
+ if len < bytes. len ( ) {
68
+ // There's a component after this; add `/` and process remaining bytes.
69
+ result. push ( b'/' ) ;
70
+ bytes = & bytes[ len + 1 ..] ;
71
+ continue ;
72
+ } else {
73
+ // This was the last component and it did not have a trailing `/`.
74
+ break ;
75
+ }
76
+ }
77
+ // Let the host `absolute` function do working-dir handling
78
+ Ok ( path:: absolute ( bytes_to_os_str ( & result) ?) )
79
+ }
80
+
24
81
impl < ' mir , ' tcx : ' mir > EvalContextExt < ' mir , ' tcx > for crate :: MiriInterpCx < ' mir , ' tcx > { }
25
82
pub trait EvalContextExt < ' mir , ' tcx : ' mir > : crate :: MiriInterpCxExt < ' mir , ' tcx > {
26
83
fn emulate_foreign_item_inner (
@@ -112,7 +169,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
112
169
113
170
let written = if handle == -11 || handle == -12 {
114
171
// stdout/stderr
115
- use std :: io:: { self , Write } ;
172
+ use io:: Write ;
116
173
117
174
let buf_cont =
118
175
this. read_bytes_ptr_strip_provenance ( buf, Size :: from_bytes ( u64:: from ( n) ) ) ?;
@@ -146,6 +203,40 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
146
203
dest,
147
204
) ?;
148
205
}
206
+ "GetFullPathNameW" => {
207
+ let [ filename, size, buffer, filepart] =
208
+ this. check_shim ( abi, Abi :: System { unwind : false } , link_name, args) ?;
209
+ this. check_no_isolation ( "`GetFullPathNameW`" ) ?;
210
+
211
+ let filename = this. read_pointer ( filename) ?;
212
+ let size = this. read_scalar ( size) ?. to_u32 ( ) ?;
213
+ let buffer = this. read_pointer ( buffer) ?;
214
+ let filepart = this. read_pointer ( filepart) ?;
215
+
216
+ if !this. ptr_is_null ( filepart) ? {
217
+ throw_unsup_format ! ( "GetFullPathNameW: non-null `lpFilePart` is not supported" ) ;
218
+ }
219
+
220
+ let filename = this. read_path_from_wide_str ( filename) ?;
221
+ let result = match win_absolute ( & filename) ? {
222
+ Err ( err) => {
223
+ this. set_last_error_from_io_error ( err. kind ( ) ) ?;
224
+ Scalar :: from_u32 ( 0 ) // return zero upon failure
225
+ }
226
+ Ok ( abs_filename) => {
227
+ this. set_last_error ( Scalar :: from_u32 ( 0 ) ) ?; // make sure this is unambiguously not an error
228
+ Scalar :: from_u32 ( helpers:: windows_check_buffer_size (
229
+ this. write_path_to_wide_str (
230
+ & abs_filename,
231
+ buffer,
232
+ size. into ( ) ,
233
+ /*truncate*/ false ,
234
+ ) ?,
235
+ ) )
236
+ }
237
+ } ;
238
+ this. write_scalar ( result, dest) ?;
239
+ }
149
240
150
241
// Allocation
151
242
"HeapAlloc" => {
0 commit comments