mirror of
https://github.com/fish-shell/fish-shell.git
synced 2024-11-24 10:46:59 +08:00
Suppress spurious error when config dir creation fails due to TOCTOU
Some checks failed
Rust checks / rustfmt (push) Has been cancelled
Rust checks / clippy (push) Has been cancelled
make test / ubuntu (push) Has been cancelled
make test / ubuntu-32bit-static-pcre2 (push) Has been cancelled
make test / ubuntu-asan (push) Has been cancelled
make test / macos (push) Has been cancelled
Some checks failed
Rust checks / rustfmt (push) Has been cancelled
Rust checks / clippy (push) Has been cancelled
make test / ubuntu (push) Has been cancelled
make test / ubuntu-32bit-static-pcre2 (push) Has been cancelled
make test / ubuntu-asan (push) Has been cancelled
make test / macos (push) Has been cancelled
Our recursive create_dir() first calls stat() to check if the directory already exists and then mkdir() trying to create it. If another (fish) process creates the same directory after our stat() but before our mkdir(), then our mkdir() fails with EEXIST. This error is spurious if there is already a directory at this path (and permissions are correct). Let's switch to the stdlib version, which promises to solve this issue. They currently do it by running mkdir() first and ask stat() later. This implies that they will only return success even if we don't have any of rwx permissions on the directory, but that was already a problem before this change. We silently don't write history in that case.. Fixes #10813
This commit is contained in:
parent
9e01981bb9
commit
3710e98d65
29
src/path.rs
29
src/path.rs
|
@ -2,14 +2,14 @@
|
|||
//! for testing if a command with a given name can be found in the PATH, and various other
|
||||
//! path-related issues.
|
||||
|
||||
use crate::common::{is_windows_subsystem_for_linux as is_wsl, wcs2zstring, WSL};
|
||||
use crate::common::{is_windows_subsystem_for_linux as is_wsl, wcs2osstring, wcs2zstring, WSL};
|
||||
use crate::env::{EnvMode, EnvStack, Environment};
|
||||
use crate::expand::{expand_tilde, HOME_DIRECTORY};
|
||||
use crate::flog::{FLOG, FLOGF};
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
use crate::libc::{MNT_LOCAL, ST_LOCAL};
|
||||
use crate::wchar::prelude::*;
|
||||
use crate::wutil::{normalize_path, path_normalize_for_cd, waccess, wdirname, wmkdir, wstat};
|
||||
use crate::wutil::{normalize_path, path_normalize_for_cd, waccess, wdirname, wstat};
|
||||
use errno::{errno, set_errno, Errno};
|
||||
use libc::{EACCES, ENOENT, ENOTDIR, F_OK, X_OK};
|
||||
use once_cell::sync::Lazy;
|
||||
|
@ -667,8 +667,8 @@ fn make_base_directory(xdg_var: &wstr, non_xdg_homepath: &wstr) -> BaseDirectory
|
|||
let mut remoteness = DirRemoteness::unknown;
|
||||
if path.is_empty() {
|
||||
err = ENOENT;
|
||||
} else if !create_directory(&path) {
|
||||
err = errno().0;
|
||||
} else if let Err(io_error) = std::fs::create_dir_all(wcs2osstring(&path)) {
|
||||
err = io_error.raw_os_error().unwrap_or_default();
|
||||
} else {
|
||||
err = 0;
|
||||
// Need to append a trailing slash to check the contents of the directory, not its parent.
|
||||
|
@ -685,27 +685,6 @@ fn make_base_directory(xdg_var: &wstr, non_xdg_homepath: &wstr) -> BaseDirectory
|
|||
}
|
||||
}
|
||||
|
||||
/// Make sure the specified directory exists. If needed, try to create it and any currently not
|
||||
/// existing parent directories, like mkdir -p,.
|
||||
///
|
||||
/// Return 0 if, at the time of function return the directory exists, -1 otherwise.
|
||||
fn create_directory(d: &wstr) -> bool {
|
||||
let md = loop {
|
||||
match wstat(d) {
|
||||
Err(md) if md.kind() == ErrorKind::Interrupted => continue,
|
||||
md => break md,
|
||||
}
|
||||
};
|
||||
match md {
|
||||
Ok(md) if md.is_dir() => true,
|
||||
Err(e) if e.kind() == ErrorKind::NotFound => {
|
||||
let dir: &wstr = wdirname(d);
|
||||
return create_directory(dir) && wmkdir(d, 0o700) == 0;
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Return whether the given path is on a remote filesystem.
|
||||
fn path_remoteness(path: &wstr) -> DirRemoteness {
|
||||
let narrow = wcs2zstring(path);
|
||||
|
|
|
@ -501,12 +501,6 @@ pub fn wbasename(mut path: &wstr) -> &wstr {
|
|||
path
|
||||
}
|
||||
|
||||
/// Wide character version of mkdir.
|
||||
pub fn wmkdir(name: &wstr, mode: libc::mode_t) -> libc::c_int {
|
||||
let name_narrow = wcs2zstring(name);
|
||||
unsafe { libc::mkdir(name_narrow.as_ptr(), mode) }
|
||||
}
|
||||
|
||||
/// Wide character version of rename.
|
||||
pub fn wrename(old_name: &wstr, new_name: &wstr) -> libc::c_int {
|
||||
let old_narrow = wcs2zstring(old_name);
|
||||
|
|
Loading…
Reference in New Issue
Block a user