Skip to content

Commit 6f84804

Browse files
committed
fold: fix crash when reading from pseudo-devices
squashme: wraparound struct for fold squashme: fix crash when reading from pseudo-devices Fixes #11291
1 parent 1ee881b commit 6f84804

1 file changed

Lines changed: 31 additions & 49 deletions

File tree

src/uu/fold/src/fold.rs

Lines changed: 31 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -194,64 +194,46 @@ fn fold_file_bytewise<T: Read, W: Write>(
194194
let mut line = Vec::new();
195195

196196
loop {
197-
if file
198-
.read_until(NL, &mut line)
199-
.map_err_context(|| translate!("fold-error-readline"))?
200-
== 0
201-
{
202-
break;
197+
// Ensures that our line always has enough bytes to either
198+
// come across a newline, a whitespace or just wrap around.
199+
while width > line.len() {
200+
let buf = file
201+
.fill_buf()
202+
.map_err_context(|| translate!("fold-error-readline"))?;
203+
if buf.is_empty() {
204+
break;
205+
}
206+
line.extend_from_slice(buf);
207+
let len = buf.len();
208+
file.consume(len);
203209
}
204210

205-
if line == [NL] {
206-
output.write_all(&[NL])?;
207-
line.clear();
208-
continue;
211+
// The width exceeds the line read so far if we have
212+
// reached EOF.
213+
if width > line.len() {
214+
output.write_all(&line)?;
215+
break;
209216
}
210217

211-
let len = line.len();
212-
let mut i = 0;
213-
214-
while i < len {
215-
let width = if len - i >= width { width } else { len - i };
216-
let slice = {
217-
let slice = &line[i..i + width];
218-
if spaces && i + width < len {
219-
match slice
220-
.iter()
221-
.enumerate()
222-
.rev()
223-
.find(|(_, c)| c.is_ascii_whitespace() && **c != CR)
224-
{
225-
Some((m, _)) => &slice[..=m],
226-
None => slice,
227-
}
228-
} else {
229-
slice
230-
}
231-
};
232-
233-
// Don't duplicate trailing newlines: if the slice is "\n", the
234-
// previous iteration folded just before the end of the line and
235-
// has already printed this newline.
236-
if slice == [NL] {
237-
break;
238-
}
218+
let chunk = &line[..width];
219+
let newline_end = chunk.iter().position(|c| NL.eq(c)).map(|v| v + 1);
239220

240-
i += slice.len();
221+
let space_end = chunk
222+
.iter()
223+
.rposition(|c| spaces && c.is_ascii_whitespace() && !CR.eq(c))
224+
.map(|v| v + 1);
241225

242-
let at_eol = i >= len;
226+
let end = newline_end.or(space_end).unwrap_or(width);
227+
let slice = &line[..end];
243228

244-
if at_eol {
245-
output.write_all(slice)?;
246-
} else {
247-
output.write_all(slice)?;
248-
output.write_all(&[NL])?;
249-
}
229+
output.write_all(slice)?;
230+
let slice_ends_without_newline = line[end - 1] != NL;
231+
let no_newline_follows_slice = line.get(end).is_some_and(|c| *c != NL);
232+
if slice_ends_without_newline && no_newline_follows_slice {
233+
output.write_all(&[NL])?;
250234
}
251-
252-
line.clear();
235+
line.drain(..end);
253236
}
254-
255237
Ok(())
256238
}
257239

0 commit comments

Comments
 (0)