Skip to content

Commit 5fd3459

Browse files
authored
mktemp: Fix template validation to require trailing consecutive Xs (#10224)
* fix(mktemp): Validation of consecutive X's at template end * fix(mktemp): Updated integration tests to expect failure for templates that do not end with a sufficient X run * mktemp: document trailing-X template parsing * mktemp: match GNU behavior for template X run detection Change logic to only accept templates where the run of Xs containing the final 'X' is at least 3 characters long. This fixes cases like "XXX_XX", which should error with "too few X's in template", and allows "tempXXXlate", matching GNU mktemp * mktemp: Simplify search using rposition
1 parent 2c75e71 commit 5fd3459

2 files changed

Lines changed: 53 additions & 3 deletions

File tree

src/uu/mktemp/src/mktemp.rs

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -193,9 +193,22 @@ struct Params {
193193
/// assert_eq!(find_last_contiguous_block_of_xs("aXbXcX"), None);
194194
/// ```
195195
fn find_last_contiguous_block_of_xs(s: &str) -> Option<(usize, usize)> {
196-
let j = s.rfind("XXX")? + 3;
197-
let i = s[..j].rfind(|c| c != 'X').map_or(0, |i| i + 1);
198-
Some((i, j))
196+
let bytes = s.as_bytes();
197+
198+
// Find the index of the last 'X'.
199+
let end = bytes.iter().rposition(|&b| b == b'X')?;
200+
201+
// Walk left to find the start of the run of Xs that ends at `end`.
202+
let mut start = end;
203+
while start > 0 && bytes[start - 1] == b'X' {
204+
start -= 1;
205+
}
206+
207+
if end + 1 - start >= 3 {
208+
Some((start, end + 1))
209+
} else {
210+
None
211+
}
199212
}
200213

201214
impl Params {

tests/by-util/test_mktemp.rs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ static TEST_TEMPLATE7: &str = "XXXtemplate";
3030
static TEST_TEMPLATE8: &str = "tempXXXl/ate";
3131
#[cfg(windows)]
3232
static TEST_TEMPLATE8: &str = "tempXXXl\\ate";
33+
static TEST_TEMPLATE9: &str = "XXX_XX";
3334

3435
#[cfg(not(windows))]
3536
const TMPDIR: &str = "TMPDIR";
@@ -109,6 +110,11 @@ fn test_mktemp_mktemp() {
109110
.env(TMPDIR, &pathname)
110111
.arg(TEST_TEMPLATE8)
111112
.fails();
113+
scene
114+
.ucmd()
115+
.env(TMPDIR, &pathname)
116+
.arg(TEST_TEMPLATE9)
117+
.fails();
112118
}
113119

114120
#[test]
@@ -168,6 +174,12 @@ fn test_mktemp_mktemp_t() {
168174
.no_stdout()
169175
.stderr_contains("invalid suffix")
170176
.stderr_contains("contains directory separator");
177+
scene
178+
.ucmd()
179+
.env(TMPDIR, &pathname)
180+
.arg("-t")
181+
.arg(TEST_TEMPLATE9)
182+
.fails();
171183
}
172184

173185
#[test]
@@ -224,6 +236,12 @@ fn test_mktemp_make_temp_dir() {
224236
.arg("-d")
225237
.arg(TEST_TEMPLATE8)
226238
.fails();
239+
scene
240+
.ucmd()
241+
.env(TMPDIR, &pathname)
242+
.arg("-d")
243+
.arg(TEST_TEMPLATE9)
244+
.fails();
227245
}
228246

229247
#[test]
@@ -280,6 +298,12 @@ fn test_mktemp_dry_run() {
280298
.arg("-u")
281299
.arg(TEST_TEMPLATE8)
282300
.fails();
301+
scene
302+
.ucmd()
303+
.env(TMPDIR, &pathname)
304+
.arg("-u")
305+
.arg(TEST_TEMPLATE9)
306+
.fails();
283307
}
284308

285309
#[test]
@@ -367,6 +391,13 @@ fn test_mktemp_suffix() {
367391
.arg("suf")
368392
.arg(TEST_TEMPLATE8)
369393
.fails();
394+
scene
395+
.ucmd()
396+
.env(TMPDIR, &pathname)
397+
.arg("--suffix")
398+
.arg("suf")
399+
.arg(TEST_TEMPLATE9)
400+
.fails();
370401
}
371402

372403
#[test]
@@ -424,6 +455,12 @@ fn test_mktemp_tmpdir() {
424455
.arg(pathname)
425456
.arg(TEST_TEMPLATE8)
426457
.fails();
458+
scene
459+
.ucmd()
460+
.arg("-p")
461+
.arg(pathname)
462+
.arg(TEST_TEMPLATE9)
463+
.fails();
427464
}
428465

429466
#[test]

0 commit comments

Comments
 (0)