Skip to content

Commit 6bc9f47

Browse files
comm: report I/O errors
I/O errors were being silently suppressed. This also removes an unnecessary check to see if one of the inputs is a directory.
1 parent 8f7afa7 commit 6bc9f47

File tree

4 files changed

+89
-47
lines changed

4 files changed

+89
-47
lines changed

src/uu/comm/locales/en-US.ftl

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ comm-help-no-check-order = do not check that the input is correctly sorted
2020
# Error messages
2121
comm-error-file-not-sorted = comm: file { $file_num } is not in sorted order
2222
comm-error-input-not-sorted = comm: input is not in sorted order
23-
comm-error-is-directory = Is a directory
2423
comm-error-multiple-conflicting-delimiters = multiple conflicting output delimiters specified
2524
2625
# Other messages

src/uu/comm/locales/fr-FR.ftl

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ comm-help-no-check-order = ne pas vérifier que l'entrée est correctement trié
2020
# Messages d'erreur
2121
comm-error-file-not-sorted = comm : le fichier { $file_num } n'est pas dans l'ordre trié
2222
comm-error-input-not-sorted = comm : l'entrée n'est pas dans l'ordre trié
23-
comm-error-is-directory = Est un répertoire
2423
comm-error-multiple-conflicting-delimiters = plusieurs délimiteurs de sortie en conflit spécifiés
2524
2625
# Autres messages

src/uu/comm/src/comm.rs

