<commit_before>use std::collections::BTreeMap;
use std::convert::{TryFrom, TryInto};
use std::fs::{read_dir, remove_dir, remove_file, rename, DirBuilder, File, FileType, OpenOptions, ReadDir};
use std::io::{self, Read, Seek, SeekFrom, Write};
use std::path::Path;
use std::time::SystemTime;

use log::trace;

use rustc_data_structures::fx::FxHashMap;
use rustc_target::abi::{Align, LayoutOf, Size};
use rustc_middle::ty;

use crate::*;
use stacked_borrows::Tag;
use helpers::{check_arg_count, immty_from_int_checked, immty_from_uint_checked};
use shims::time::system_time_to_duration;

#[derive(Debug)]
struct FileHandle {
    file: File,
    writable: bool,
}

trait FileDescriptor : std::fmt::Debug {
    fn as_file_handle<'tcx>(&self) -> InterpResult<'tcx, &FileHandle>;

    fn read<'tcx>(&mut self, communicate_allowed: bool, bytes: &mut [u8]) -> InterpResult<'tcx, io::Result<usize>>;
    fn write<'tcx>(&mut self, communicate_allowed: bool, bytes: &[u8]) -> InterpResult<'tcx, io::Result<usize>>;
    fn seek<'tcx>(&mut self, communicate_allowed: bool, offset: SeekFrom) -> InterpResult<'tcx, io::Result<u64>>;
}

impl FileDescriptor for FileHandle {
    fn as_file_handle<'tcx>(&self) -> InterpResult<'tcx, &FileHandle> {
        Ok(&self)
    }

    fn read<'tcx>(&mut self, communicate_allowed: bool, bytes: &mut [u8]) -> InterpResult<'tcx, io::Result<usize>> {
        assert!(communicate_allowed, "isolation should have prevented even opening a file");
        Ok(self.file.read(bytes))
    }

    fn write<'tcx>(&mut self, communicate_allowed: bool, bytes: &[u8]) -> InterpResult<'tcx, io::Result<usize>> {
        assert!(communicate_allowed, "isolation should have prevented even opening a file");
        Ok(self.file.write(bytes))
    }

    fn seek<'tcx>(&mut self, communicate_allowed: bool, offset: SeekFrom) -> InterpResult<'tcx, io::Result<u64>> {
        assert!(communicate_allowed, "isolation should have prevented even opening a file");
        Ok(self.file.seek(offset))
    }
}

impl FileDescriptor for io::Stdin {
    fn as_file_handle<'tcx>(&self) -> InterpResult<'tcx, &FileHandle> {
        throw_unsup_format!("stdin cannot be used as FileHandle");
    }

    fn read<'tcx>(&mut self, communicate_allowed: bool, bytes: &mut [u8]) -> InterpResult<'tcx, io::Result<usize>> {
        if !communicate_allowed {
            // We want isolation mode to be deterministic, so we have to disallow all reads, even stdin.
            helpers::isolation_error("read")?;
        }
        Ok(Read::read(self, bytes))
    }

    fn write<'tcx>(&mut self, _communicate_allowed: bool, _bytes: &[u8]) -> InterpResult<'tcx, io::Result<usize>> {
        throw_unsup_format!("cannot write to stdin");
    }

    fn seek<'tcx>(&mut self, _communicate_allowed: bool, _offset: SeekFrom) -> InterpResult<'tcx, io::Result<u64>> {
        throw_unsup_format!("cannot seek on stdin");
    }
}

impl FileDescriptor for io::Stdout {
    fn as_file_handle<'tcx>(&self) -> InterpResult<'tcx, &FileHandle> {
        throw_unsup_format!("stdout cannot be used as FileHandle");
    }

    fn read<'tcx>(&mut self, _communicate_allowed: bool, _bytes: &mut [u8]) -> InterpResult<'tcx, io::Result<usize>> {
        throw_unsup_format!("cannot read from stdout");
    }

    fn write<'tcx>(&mut self, _communicate_allowed: bool, bytes: &[u8]) -> InterpResult<'tcx, io::Result<usize>> {
        // We allow writing to stderr even with isolation enabled.
        let result = Write::write(self, bytes);
        // Stdout is buffered, flush to make sure it appears on the
        // screen.  This is the write() syscall of the interpreted
        // program, we want it to correspond to a write() syscall on
        // the host -- there is no good in adding extra buffering
        // here.
        io::stdout().flush().unwrap();

        Ok(result)
    }

    fn seek<'tcx>(&mut self, _communicate_allowed: bool, _offset: SeekFrom) -> InterpResult<'tcx, io::Result<u64>> {
        throw_unsup_format!("cannot seek on stdout");
    }
}

impl FileDescriptor for io::Stderr {
    fn as_file_handle<'tcx>(&self) -> InterpResult<'tcx, &FileHandle> {
        throw_unsup_format!("stdout cannot be used as FileHandle");
    }

