Skip to content

Commit 2ebd3da

Browse files
committed
comm: fix comparison when reading from pipes
Use case is that two files are piped into comm, i.e. in bash comm <(cat file1) <(cat file2) Before the fix, comm reads from the pipes twice. Once in "fn comm" and once in "fn are_files_identical". As such, part of the data is skipped in comparison which leads to wrong output. This is fixed by skipping the file comparison in case one of the files is not a regular file.
1 parent 40db489 commit 2ebd3da

File tree

2 files changed

+38
-0
lines changed

2 files changed

+38
-0
lines changed

src/uu/comm/src/comm.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,11 @@ pub fn are_files_identical(path1: &Path, path2: &Path) -> io::Result<bool> {
135135
return Ok(false);
136136
}
137137

138+
// only proceed if both are regular files
139+
if !metadata1.is_file() || !metadata2.is_file() {
140+
return Ok(false);
141+
}
142+
138143
let file1 = File::open(path1)?;
139144
let file2 = File::open(path2)?;
140145

tests/by-util/test_comm.rs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -648,3 +648,36 @@ fn test_comm_eintr_handling() {
648648
.stdout_contains("line2")
649649
.stdout_contains("line3");
650650
}
651+
652+
#[test]
653+
#[cfg(unix)]
654+
fn test_anonymous_pipes() {
655+
let scene = TestScenario::new(util_name!());
656+
let at = &scene.fixtures;
657+
658+
let mut comm1_content = String::new();
659+
for i in 0..10000 {
660+
comm1_content.push_str(&format!("{i:05}\n"));
661+
}
662+
at.write("comm1", &comm1_content);
663+
664+
let mut comm2_content = String::new();
665+
for i in 0..9000 {
666+
comm2_content.push_str(&format!("{i:05}\n"));
667+
}
668+
// add one extra item which is only present in comm2
669+
comm2_content.push_str("99999\n");
670+
at.write("comm2", &comm2_content);
671+
672+
scene
673+
.cmd("bash")
674+
.arg("-c")
675+
.arg(format!(
676+
"{} comm -13 <(cat {}) <(cat {})",
677+
scene.bin_path.display(),
678+
at.plus("comm1").display(),
679+
at.plus("comm2").display()
680+
))
681+
.succeeds()
682+
.stdout_is("99999\n");
683+
}

0 commit comments

Comments
 (0)