11use  std:: any:: Any ; 
22use  std:: collections:: BTreeMap ; 
3- use  std:: io:: { IsTerminal ,  SeekFrom ,  Write } ; 
3+ use  std:: fs:: { File ,  Metadata } ; 
4+ use  std:: io:: { IsTerminal ,  Seek ,  SeekFrom ,  Write } ; 
45use  std:: marker:: CoercePointee ; 
56use  std:: ops:: Deref ; 
67use  std:: rc:: { Rc ,  Weak } ; 
@@ -192,7 +193,7 @@ pub trait FileDescription: std::fmt::Debug + FileDescriptionExt {
192193 false 
193194 } 
194195
195-  fn  as_unix ( & self )  -> & dyn  UnixFileDescription  { 
196+  fn  as_unix < ' tcx > ( & self ,   _ecx :   & MiriInterpCx < ' tcx > )  -> & dyn  UnixFileDescription  { 
196197 panic ! ( "Not a unix file descriptor: {}" ,  self . name( ) ) ; 
197198 } 
198199} 
@@ -278,6 +279,97 @@ impl FileDescription for io::Stderr {
278279 } 
279280} 
280281
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+ 
281373/// Like /dev/null 
282374#[ derive( Debug ) ]  
283375pub  struct  NullOutput ; 
@@ -300,10 +392,13 @@ impl FileDescription for NullOutput {
300392 } 
301393} 
302394
395+ /// Internal type of a file-descriptor - this is what [`FdTable`] expects 
396+ pub  type  FdNum  = i32 ; 
397+ 
303398/// The file descriptor table 
304399#[ derive( Debug ) ]  
305400pub  struct  FdTable  { 
306-  pub  fds :  BTreeMap < i32 ,  DynFileDescriptionRef > , 
401+  pub  fds :  BTreeMap < FdNum ,  DynFileDescriptionRef > , 
307402 /// Unique identifier for file description, used to differentiate between various file description. 
308403  next_file_description_id :  FdId , 
309404} 
@@ -339,21 +434,21 @@ impl FdTable {
339434 } 
340435
341436 /// 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  { 
343438 let  fd_ref = self . new_ref ( fd) ; 
344439 self . insert ( fd_ref) 
345440 } 
346441
347-  pub  fn  insert ( & mut  self ,  fd_ref :  DynFileDescriptionRef )  -> i32  { 
442+  pub  fn  insert ( & mut  self ,  fd_ref :  DynFileDescriptionRef )  -> FdNum  { 
348443 self . insert_with_min_num ( fd_ref,  0 ) 
349444 } 
350445
351446 /// Insert a file description, giving it a file descriptor that is at least `min_fd_num`. 
352447  pub  fn  insert_with_min_num ( 
353448 & mut  self , 
354449 file_handle :  DynFileDescriptionRef , 
355-  min_fd_num :  i32 , 
356-  )  -> i32  { 
450+  min_fd_num :  FdNum , 
451+  )  -> FdNum  { 
357452 // Find the lowest unused FD, starting from min_fd. If the first such unused FD is in 
358453 // between used FDs, the find_map combinator will return it. If the first such unused FD 
359454 // is after all other used FDs, the find_map combinator will return None, and we will use 
@@ -379,16 +474,16 @@ impl FdTable {
379474 new_fd_num
380475 } 
381476
382-  pub  fn  get ( & self ,  fd_num :  i32 )  -> Option < DynFileDescriptionRef >  { 
477+  pub  fn  get ( & self ,  fd_num :  FdNum )  -> Option < DynFileDescriptionRef >  { 
383478 let  fd = self . fds . get ( & fd_num) ?; 
384479 Some ( fd. clone ( ) ) 
385480 } 
386481
387-  pub  fn  remove ( & mut  self ,  fd_num :  i32 )  -> Option < DynFileDescriptionRef >  { 
482+  pub  fn  remove ( & mut  self ,  fd_num :  FdNum )  -> Option < DynFileDescriptionRef >  { 
388483 self . fds . remove ( & fd_num) 
389484 } 
390485
391-  pub  fn  is_fd_num ( & self ,  fd_num :  i32 )  -> bool  { 
486+  pub  fn  is_fd_num ( & self ,  fd_num :  FdNum )  -> bool  { 
392487 self . fds . contains_key ( & fd_num) 
393488 } 
394489} 
0 commit comments