@@ -2,8 +2,8 @@ use std::convert::TryFrom;
22use std::ffi::{OsStr, OsString};
33use std::fs::File;
44use std::io::{self, BufRead, BufReader, Read};
5−use std::path::Path;
65
6+use clircle::{Clircle, Identifier};
77use content_inspector::{self, ContentType};
88
99use crate::error::*;
@@ -157,25 +157,55 @@ impl<'a> Input<'a> {
157157 &mut self.description
158158 }
159159
160− pub(crate) fn open<R: BufRead + 'a>(self, stdin: R) -> Result<OpenedInput<'a>> {
160+ pub(crate) fn open<R: BufRead + 'a>(
161+ self,
162+ stdin: R,
163+ stdout_identifier: Option<&Identifier>,
164+ ) -> Result<OpenedInput<'a>> {
161165 let description = self.description().clone();
162166 match self.kind {
163− InputKind::StdIn => Ok(OpenedInput {
164− kind: OpenedInputKind::StdIn,
165− description,
166− metadata: self.metadata,
167− reader: InputReader::new(stdin),
168− }),
167+ InputKind::StdIn => {
168+ if let Some(stdout) = stdout_identifier {
169+ let input_identifier = Identifier::try_from(clircle::Stdio::Stdin)
170+ .map_err(|e| format!("Stdin: Error identifying file: {}", e))?;
171+ if stdout.surely_conflicts_with(&input_identifier) {
172+ return Err("IO circle detected. The input from stdin is also an output. Aborting to avoid infinite loop.".into());
173+ }
174+ }
175+
176+ Ok(OpenedInput {
177+ kind: OpenedInputKind::StdIn,
178+ description,
179+ metadata: self.metadata,
180+ reader: InputReader::new(stdin),
181+ })
182+ }
183+
169184 InputKind::OrdinaryFile(path) => Ok(OpenedInput {
170185 kind: OpenedInputKind::OrdinaryFile(path.clone()),
171186 description,
172187 metadata: self.metadata,
173188 reader: {
174− let file = File::open(&path)
189+ let mut file = File::open(&path)
175190 .map_err(|e| format!("'{}': {}", path.to_string_lossy(), e))?;
176191 if file.metadata()?.is_dir() {
177192 return Err(format!("'{}' is a directory.", path.to_string_lossy()).into());
178193 }
194+
195+ if let Some(stdout) = stdout_identifier {
196+ let input_identifier = Identifier::try_from(file).map_err(|e| {
197+ format!("{}: Error identifying file: {}", path.to_string_lossy(), e)
198+ })?;
199+ if stdout.surely_conflicts_with(&input_identifier) {
200+ return Err(format!(
201+ "IO circle detected. The input from '{}' is also an output. Aborting to avoid infinite loop.",
202+ path.to_string_lossy()
203+ )
204+ .into());
205+ }
206+ file = input_identifier.into_inner().expect("The file was lost in the clircle::Identifier, this should not have happended...");
207+ }
208+
179209 InputReader::new(BufReader::new(file))
180210 },
181211 }),
@@ -189,18 +219,6 @@ impl<'a> Input<'a> {
189219 }
190220}
191221
192−impl TryFrom<&'_ Input<'_>> for clircle::Identifier {
193− type Error = ();
194−
195− fn try_from(input: &Input) -> std::result::Result<clircle::Identifier, ()> {
196− match input.kind {
197− InputKind::OrdinaryFile(ref path) => Self::try_from(Path::new(path)).map_err(|_| ()),
198− InputKind::StdIn => Self::try_from(clircle::Stdio::Stdin).map_err(|_| ()),
199− InputKind::CustomReader(_) => Err(()),
200− }
201− }
202−}
203−
204222pub(crate) struct InputReader<'a> {
205223 inner: Box<dyn BufRead + 'a>,
206224 pub(crate) first_line: Vec<u8>,