@@ -124,10 +124,12 @@ impl FileAttributes {
124
124
if value & file_flag_backup_semantics != 0 {
125
125
value &= !file_flag_backup_semantics;
126
126
out |= FileAttributes :: BACKUP_SEMANTICS ;
127
- } else if value & file_flag_open_reparse_point != 0 {
127
+ }
128
+ if value & file_flag_open_reparse_point != 0 {
128
129
value &= !file_flag_open_reparse_point;
129
130
out |= FileAttributes :: OPEN_REPARSE ;
130
- } else if value & file_attribute_normal != 0 {
131
+ }
132
+ if value & file_attribute_normal != 0 {
131
133
value &= !file_attribute_normal;
132
134
out |= FileAttributes :: NORMAL ;
133
135
}
@@ -137,6 +139,7 @@ impl FileAttributes {
137
139
}
138
140
139
141
if out == FileAttributes :: ZERO {
142
+ // NORMAL is equivalent to 0. Avoid needing to check both cases by unifying the two.
140
143
out = FileAttributes :: NORMAL ;
141
144
}
142
145
interp_ok ( out)
@@ -162,6 +165,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
162
165
let this = self . eval_context_mut ( ) ;
163
166
this. assert_target_os ( "windows" , "CreateFileW" ) ;
164
167
this. check_no_isolation ( "`CreateFileW`" ) ?;
168
+
169
+ // This function appears to always set the error to 0. This is important for some flag
170
+ // combinations, which may set error code on success.
165
171
this. set_last_error ( IoError :: Raw ( Scalar :: from_i32 ( 0 ) ) ) ?;
166
172
167
173
let file_name = this. read_path_from_wide_str ( this. read_pointer ( file_name) ?) ?;
@@ -200,6 +206,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
200
206
201
207
let is_dir = file_name. is_dir ( ) ;
202
208
209
+ // BACKUP_SEMANTICS is how Windows calls the act of opening a directory handle.
203
210
if !attributes. contains ( FileAttributes :: BACKUP_SEMANTICS ) && is_dir {
204
211
this. set_last_error ( IoError :: WindowsError ( "ERROR_ACCESS_DENIED" ) ) ?;
205
212
return interp_ok ( Handle :: Invalid ) ;
@@ -226,20 +233,19 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
226
233
227
234
match creation_disposition {
228
235
CreateAlways | OpenAlways => {
229
- // This is racy, but there doesn't appear to be an std API that both succeeds if a
230
- // file exists but tells us it isn't new. Either we accept racing one way or another,
231
- // or we use an iffy heuristic like file creation time. This implementation prefers
232
- // to fail in the direction of erroring more often.
233
236
// Per the documentation:
234
237
// If the specified file exists and is writable, the function truncates the file,
235
238
// the function succeeds, and last-error code is set to ERROR_ALREADY_EXISTS.
236
239
// If the specified file does not exist and is a valid path, a new file is created,
237
240
// the function succeeds, and the last-error code is set to zero.
238
241
// https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilew
242
+ //
243
+ // This is racy, but there doesn't appear to be an std API that both succeeds if a
244
+ // file exists but tells us it isn't new. Either we accept racing one way or another,
245
+ // or we use an iffy heuristic like file creation time. This implementation prefers
246
+ // to fail in the direction of erroring more often.
239
247
if file_name. exists ( ) {
240
248
this. set_last_error ( IoError :: WindowsError ( "ERROR_ALREADY_EXISTS" ) ) ?;
241
- } else {
242
- this. set_last_error ( IoError :: Raw ( Scalar :: from_u32 ( 0 ) ) ) ?;
243
249
}
244
250
options. create ( true ) ;
245
251
if creation_disposition == CreateAlways {
0 commit comments