in sources/api/datastore/src/filesystem.rs [116:169]
fn delete_key_path<P>(&mut self, path: P, committed: &Committed) -> Result<()>
where
P: AsRef<Path>,
{
let path = path.as_ref();
// Remove the file. If it doesn't exist, we're still OK.
match fs::remove_file(path) {
Ok(()) => {}
Err(e) => {
if e.kind() != io::ErrorKind::NotFound {
return Err(e).context(error::DeleteKey { path });
}
}
}
// Remove the directory if it's empty, i.e. if the setting we removed was the last setting
// in that prefix. Continue up the tree until the base, in case it was the only thing in
// that subtree.
let base = self.base_path(committed);
if let Some(parent) = path.parent() {
// Note: ancestors() includes 'parent' itself
for parent in parent.ancestors() {
// Stop at the base directory; we don't expect anything here or above to be empty,
// but stop as a safeguard.
if parent == base {
break;
}
if let Err(e) = fs::remove_dir(parent) {
// If the directory doesn't exist, continue up the tree. Modulo timing issues,
// this means the key didn't exist either, which means a previous attempt to remove
// the directory failed or we got an unset request for a bogus key. Either way, we
// can clean up and make things consistent.
if e.kind() == io::ErrorKind::NotFound {
continue;
// "Directory not empty" doesn't have its own ErrorKind, so we have to check a
// platform-specific error number or the error description, neither of which is
// ideal. Still, we can at least log an error in the case we know. Don't
// fail, though, because we've still accomplished our main purpose.
} else if e.raw_os_error() != Some(39) {
error!(
"Failed to delete directory '{}' we believe is empty: {}",
parent.display(),
e
);
}
// We won't be able to delete parent directories if this one still exists.
break;
}
}
}
Ok(())
}