    fn read<'tcx>(&mut self, _communicate_allowed: bool, _bytes: &mut [u8]) -> InterpResult<'tcx, io::Result<usize>> {<commit_msg>Auto merge of #1510 - RalfJung:stderr, r=RalfJung<commit_after>use std::collections::BTreeMap;
use std::convert::{TryFrom, TryInto};
use std::fs::{read_dir, remove_dir, remove_file, rename, DirBuilder, File, FileType, OpenOptions, ReadDir};
use std::io::{self, Read, Seek, SeekFrom, Write};
use std::path::Path;
use std::time::SystemTime;

use log::trace;

use rustc_data_structures::fx::FxHashMap;
use rustc_target::abi::{Align, LayoutOf, Size};
use rustc_middle::ty;

use crate::*;
use stacked_borrows::Tag;
use helpers::{check_arg_count, immty_from_int_checked, immty_from_uint_checked};
use shims::time::system_time_to_duration;

#[derive(Debug)]
struct FileHandle {
    file: File,
    writable: bool,
}

trait FileDescriptor : std::fmt::Debug {
    fn as_file_handle<'tcx>(&self) -> InterpResult<'tcx, &FileHandle>;

    fn read<'tcx>(&mut self, communicate_allowed: bool, bytes: &mut [u8]) -> InterpResult<'tcx, io::Result<usize>>;
    fn write<'tcx>(&mut self, communicate_allowed: bool, bytes: &[u8]) -> InterpResult<'tcx, io::Result<usize>>;
    fn seek<'tcx>(&mut self, communicate_allowed: bool, offset: SeekFrom) -> InterpResult<'tcx, io::Result<u64>>;
}

impl FileDescriptor for FileHandle {
    fn as_file_handle<'tcx>(&self) -> InterpResult<'tcx, &FileHandle> {
        Ok(&self)
    }

    fn read<'tcx>(&mut self, communicate_allowed: bool, bytes: &mut [u8]) -> InterpResult<'tcx, io::Result<usize>> {
        assert!(communicate_allowed, "isolation should have prevented even opening a file");
        Ok(self.file.read(bytes))
    }

    fn write<'tcx>(&mut self, communicate_allowed: bool, bytes: &[u8]) -> InterpResult<'tcx, io::Result<usize>> {
        assert!(communicate_allowed, "isolation should have prevented even opening a file");
        Ok(self.file.write(bytes))
    }

    fn seek<'tcx>(&mut self, communicate_allowed: bool, offset: SeekFrom) -> InterpResult<'tcx, io::Result<u64>> {
        assert!(communicate_allowed, "isolation should have prevented even opening a file");
        Ok(self.file.seek(offset))
    }
}

impl FileDescriptor for io::Stdin {
    fn as_file_handle<'tcx>(&self) -> InterpResult<'tcx, &FileHandle> {
        throw_unsup_format!("stdin cannot be used as FileHandle");
    }

    fn read<'tcx>(&mut self, communicate_allowed: bool, bytes: &mut [u8]) -> InterpResult<'tcx, io::Result<usize>> {
        if !communicate_allowed {
            // We want isolation mode to be deterministic, so we have to disallow all reads, even stdin.
            helpers::isolation_error("read")?;
        }
        Ok(Read::read(self, bytes))
    }

    fn write<'tcx>(&mut self, _communicate_allowed: bool, _bytes: &[u8]) -> InterpResult<'tcx, io::Result<usize>> {
        throw_unsup_format!("cannot write to stdin");
    }

    fn seek<'tcx>(&mut self, _communicate_allowed: bool, _offset: SeekFrom) -> InterpResult<'tcx, io::Result<u64>> {
        throw_unsup_format!("cannot seek on stdin");
    }
}

impl FileDescriptor for io::Stdout {
    fn as_file_handle<'tcx>(&self) -> InterpResult<'tcx, &FileHandle> {
        throw_unsup_format!("stdout cannot be used as FileHandle");
    }

    fn read<'tcx>(&mut self, _communicate_allowed: bool, _bytes: &mut [u8]) -> InterpResult<'tcx, io::Result<usize>> {
        throw_unsup_format!("cannot read from stdout");
    }

    fn write<'tcx>(&mut self, _communicate_allowed: bool, bytes: &[u8]) -> InterpResult<'tcx, io::Result<usize>> {
        // We allow writing to stderr even with isolation enabled.
        let result = Write::write(self, bytes);
        // Stdout is buffered, flush to make sure it appears on the
        // screen.  This is the write() syscall of the interpreted
        // program, we want it to correspond to a write() syscall on
        // the host -- there is no good in adding extra buffering
        // here.
        io::stdout().flush().unwrap();

        Ok(result)
    }

    fn seek<'tcx>(&mut self, _communicate_allowed: bool, _offset: SeekFrom) -> InterpResult<'tcx, io::Result<u64>> {
        throw_unsup_format!("cannot seek on stdout");
    }
}

impl FileDescriptor for io::Stderr {
    fn as_file_handle<'tcx>(&self) -> InterpResult<'tcx, &FileHandle> {
        throw_unsup_format!("stderr cannot be used as FileHandle");
    }

    fn read<'tcx>(&mut self, _communicate_allowed: bool, _bytes: &mut [u8]) -> InterpResult<'tcx, io::Result<usize>> {
{'fraction_non_alphanumeric': 0.15073360843649702, 'fraction_numerical': 0.004355800091701055, 'mean_word_length': 4.078579743888242, 'pattern_counts': {'":': 0, '<': 101, '<?xml version=': 0, '>': 137, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4854200', 'n_tokens_mistral': 2830, 'n_tokens_neox': 2949, 'n_words': 723}