#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct PathFileDescriptor
{
raw_fd: RawFd,
is_directory: bool,
}
impl Drop for PathFileDescriptor
{
#[inline(always)]
fn drop(&mut self)
{
self.raw_fd.close()
}
}
impl AsRawFd for PathFileDescriptor
{
#[inline(always)]
fn as_raw_fd(&self) -> RawFd
{
self.raw_fd
}
}
impl IntoRawFd for PathFileDescriptor
{
#[inline(always)]
fn into_raw_fd(self) -> RawFd
{
self.raw_fd
}
}
impl FromRawFd for PathFileDescriptor
{
#[inline(always)]
unsafe fn from_raw_fd(fd: RawFd) -> Self
{
let o_flags = Self::get_o_flags_raw_fd(fd);
debug_assert_ne!(o_flags & O_PATH, 0, "Not a path");
Self
{
raw_fd: fd,
is_directory: o_flags & O_DIRECTORY != 0,
}
}
}
impl FileDescriptor for PathFileDescriptor
{
}
impl OnDiskFileDescriptor for PathFileDescriptor
{
}
impl PathFileDescriptor
{
#[inline(always)]
pub fn open(path: &CStr, is_directory: bool, no_follow: bool) -> io::Result<Self>
{
let flags = O_PATH | O_CLOEXEC | if is_directory
{
O_DIRECTORY
}
else
{
0
}
| if no_follow
{
O_NOFOLLOW
}
else
{
0
};
let result = unsafe { open(path.as_ptr(), flags) };
if likely!(result >= 0)
{
Ok
(
Self
{
raw_fd: result,
is_directory,
}
)
}
else if likely!(result == -1)
{
Err(io::Error::last_os_error())
}
else
{
unreachable_code(format_args!("open() returned unexpected result {}", result))
}
}
#[inline(always)]
pub fn metadata_of_self(&self) -> io::Result<Metadata>
{
self.use_as_directory(|directory| directory.metadata_of_self())
}
#[inline(always)]
pub fn extended_metadata_of_self(&self, force_synchronization: Option<bool>, extended_metadata_wanted: ExtendedMetadataWanted) -> io::Result<ExtendedMetadata>
{
self.use_as_directory(|directory| directory.extended_metadata_of_self(force_synchronization, extended_metadata_wanted))
}
#[inline(always)]
pub fn change_current_working_directory_to_self(&self) -> io::Result<()>
{
debug_assert!(self.is_directory, "is not a directory");
self.use_as_directory(|directory| directory.change_current_working_directory_to_self())
}
#[inline(always)]
pub fn change_ownership_of_self(&self, owner: Option<UserIdentifier>, group: Option<GroupIdentifier>) -> io::Result<()>
{
self.use_as_directory(|directory| directory.change_ownership_of_self(owner, group, false))
}
#[inline(always)]
pub fn name_to_handle_for_self(&self) -> io::Result<LinuxFileHandle>
{
self.use_as_directory(|directory| directory.name_to_handle_for_self())
}
#[inline(always)]
pub fn make_hard_link_for_self(&self, to: &DirectoryFileDescriptor, to_path: &CStr) -> io::Result<()>
{
debug_assert!(!self.is_directory, "is a directory");
self.use_as_directory(|directory| directory.make_hard_link_for_self(to, to_path))
}
#[inline(always)]
pub fn execve(&self, arguments: &NulTerminatedCStringArray, environment: &Environment) -> io::Result<!>
{
debug_assert!(!self.is_directory, "is a directory");
self.use_as_directory(|directory| directory.execve_for_self(false, arguments, environment))
}
#[inline(always)]
fn use_as_directory<R>(&self, callback: impl FnOnce(&DirectoryFileDescriptor) -> R) -> R
{
let directory = DirectoryFileDescriptor(self.raw_fd);
let result = callback(&directory);
forget(directory);
result
}
}