#![allow(unsafe_code)]
use crate::buffer::Buffer;
use crate::fd::OwnedFd;
#[cfg(not(any(target_os = "espidf", target_os = "horizon", target_os = "vita")))]
use crate::fs::Access;
#[cfg(not(target_os = "espidf"))]
use crate::fs::AtFlags;
#[cfg(apple)]
use crate::fs::CloneFlags;
#[cfg(any(linux_kernel, apple))]
use crate::fs::RenameFlags;
#[cfg(not(target_os = "espidf"))]
use crate::fs::Stat;
#[cfg(not(any(apple, target_os = "espidf", target_os = "vita", target_os = "wasi")))]
use crate::fs::{Dev, FileType};
#[cfg(not(any(target_os = "espidf", target_os = "wasi")))]
use crate::fs::{Gid, Uid};
use crate::fs::{Mode, OFlags};
use crate::{backend, io, path};
use backend::fd::AsFd;
#[cfg(feature = "alloc")]
use {
crate::ffi::{CStr, CString},
crate::path::SMALL_PATH_BUFFER_SIZE,
alloc::vec::Vec,
backend::fd::BorrowedFd,
};
#[cfg(not(any(target_os = "espidf", target_os = "vita")))]
use {crate::fs::Timestamps, crate::timespec::Nsecs};
#[cfg(not(any(
target_os = "espidf",
target_os = "horizon",
target_os = "redox",
target_os = "vita"
)))]
pub const UTIME_NOW: Nsecs = backend::c::UTIME_NOW as Nsecs;
#[cfg(not(any(
target_os = "espidf",
target_os = "horizon",
target_os = "redox",
target_os = "vita"
)))]
pub const UTIME_OMIT: Nsecs = backend::c::UTIME_OMIT as Nsecs;
#[inline]
pub fn openat<P: path::Arg, Fd: AsFd>(
dirfd: Fd,
path: P,
oflags: OFlags,
create_mode: Mode,
) -> io::Result<OwnedFd> {
path.into_with_c_str(|path| {
backend::fs::syscalls::openat(dirfd.as_fd(), path, oflags, create_mode)
})
}
#[cfg(feature = "alloc")]
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
#[inline]
pub fn readlinkat<P: path::Arg, Fd: AsFd, B: Into<Vec<u8>>>(
dirfd: Fd,
path: P,
reuse: B,
) -> io::Result<CString> {
path.into_with_c_str(|path| _readlinkat(dirfd.as_fd(), path, reuse.into()))
}
#[cfg(feature = "alloc")]
#[allow(unsafe_code)]
fn _readlinkat(dirfd: BorrowedFd<'_>, path: &CStr, mut buffer: Vec<u8>) -> io::Result<CString> {
buffer.clear();
buffer.reserve(SMALL_PATH_BUFFER_SIZE);
loop {
let buf = buffer.spare_capacity_mut();
let nread = unsafe {
backend::fs::syscalls::readlinkat(
dirfd.as_fd(),
path,
(buf.as_mut_ptr().cast(), buf.len()),
)?
};
debug_assert!(nread <= buffer.capacity());
if nread < buffer.capacity() {
unsafe {
buffer.set_len(nread);
}
unsafe {
return Ok(CString::from_vec_unchecked(buffer));
}
}
buffer.reserve(buffer.capacity() + 1);
}
}
#[inline]
pub fn readlinkat_raw<P: path::Arg, Fd: AsFd, Buf: Buffer<u8>>(
dirfd: Fd,
path: P,
mut buf: Buf,
) -> io::Result<Buf::Output> {
let len = path.into_with_c_str(|path| unsafe {
backend::fs::syscalls::readlinkat(dirfd.as_fd(), path, buf.parts_mut())
})?;
unsafe { Ok(buf.assume_init(len)) }
}
#[inline]
pub fn mkdirat<P: path::Arg, Fd: AsFd>(dirfd: Fd, path: P, mode: Mode) -> io::Result<()> {
path.into_with_c_str(|path| backend::fs::syscalls::mkdirat(dirfd.as_fd(), path, mode))
}
#[cfg(not(target_os = "espidf"))]
#[inline]
pub fn linkat<P: path::Arg, Q: path::Arg, PFd: AsFd, QFd: AsFd>(
old_dirfd: PFd,
old_path: P,
new_dirfd: QFd,
new_path: Q,
flags: AtFlags,
) -> io::Result<()> {
old_path.into_with_c_str(|old_path| {
new_path.into_with_c_str(|new_path| {
backend::fs::syscalls::linkat(
old_dirfd.as_fd(),
old_path,
new_dirfd.as_fd(),
new_path,
flags,
)
})
})
}
#[cfg(not(target_os = "espidf"))]
#[inline]
pub fn unlinkat<P: path::Arg, Fd: AsFd>(dirfd: Fd, path: P, flags: AtFlags) -> io::Result<()> {
path.into_with_c_str(|path| backend::fs::syscalls::unlinkat(dirfd.as_fd(), path, flags))
}
#[inline]
pub fn renameat<P: path::Arg, Q: path::Arg, PFd: AsFd, QFd: AsFd>(
old_dirfd: PFd,
old_path: P,
new_dirfd: QFd,
new_path: Q,
) -> io::Result<()> {
old_path.into_with_c_str(|old_path| {
new_path.into_with_c_str(|new_path| {
backend::fs::syscalls::renameat(
old_dirfd.as_fd(),
old_path,
new_dirfd.as_fd(),
new_path,
)
})
})
}
#[cfg(any(apple, linux_kernel))]
#[inline]
#[doc(alias = "renameat2")]
#[doc(alias = "renameatx_np")]
pub fn renameat_with<P: path::Arg, Q: path::Arg, PFd: AsFd, QFd: AsFd>(
old_dirfd: PFd,
old_path: P,
new_dirfd: QFd,
new_path: Q,
flags: RenameFlags,
) -> io::Result<()> {
old_path.into_with_c_str(|old_path| {
new_path.into_with_c_str(|new_path| {
backend::fs::syscalls::renameat2(
old_dirfd.as_fd(),
old_path,
new_dirfd.as_fd(),
new_path,
flags,
)
})
})
}
#[inline]
pub fn symlinkat<P: path::Arg, Q: path::Arg, Fd: AsFd>(
old_path: P,
new_dirfd: Fd,
new_path: Q,
) -> io::Result<()> {
old_path.into_with_c_str(|old_path| {
new_path.into_with_c_str(|new_path| {
backend::fs::syscalls::symlinkat(old_path, new_dirfd.as_fd(), new_path)
})
})
}
#[cfg(not(target_os = "espidf"))]
#[inline]
#[doc(alias = "fstatat")]
pub fn statat<P: path::Arg, Fd: AsFd>(dirfd: Fd, path: P, flags: AtFlags) -> io::Result<Stat> {
path.into_with_c_str(|path| backend::fs::syscalls::statat(dirfd.as_fd(), path, flags))
}
#[cfg(not(any(target_os = "espidf", target_os = "horizon", target_os = "vita")))]
#[inline]
#[doc(alias = "faccessat")]
pub fn accessat<P: path::Arg, Fd: AsFd>(
dirfd: Fd,
path: P,
access: Access,
flags: AtFlags,
) -> io::Result<()> {
path.into_with_c_str(|path| backend::fs::syscalls::accessat(dirfd.as_fd(), path, access, flags))
}
#[cfg(not(any(target_os = "espidf", target_os = "horizon", target_os = "vita")))]
#[inline]
pub fn utimensat<P: path::Arg, Fd: AsFd>(
dirfd: Fd,
path: P,
times: &Timestamps,
flags: AtFlags,
) -> io::Result<()> {
path.into_with_c_str(|path| backend::fs::syscalls::utimensat(dirfd.as_fd(), path, times, flags))
}
#[cfg(not(any(target_os = "espidf", target_os = "wasi")))]
#[inline]
#[doc(alias = "fchmodat")]
pub fn chmodat<P: path::Arg, Fd: AsFd>(
dirfd: Fd,
path: P,
mode: Mode,
flags: AtFlags,
) -> io::Result<()> {
path.into_with_c_str(|path| backend::fs::syscalls::chmodat(dirfd.as_fd(), path, mode, flags))
}
#[cfg(apple)]
#[inline]
pub fn fclonefileat<Fd: AsFd, DstFd: AsFd, P: path::Arg>(
src: Fd,
dst_dir: DstFd,
dst: P,
flags: CloneFlags,
) -> io::Result<()> {
dst.into_with_c_str(|dst| {
backend::fs::syscalls::fclonefileat(src.as_fd(), dst_dir.as_fd(), dst, flags)
})
}
#[cfg(not(any(
apple,
target_os = "espidf",
target_os = "horizon",
target_os = "vita",
target_os = "wasi"
)))]
#[inline]
pub fn mknodat<P: path::Arg, Fd: AsFd>(
dirfd: Fd,
path: P,
file_type: FileType,
mode: Mode,
dev: Dev,
) -> io::Result<()> {
path.into_with_c_str(|path| {
backend::fs::syscalls::mknodat(dirfd.as_fd(), path, file_type, mode, dev)
})
}
#[cfg(not(any(target_os = "espidf", target_os = "wasi")))]
#[inline]
#[doc(alias = "fchownat")]
pub fn chownat<P: path::Arg, Fd: AsFd>(
dirfd: Fd,
path: P,
owner: Option<Uid>,
group: Option<Gid>,
flags: AtFlags,
) -> io::Result<()> {
path.into_with_c_str(|path| {
backend::fs::syscalls::chownat(dirfd.as_fd(), path, owner, group, flags)
})
}