rm unused fn
This commit is contained in:
parent
0dc4a72500
commit
e2a83fe122
95
src/util.rs
95
src/util.rs
|
|
@ -149,101 +149,6 @@ impl FzfChild {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Similar to [`fs::write`], but atomic (best effort on Windows).
|
|
||||||
pub fn write(path: impl AsRef<Path>, contents: impl AsRef<[u8]>) -> Result<()> {
|
|
||||||
let path = path.as_ref();
|
|
||||||
let contents = contents.as_ref();
|
|
||||||
let dir = path.parent().unwrap();
|
|
||||||
|
|
||||||
// Create a tmpfile.
|
|
||||||
let (mut tmp_file, tmp_path) = tmpfile(dir)?;
|
|
||||||
let result = (|| {
|
|
||||||
// Write to the tmpfile.
|
|
||||||
_ = tmp_file.set_len(contents.len() as u64);
|
|
||||||
tmp_file
|
|
||||||
.write_all(contents)
|
|
||||||
.with_context(|| format!("could not write to file: {}", tmp_path.display()))?;
|
|
||||||
|
|
||||||
// Set the owner of the tmpfile (UNIX only).
|
|
||||||
#[cfg(unix)]
|
|
||||||
if let Ok(metadata) = path.metadata() {
|
|
||||||
use std::os::unix::fs::MetadataExt;
|
|
||||||
|
|
||||||
use nix::unistd::{self, Gid, Uid};
|
|
||||||
|
|
||||||
let uid = Uid::from_raw(metadata.uid());
|
|
||||||
let gid = Gid::from_raw(metadata.gid());
|
|
||||||
_ = unistd::fchown(&tmp_file, Some(uid), Some(gid));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close and rename the tmpfile.
|
|
||||||
// In some cases, errors from the last write() are reported only on close().
|
|
||||||
// Rust ignores errors from close(), since it occurs inside `Drop`. To
|
|
||||||
// catch these errors, we manually call `File::sync_all()` first.
|
|
||||||
tmp_file
|
|
||||||
.sync_all()
|
|
||||||
.with_context(|| format!("could not sync writes to file: {}", tmp_path.display()))?;
|
|
||||||
mem::drop(tmp_file);
|
|
||||||
rename(&tmp_path, path)
|
|
||||||
})();
|
|
||||||
// In case of an error, delete the tmpfile.
|
|
||||||
if result.is_err() {
|
|
||||||
_ = fs::remove_file(&tmp_path);
|
|
||||||
}
|
|
||||||
result
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Atomically create a tmpfile in the given directory.
|
|
||||||
fn tmpfile(dir: impl AsRef<Path>) -> Result<(File, PathBuf)> {
|
|
||||||
const MAX_ATTEMPTS: usize = 5;
|
|
||||||
const TMP_NAME_LEN: usize = 16;
|
|
||||||
let dir = dir.as_ref();
|
|
||||||
|
|
||||||
let mut attempts = 0;
|
|
||||||
loop {
|
|
||||||
attempts += 1;
|
|
||||||
|
|
||||||
// Generate a random name for the tmpfile.
|
|
||||||
let mut name = String::with_capacity(TMP_NAME_LEN);
|
|
||||||
name.push_str("tmp_");
|
|
||||||
while name.len() < TMP_NAME_LEN {
|
|
||||||
name.push(fastrand::alphanumeric());
|
|
||||||
}
|
|
||||||
let path = dir.join(name);
|
|
||||||
|
|
||||||
// Atomically create the tmpfile.
|
|
||||||
match OpenOptions::new().write(true).create_new(true).open(&path) {
|
|
||||||
Ok(file) => break Ok((file, path)),
|
|
||||||
Err(e) if e.kind() == io::ErrorKind::AlreadyExists && attempts < MAX_ATTEMPTS => {}
|
|
||||||
Err(e) => {
|
|
||||||
break Err(e).with_context(|| format!("could not create file: {}", path.display()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Similar to [`fs::rename`], but with retries on Windows.
|
|
||||||
fn rename(from: impl AsRef<Path>, to: impl AsRef<Path>) -> Result<()> {
|
|
||||||
let from = from.as_ref();
|
|
||||||
let to = to.as_ref();
|
|
||||||
|
|
||||||
const MAX_ATTEMPTS: usize = if cfg!(windows) { 5 } else { 1 };
|
|
||||||
let mut attempts = 0;
|
|
||||||
|
|
||||||
loop {
|
|
||||||
match fs::rename(from, to) {
|
|
||||||
Err(e) if e.kind() == io::ErrorKind::PermissionDenied && attempts < MAX_ATTEMPTS => {
|
|
||||||
attempts += 1
|
|
||||||
}
|
|
||||||
result => {
|
|
||||||
break result.with_context(|| {
|
|
||||||
format!("could not rename file: {} -> {}", from.display(), to.display())
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn canonicalize(path: impl AsRef<Path>) -> Result<PathBuf> {
|
pub fn canonicalize(path: impl AsRef<Path>) -> Result<PathBuf> {
|
||||||
dunce::canonicalize(&path)
|
dunce::canonicalize(&path)
|
||||||
.with_context(|| format!("could not resolve path: {}", path.as_ref().display()))
|
.with_context(|| format!("could not resolve path: {}", path.as_ref().display()))
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue