mirror of
https://github.com/uutils/findutils.git
synced 2026-06-10 15:48:30 -07:00
updatedb: clear error when the output database can't be created
Opening the output file with `?` surfaced a bare "No such file or directory" with no indication of which file failed (easy to hit because the default output path /usr/local/var/locatedb often doesn't exist). Report it like GNU does, naming the path and the reason, e.g. `cannot create '/usr/local/var/locatedb': No such file or directory`. strip_errno() drops the trailing "(os error N)" noise.
This commit is contained in:
+35
-11
@@ -14,7 +14,7 @@ use std::{
|
||||
};
|
||||
|
||||
use clap::{crate_version, value_parser, Arg, ArgAction, ArgMatches, Command};
|
||||
use uucore::error::UResult;
|
||||
use uucore::error::{strip_errno, UResult, USimpleError};
|
||||
|
||||
use crate::find::{find_main, Dependencies};
|
||||
|
||||
@@ -323,22 +323,46 @@ fn do_updatedb(args: &[&str]) -> UResult<()> {
|
||||
let deps = CapturedDependencies::new(output.clone());
|
||||
find_main(find_args.as_slice(), &deps);
|
||||
|
||||
let mut writer = BufWriter::new(
|
||||
OpenOptions::new()
|
||||
.write(true)
|
||||
.truncate(true)
|
||||
.create(true)
|
||||
.open(config.output)?,
|
||||
);
|
||||
let output_path = config.output;
|
||||
let file = OpenOptions::new()
|
||||
.write(true)
|
||||
.truncate(true)
|
||||
.create(true)
|
||||
.open(&output_path)
|
||||
.map_err(|e| {
|
||||
USimpleError::new(
|
||||
1,
|
||||
format!(
|
||||
"cannot create '{}': {}",
|
||||
output_path.display(),
|
||||
strip_errno(&e)
|
||||
),
|
||||
)
|
||||
})?;
|
||||
let mut writer = BufWriter::new(file);
|
||||
|
||||
// strip the trailing "(os error N)" so write failures read like the create error above
|
||||
let write_err = |e: std::io::Error| {
|
||||
USimpleError::new(
|
||||
1,
|
||||
format!(
|
||||
"error writing '{}': {}",
|
||||
output_path.display(),
|
||||
strip_errno(&e)
|
||||
),
|
||||
)
|
||||
};
|
||||
|
||||
let output = output.borrow();
|
||||
let frcoder = Frcoder::new(output.as_slice(), config.db_format);
|
||||
writer.write_all(&frcoder.generate_header())?;
|
||||
writer
|
||||
.write_all(&frcoder.generate_header())
|
||||
.map_err(&write_err)?;
|
||||
for v in frcoder {
|
||||
writer.write_all(v.as_slice())?;
|
||||
writer.write_all(v.as_slice()).map_err(&write_err)?;
|
||||
}
|
||||
|
||||
writer.flush()?;
|
||||
writer.flush().map_err(&write_err)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -196,6 +196,32 @@ fn test_updatedb_empty_prune() {
|
||||
.success();
|
||||
}
|
||||
|
||||
// when the output database can't be created, updatedb must report a clear error naming the path
|
||||
// and must not leak the raw "(os error N)" suffix
|
||||
#[test]
|
||||
fn test_updatedb_output_create_error() {
|
||||
let tmp = tempfile::tempdir().unwrap();
|
||||
// a path under a non-existent directory can't be created
|
||||
let bad_output = tmp.path().join("does-not-exist").join("db");
|
||||
let assert = Command::cargo_bin("updatedb")
|
||||
.expect("couldn't find updatedb binary")
|
||||
.args([
|
||||
"--localpaths=./test_data".to_string(),
|
||||
format!("--output={}", bad_output.display()),
|
||||
])
|
||||
.assert()
|
||||
.failure();
|
||||
let stderr = String::from_utf8_lossy(&assert.get_output().stderr);
|
||||
assert!(
|
||||
stderr.contains("cannot create") && stderr.contains(&bad_output.display().to_string()),
|
||||
"stderr did not name the un-creatable output path: {stderr:?}"
|
||||
);
|
||||
assert!(
|
||||
!stderr.contains("os error"),
|
||||
"stderr leaked the raw OS error: {stderr:?}"
|
||||
);
|
||||
}
|
||||
|
||||
// build a database from a temp tree with updatedb, then query it back with locate. This is the
|
||||
// only test that exercises the full pipeline (writer + reader) and is platform-independent.
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user