Implement mkdirat
Linux's variant uses the syscall as intended. Redox's variant uses fpath to build a path to pass to mkdir from the file descriptor plus the file name, which isn't atomic due to the fpath lookup being subject to TOCTOU when paired with mkdir.
This commit is contained in:
@@ -160,6 +160,15 @@ pub unsafe extern "C" fn lstat(path: *const c_char, buf: *mut stat) -> c_int {
|
||||
res
|
||||
}
|
||||
|
||||
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/mkdirat.html>.
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn mkdirat(dirfd: c_int, path: *const c_char, mode: mode_t) -> c_int {
|
||||
let path = CStr::from_ptr(path);
|
||||
Sys::mkdirat(dirfd, path, mode)
|
||||
.map(|()| 0)
|
||||
.or_minus_one_errno()
|
||||
}
|
||||
|
||||
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/mkdir.html>.
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn mkdir(path: *const c_char, mode: mode_t) -> c_int {
|
||||
|
||||
@@ -502,8 +502,12 @@ impl Pal for Sys {
|
||||
e_raw(unsafe { syscall!(LSEEK, fildes, offset, whence) }).map(|o| o as off_t)
|
||||
}
|
||||
|
||||
fn mkdirat(dir_fildes: c_int, path: CStr, mode: mode_t) -> Result<()> {
|
||||
e_raw(unsafe { syscall!(MKDIRAT, dir_fildes, path.as_ptr(), mode) }).map(|_| ())
|
||||
}
|
||||
|
||||
fn mkdir(path: CStr, mode: mode_t) -> Result<()> {
|
||||
e_raw(unsafe { syscall!(MKDIRAT, AT_FDCWD, path.as_ptr(), mode) }).map(|_| ())
|
||||
Sys::mkdirat(AT_FDCWD, path, mode)
|
||||
}
|
||||
|
||||
fn mknodat(dir_fildes: c_int, path: CStr, mode: mode_t, dev: dev_t) -> Result<()> {
|
||||
|
||||
@@ -170,6 +170,8 @@ pub trait Pal {
|
||||
|
||||
fn lseek(fildes: c_int, offset: off_t, whence: c_int) -> Result<off_t>;
|
||||
|
||||
fn mkdirat(fildes: c_int, path: CStr, mode: mode_t) -> Result<()>;
|
||||
|
||||
fn mkdir(path: CStr, mode: mode_t) -> Result<()>;
|
||||
|
||||
fn mkfifo(path: CStr, mode: mode_t) -> Result<()>;
|
||||
|
||||
@@ -680,6 +680,24 @@ impl Pal for Sys {
|
||||
Ok(syscall::lseek(fd as usize, offset as isize, whence as usize)? as off_t)
|
||||
}
|
||||
|
||||
fn mkdirat(dir_fd: c_int, path_name: CStr, mode: mode_t) -> Result<()> {
|
||||
let mut dir_path_buf = [0; 4096];
|
||||
let res = Sys::fpath(dir_fd, &mut dir_path_buf)?;
|
||||
|
||||
let dir_path = str::from_utf8(&dir_path_buf[..res as usize]).map_err(|_| Errno(EBADR))?;
|
||||
|
||||
let resource_path =
|
||||
path::canonicalize_using_cwd(Some(&dir_path), &path_name.to_string_lossy())
|
||||
// Since parent_dir_path is resolved by fpath, it is more likely that
|
||||
// the problem was with path.
|
||||
.ok_or(Errno(ENOENT))?;
|
||||
|
||||
Sys::mkdir(
|
||||
CStr::borrow(&CString::new(resource_path.as_bytes()).unwrap()),
|
||||
mode,
|
||||
)
|
||||
}
|
||||
|
||||
fn mkdir(path: CStr, mode: mode_t) -> Result<()> {
|
||||
File::create(
|
||||
path,
|
||||
|
||||
Reference in New Issue
Block a user