1
1
use std:: any:: Any ;
2
2
use std:: collections:: BTreeMap ;
3
- use std:: io:: { IsTerminal , SeekFrom , Write } ;
3
+ use std:: fs:: { File , Metadata } ;
4
+ use std:: io:: { IsTerminal , Seek , SeekFrom , Write } ;
4
5
use std:: marker:: CoercePointee ;
5
6
use std:: ops:: Deref ;
6
7
use std:: rc:: { Rc , Weak } ;
@@ -192,7 +193,7 @@ pub trait FileDescription: std::fmt::Debug + FileDescriptionExt {
192
193
false
193
194
}
194
195
195
- fn as_unix ( & self ) -> & dyn UnixFileDescription {
196
+ fn as_unix < ' tcx > ( & self , _ecx : & MiriInterpCx < ' tcx > ) -> & dyn UnixFileDescription {
196
197
panic ! ( "Not a unix file descriptor: {}" , self . name( ) ) ;
197
198
}
198
199
}
@@ -278,6 +279,97 @@ impl FileDescription for io::Stderr {
278
279
}
279
280
}
280
281
282
+ #[ derive( Debug ) ]
283
+ pub struct FileHandle {
284
+ pub ( crate ) file : File ,
285
+ pub ( crate ) writable : bool ,
286
+ }
287
+
288
+ impl FileDescription for FileHandle {
289
+ fn name ( & self ) -> & ' static str {
290
+ "file"
291
+ }
292
+
293
+ fn read < ' tcx > (
294
+ self : FileDescriptionRef < Self > ,
295
+ communicate_allowed : bool ,
296
+ ptr : Pointer ,
297
+ len : usize ,
298
+ ecx : & mut MiriInterpCx < ' tcx > ,
299
+ finish : DynMachineCallback < ' tcx , Result < usize , IoError > > ,
300
+ ) -> InterpResult < ' tcx > {
301
+ assert ! ( communicate_allowed, "isolation should have prevented even opening a file" ) ;
302
+
303
+ let result = ecx. read_from_host ( & self . file , len, ptr) ?;
304
+ finish. call ( ecx, result)
305
+ }
306
+
307
+ fn write < ' tcx > (
308
+ self : FileDescriptionRef < Self > ,
309
+ communicate_allowed : bool ,
310
+ ptr : Pointer ,
311
+ len : usize ,
312
+ ecx : & mut MiriInterpCx < ' tcx > ,
313
+ finish : DynMachineCallback < ' tcx , Result < usize , IoError > > ,
314
+ ) -> InterpResult < ' tcx > {
315
+ assert ! ( communicate_allowed, "isolation should have prevented even opening a file" ) ;
316
+
317
+ let result = ecx. write_to_host ( & self . file , len, ptr) ?;
318
+ finish. call ( ecx, result)
319
+ }
320
+
321
+ fn seek < ' tcx > (
322
+ & self ,
323
+ communicate_allowed : bool ,
324
+ offset : SeekFrom ,
325
+ ) -> InterpResult < ' tcx , io:: Result < u64 > > {
326
+ assert ! ( communicate_allowed, "isolation should have prevented even opening a file" ) ;
327
+ interp_ok ( ( & mut & self . file ) . seek ( offset) )
328
+ }
329
+
330
+ fn close < ' tcx > (
331
+ self ,
332
+ communicate_allowed : bool ,
333
+ _ecx : & mut MiriInterpCx < ' tcx > ,
334
+ ) -> InterpResult < ' tcx , io:: Result < ( ) > > {
335
+ assert ! ( communicate_allowed, "isolation should have prevented even opening a file" ) ;
336
+ // We sync the file if it was opened in a mode different than read-only.
337
+ if self . writable {
338
+ // `File::sync_all` does the checks that are done when closing a file. We do this to
339
+ // to handle possible errors correctly.
340
+ let result = self . file . sync_all ( ) ;
341
+ // Now we actually close the file and return the result.
342
+ drop ( self . file ) ;
343
+ interp_ok ( result)
344
+ } else {
345
+ // We drop the file, this closes it but ignores any errors
346
+ // produced when closing it. This is done because
347
+ // `File::sync_all` cannot be done over files like
348
+ // `/dev/urandom` which are read-only. Check
349
+ // https://github.com/rust-lang/miri/issues/999#issuecomment-568920439
350
+ // for a deeper discussion.
351
+ drop ( self . file ) ;
352
+ interp_ok ( Ok ( ( ) ) )
353
+ }
354
+ }
355
+
356
+ fn metadata < ' tcx > ( & self ) -> InterpResult < ' tcx , io:: Result < Metadata > > {
357
+ interp_ok ( self . file . metadata ( ) )
358
+ }
359
+
360
+ fn is_tty ( & self , communicate_allowed : bool ) -> bool {
361
+ communicate_allowed && self . file . is_terminal ( )
362
+ }
363
+
364
+ fn as_unix < ' tcx > ( & self , ecx : & MiriInterpCx < ' tcx > ) -> & dyn UnixFileDescription {
365
+ assert ! (
366
+ ecx. target_os_is_unix( ) ,
367
+ "unix file operations are only available for unix targets"
368
+ ) ;
369
+ self
370
+ }
371
+ }
372
+
281
373
/// Like /dev/null
282
374
#[ derive( Debug ) ]
283
375
pub struct NullOutput ;
@@ -300,10 +392,13 @@ impl FileDescription for NullOutput {
300
392
}
301
393
}
302
394
395
+ /// Internal type of a file-descriptor - this is what [`FdTable`] expects
396
+ pub type FdNum = i32 ;
397
+
303
398
/// The file descriptor table
304
399
#[ derive( Debug ) ]
305
400
pub struct FdTable {
306
- pub fds : BTreeMap < i32 , DynFileDescriptionRef > ,
401
+ pub fds : BTreeMap < FdNum , DynFileDescriptionRef > ,
307
402
/// Unique identifier for file description, used to differentiate between various file description.
308
403
next_file_description_id : FdId ,
309
404
}
@@ -339,21 +434,21 @@ impl FdTable {
339
434
}
340
435
341
436
/// Insert a new file description to the FdTable.
342
- pub fn insert_new ( & mut self , fd : impl FileDescription ) -> i32 {
437
+ pub fn insert_new ( & mut self , fd : impl FileDescription ) -> FdNum {
343
438
let fd_ref = self . new_ref ( fd) ;
344
439
self . insert ( fd_ref)
345
440
}
346
441
347
- pub fn insert ( & mut self , fd_ref : DynFileDescriptionRef ) -> i32 {
442
+ pub fn insert ( & mut self , fd_ref : DynFileDescriptionRef ) -> FdNum {
348
443
self . insert_with_min_num ( fd_ref, 0 )
349
444
}
350
445
351
446
/// Insert a file description, giving it a file descriptor that is at least `min_fd_num`.
352
447
pub fn insert_with_min_num (
353
448
& mut self ,
354
449
file_handle : DynFileDescriptionRef ,
355
- min_fd_num : i32 ,
356
- ) -> i32 {
450
+ min_fd_num : FdNum ,
451
+ ) -> FdNum {
357
452
// Find the lowest unused FD, starting from min_fd. If the first such unused FD is in
358
453
// between used FDs, the find_map combinator will return it. If the first such unused FD
359
454
// is after all other used FDs, the find_map combinator will return None, and we will use
@@ -379,16 +474,16 @@ impl FdTable {
379
474
new_fd_num
380
475
}
381
476
382
- pub fn get ( & self , fd_num : i32 ) -> Option < DynFileDescriptionRef > {
477
+ pub fn get ( & self , fd_num : FdNum ) -> Option < DynFileDescriptionRef > {
383
478
let fd = self . fds . get ( & fd_num) ?;
384
479
Some ( fd. clone ( ) )
385
480
}
386
481
387
- pub fn remove ( & mut self , fd_num : i32 ) -> Option < DynFileDescriptionRef > {
482
+ pub fn remove ( & mut self , fd_num : FdNum ) -> Option < DynFileDescriptionRef > {
388
483
self . fds . remove ( & fd_num)
389
484
}
390
485
391
- pub fn is_fd_num ( & self , fd_num : i32 ) -> bool {
486
+ pub fn is_fd_num ( & self , fd_num : FdNum ) -> bool {
392
487
self . fds . contains_key ( & fd_num)
393
488
}
394
489
}
0 commit comments