Lines changed: 54 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use std::cmp::Ordering;
99
use std::ffi::OsString;
1010
use std::fs::{File, metadata};
1111
use std::io::{self, BufRead, BufReader, Read, StdinLock, stdin};
12-
use std::path::Path;
12+
use std::path::{Path, PathBuf};
1313
use uucore::error::{FromIo, UResult, USimpleError};
1414
use uucore::format_usage;
1515
use uucore::fs::paths_refer_to_same_file;
@@ -56,16 +56,29 @@ struct OrderChecker {
5656

5757
enum Input {
5858
Stdin(StdinLock<'static>),
59-
FileIn(BufReader<File>),
59+
FileIn {
60+
path: PathBuf,
61+
file: BufReader<File>,
62+
},
6063
}
6164

6265
impl Input {
6366
fn stdin() -> Self {
6467
Self::Stdin(stdin().lock())
6568
}
6669

67-
fn from_file(f: File) -> Self {
68-
Self::FileIn(BufReader::new(f))
70+
fn from_file(path: PathBuf, file: File) -> Self {
71+
Self::FileIn {
72+
path,
73+
file: BufReader::new(file),
74+
}
75+
}
76+
77+
fn path(&self) -> &Path {
78+
match self {
79+
Self::Stdin(_) => Path::new("-"),
80+
Self::FileIn { path, .. } => path,
81+
}
6982
}
7083
}
7184

@@ -79,19 +92,22 @@ impl LineReader {
7992
Self { line_ending, input }
8093
}
8194

82-
fn read_line(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
95+
fn read_line(&mut self, buf: &mut Vec<u8>) -> UResult<usize> {
96+
buf.clear();
97+
8398
let line_ending = self.line_ending.into();
8499

85-
let result = match &mut self.input {
100+
let n = match &mut self.input {
86101
Input::Stdin(r) => r.read_until(line_ending, buf),
87-
Input::FileIn(r) => r.read_until(line_ending, buf),
88-
};
102+
Input::FileIn { file: r, .. } => r.read_until(line_ending, buf),
103+
}
104+
.map_err_context(|| self.input.path().display().to_string())?;
89105

90-
if !buf.ends_with(&[line_ending]) {
106+
if n > 0 && !buf.ends_with(&[line_ending]) {
91107
buf.push(line_ending);
92108
}
93109

94-
result
110+
Ok(n)
95111
}
96112
}
97113

@@ -185,10 +201,10 @@ fn comm(a: &mut LineReader, b: &mut LineReader, delim: &str, opts: &ArgMatches)
185201
let delim_col_2 = delim.repeat(width_col_1);
186202
let delim_col_3 = delim.repeat(width_col_1 + width_col_2);
187203

188-
let ra = &mut Vec::new();
189-
let mut na = a.read_line(ra);
190-
let rb = &mut Vec::new();
191-
let mut nb = b.read_line(rb);
204+
let line_a = &mut Vec::new();
205+
let line_b = &mut Vec::new();
206+
a.read_line(line_a)?;
207+
b.read_line(line_b)?;
192208

193209
let mut total_col_1 = 0;
194210
let mut total_col_2 = 0;
@@ -214,54 +230,46 @@ fn comm(a: &mut LineReader, b: &mut LineReader, delim: &str, opts: &ArgMatches)
214230
let mut checker2 = OrderChecker::new(FileNumber::Two, check_order);
215231
let mut input_error = false;
216232

217-
while na.is_ok() || nb.is_ok() {
218-
let ord = match (na.is_ok(), nb.is_ok()) {
219-
(false, true) => Ordering::Greater,
220-
(true, false) => Ordering::Less,
221-
(true, true) => match (&na, &nb) {
222-
(&Ok(0), &Ok(0)) => break,
223-
(&Ok(0), _) => Ordering::Greater,
224-
(_, &Ok(0)) => Ordering::Less,
225-
_ => ra.cmp(&rb),
226-
},
227-
_ => unreachable!(),
233+
loop {
234+
let ord = match (line_a.is_empty(), line_b.is_empty()) {
235+
(true, true) => break,
236+
(true, false) => Ordering::Greater,
237+
(false, true) => Ordering::Less,
238+
(false, false) => line_a.cmp(&line_b),
228239
};
229240

230241
match ord {
231242
Ordering::Less => {
232-
if should_check_order && !checker1.verify_order(ra) {
243+
if should_check_order && !checker1.verify_order(line_a) {
233244
break;
234245
}
235246
if !opts.get_flag(options::COLUMN_1) {
236-
print!("{}", String::from_utf8_lossy(ra));
247+
print!("{}", String::from_utf8_lossy(line_a));
237248
}
238-
ra.clear();
239-
na = a.read_line(ra);
249+
a.read_line(line_a)?;
240250
total_col_1 += 1;
241251
}
242252
Ordering::Greater => {
243-
if should_check_order && !checker2.verify_order(rb) {
253+
if should_check_order && !checker2.verify_order(line_b) {
244254
break;
245255
}
246256
if !opts.get_flag(options::COLUMN_2) {
247-
print!("{delim_col_2}{}", String::from_utf8_lossy(rb));
257+
print!("{delim_col_2}{}", String::from_utf8_lossy(line_b));
248258
}
249-
rb.clear();
250-
nb = b.read_line(rb);
259+
b.read_line(line_b)?;
251260
total_col_2 += 1;
252261
}
253262
Ordering::Equal => {
254-
if should_check_order && (!checker1.verify_order(ra) || !checker2.verify_order(rb))
263+
if should_check_order
264+
&& (!checker1.verify_order(line_a) || !checker2.verify_order(line_b))
255265
{
256266
break;
257267
}
258268
if !opts.get_flag(options::COLUMN_3) {
259-
print!("{delim_col_3}{}", String::from_utf8_lossy(ra));
269+
print!("{delim_col_3}{}", String::from_utf8_lossy(line_a));
260270
}
261-
ra.clear();
262-
rb.clear();
263-
na = a.read_line(ra);
264-
nb = b.read_line(rb);
271+
a.read_line(line_a)?;
272+
b.read_line(line_b)?;
265273
total_col_3 += 1;
266274
}
267275
}
@@ -291,15 +299,16 @@ fn comm(a: &mut LineReader, b: &mut LineReader, delim: &str, opts: &ArgMatches)
291299
}
292300
}
293301

294-
fn open_file(name: &OsString, line_ending: LineEnding) -> io::Result<LineReader> {
295-
if name == "-" {
302+
fn open_file<P: AsRef<Path>>(name: P, line_ending: LineEnding) -> io::Result<LineReader> {
303+
let name = name.as_ref();
304+
if name.as_os_str() == "-" {
296305
Ok(LineReader::new(Input::stdin(), line_ending))
297306
} else {
298-
if metadata(name)?.is_dir() {
299-
return Err(io::Error::other(translate!("comm-error-is-directory")));
300-
}
301307
let f = File::open(name)?;
302-
Ok(LineReader::new(Input::from_file(f), line_ending))
308+
Ok(LineReader::new(
309+
Input::from_file(name.to_path_buf(), f),
310+
line_ending,
311+
))
303312
}
304313
}
305314

tests/by-util/test_comm.rs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -417,6 +417,7 @@ fn test_no_such_file() {
417417
}
418418

419419
#[test]
420+
#[cfg(unix)]
420421
fn test_is_dir() {
421422
let scene = TestScenario::new(util_name!());
422423
let at = &scene.fixtures;
@@ -449,6 +450,40 @@ fn test_is_dir() {
449450
.stderr_only("comm: .: Is a directory\n");
450451
}
451452

453+
#[test]
454+
#[cfg(windows)]
455+
fn test_is_dir() {
456+
let scene = TestScenario::new(util_name!());
457+
let at = &scene.fixtures;
458+
459+
scene
460+
.ucmd()
461+
.args(&[".", "."])
462+
.fails()
463+
.stderr_only("comm: .: Permission denied\n");
464+
465+
at.mkdir("dir");
466+
scene
467+
.ucmd()
468+
.args(&["dir", "."])
469+
.fails()
470+
.stderr_only("comm: dir: Permission denied\n");
471+
472+
at.touch("file");
473+
scene
474+
.ucmd()
475+
.args(&[".", "file"])
476+
.fails()
477+
.stderr_only("comm: .: Permission denied\n");
478+
479+
at.touch("file");
480+
scene
481+
.ucmd()
482+
.args(&["file", "."])
483+
.fails()
484+
.stderr_only("comm: .: Permission denied\n");
485+
}
486+
452487
#[test]
453488
fn test_sorted() {
454489
let expected_stderr =

0 commit comments

Comments
 (0)