use crate::{
capi::{
ret::IntoCReturn,
utils::{self, CBorrowedFd},
},
error::{Error, ErrorImpl},
flags::{OpenFlags, RenameFlags},
procfs::ProcfsHandle,
utils::FdExt,
InodeType, Root, RootRef,
};
use std::{
fs::Permissions,
os::unix::{
fs::PermissionsExt,
io::{AsRawFd, RawFd},
},
};
use libc::{c_char, c_int, c_uint, dev_t, size_t};
#[no_mangle]
pub unsafe extern "C" fn pathrs_open_root(path: *const c_char) -> RawFd {
unsafe { utils::parse_path(path) } .and_then(Root::open)
.into_c_return()
}
utils::symver! {
fn pathrs_open_root <- (pathrs_open_root, version = "LIBPATHRS_0.2", default);
fn pathrs_open_root <- (pathrs_root_open, version = "LIBPATHRS_0.1", default);
}
#[no_mangle]
pub extern "C" fn pathrs_reopen(fd: CBorrowedFd<'_>, flags: u64) -> RawFd {
let flags = OpenFlags::from_bits_retain(flags);
|| -> Result<_, Error> {
fd.try_as_borrowed_fd()?
.reopen(&ProcfsHandle::new()?, flags)
}()
.into_c_return()
}
utils::symver! {
fn pathrs_reopen <- (pathrs_reopen, version = "LIBPATHRS_0.2.5", default);
}
#[doc(hidden)]
#[no_mangle]
pub extern "C" fn __pathrs_reopen_v1(fd: CBorrowedFd<'_>, flags: libc::c_int) -> RawFd {
pathrs_reopen(fd, flags as u32 as u64)
}
utils::symver! {
fn __pathrs_reopen_v1 <- (pathrs_reopen, version = "LIBPATHRS_0.1");
}
#[no_mangle]
pub unsafe extern "C" fn pathrs_inroot_resolve(
root_fd: CBorrowedFd<'_>,
path: *const c_char,
) -> RawFd {
|| -> Result<_, Error> {
let root_fd = root_fd.try_as_borrowed_fd()?;
let root = RootRef::from_fd(root_fd);
let path = unsafe { utils::parse_path(path) }?; root.resolve(path)
}()
.into_c_return()
}
utils::symver! {
fn pathrs_inroot_resolve <- (pathrs_inroot_resolve, version = "LIBPATHRS_0.2", default);
fn pathrs_inroot_resolve <- (pathrs_resolve, version = "LIBPATHRS_0.1", default);
}
#[no_mangle]
pub unsafe extern "C" fn pathrs_inroot_resolve_nofollow(
root_fd: CBorrowedFd<'_>,
path: *const c_char,
) -> RawFd {
|| -> Result<_, Error> {
let root_fd = root_fd.try_as_borrowed_fd()?;
let root = RootRef::from_fd(root_fd);
let path = unsafe { utils::parse_path(path) }?; root.resolve_nofollow(path)
}()
.into_c_return()
}
utils::symver! {
fn pathrs_inroot_resolve_nofollow <- (pathrs_inroot_resolve_nofollow, version = "LIBPATHRS_0.2", default);
fn pathrs_inroot_resolve_nofollow <- (pathrs_resolve_nofollow, version = "LIBPATHRS_0.1", default);
}
#[no_mangle]
pub unsafe extern "C" fn pathrs_inroot_open(
root_fd: CBorrowedFd<'_>,
path: *const c_char,
flags: u64,
) -> RawFd {
|| -> Result<_, Error> {
let root_fd = root_fd.try_as_borrowed_fd()?;
let root = RootRef::from_fd(root_fd);
let path = unsafe { utils::parse_path(path) }?; let flags = OpenFlags::from_bits_retain(flags);
root.open_subpath(path, flags)
}()
.into_c_return()
}
utils::symver! {
fn pathrs_inroot_open <- (pathrs_inroot_open, version = "LIBPATHRS_0.2.5", default);
}
#[doc(hidden)]
#[no_mangle]
pub unsafe extern "C" fn __pathrs_inroot_open_v1(
fd: CBorrowedFd<'_>,
path: *const c_char,
flags: libc::c_int,
) -> RawFd {
unsafe { pathrs_inroot_open(fd, path, flags as u32 as u64) }
}
utils::symver! {
fn __pathrs_inroot_open_v1 <- (pathrs_inroot_open, version = "LIBPATHRS_0.2");
}
#[no_mangle]
pub unsafe extern "C" fn pathrs_inroot_readlink(
root_fd: CBorrowedFd<'_>,
path: *const c_char,
linkbuf: *mut c_char,
linkbuf_size: size_t,
) -> RawFd {
|| -> Result<_, Error> {
let root_fd = root_fd.try_as_borrowed_fd()?;
let root = RootRef::from_fd(root_fd);
let path = unsafe { utils::parse_path(path) }?; let link_target = root.readlink(path)?;
unsafe { utils::copy_path_into_buffer(link_target, linkbuf, linkbuf_size) }
}()
.into_c_return()
}
utils::symver! {
fn pathrs_inroot_readlink <- (pathrs_inroot_readlink, version = "LIBPATHRS_0.2", default);
fn pathrs_inroot_readlink <- (pathrs_readlink, version = "LIBPATHRS_0.1", default);
}
#[no_mangle]
pub unsafe extern "C" fn pathrs_inroot_rename(
old_root_fd: CBorrowedFd<'_>,
old_path: *const c_char,
new_root_fd: CBorrowedFd<'_>,
new_path: *const c_char,
flags: u64,
) -> c_int {
let rflags = RenameFlags::from_bits_retain(flags);
|| -> Result<_, Error> {
let old_root_fd = old_root_fd.try_as_borrowed_fd()?;
let new_root_fd = new_root_fd.try_as_borrowed_fd()?;
if old_root_fd.as_raw_fd() != new_root_fd.as_raw_fd() {
Err(ErrorImpl::InvalidArgument {
name: "new_root_fd".into(),
description: "new_root_fd and old_root_fd must have the same fd value".into(),
})?;
}
let root = RootRef::from_fd(new_root_fd);
let old_path = unsafe { utils::parse_path(old_path) }?; let new_path = unsafe { utils::parse_path(new_path) }?;
root.rename(old_path, new_path, rflags)
}()
.into_c_return()
}
utils::symver! {
fn pathrs_inroot_rename <- (pathrs_inroot_rename, version = "LIBPATHRS_0.2.5", default);
}
#[doc(hidden)]
#[no_mangle]
pub unsafe extern "C" fn __pathrs_inroot_rename_v1(
root_fd: CBorrowedFd<'_>,
src: *const c_char,
dst: *const c_char,
flags: u32,
) -> c_int {
pathrs_inroot_rename(root_fd, src, root_fd, dst, flags.into())
}
utils::symver! {
fn __pathrs_inroot_rename_v1 <- (pathrs_inroot_rename, version = "LIBPATHRS_0.2");
fn __pathrs_inroot_rename_v1 <- (pathrs_rename, version = "LIBPATHRS_0.1", default);
}
#[no_mangle]
pub unsafe extern "C" fn pathrs_inroot_rmdir(
root_fd: CBorrowedFd<'_>,
path: *const c_char,
) -> c_int {
|| -> Result<_, Error> {
let root_fd = root_fd.try_as_borrowed_fd()?;
let root = RootRef::from_fd(root_fd);
let path = unsafe { utils::parse_path(path) }?; root.remove_dir(path)
}()
.into_c_return()
}
utils::symver! {
fn pathrs_inroot_rmdir <- (pathrs_inroot_rmdir, version = "LIBPATHRS_0.2", default);
fn pathrs_inroot_rmdir <- (pathrs_rmdir, version = "LIBPATHRS_0.1", default);
}
#[no_mangle]
pub unsafe extern "C" fn pathrs_inroot_unlink(
root_fd: CBorrowedFd<'_>,
path: *const c_char,
) -> c_int {
|| -> Result<_, Error> {
let root_fd = root_fd.try_as_borrowed_fd()?;
let root = RootRef::from_fd(root_fd);
let path = unsafe { utils::parse_path(path) }?; root.remove_file(path)
}()
.into_c_return()
}
utils::symver! {
fn pathrs_inroot_unlink <- (pathrs_inroot_unlink, version = "LIBPATHRS_0.2", default);
fn pathrs_inroot_unlink <- (pathrs_unlink, version = "LIBPATHRS_0.1", default);
}
#[no_mangle]
pub unsafe extern "C" fn pathrs_inroot_remove_all(
root_fd: CBorrowedFd<'_>,
path: *const c_char,
) -> c_int {
|| -> Result<_, Error> {
let root_fd = root_fd.try_as_borrowed_fd()?;
let root = RootRef::from_fd(root_fd);
let path = unsafe { utils::parse_path(path) }?; root.remove_all(path)
}()
.into_c_return()
}
utils::symver! {
fn pathrs_inroot_remove_all <- (pathrs_inroot_remove_all, version = "LIBPATHRS_0.2", default);
fn pathrs_inroot_remove_all <- (pathrs_remove_all, version = "LIBPATHRS_0.1", default);
}
#[no_mangle]
pub unsafe extern "C" fn pathrs_inroot_creat(
root_fd: CBorrowedFd<'_>,
path: *const c_char,
flags: u64,
mode: c_uint,
) -> RawFd {
|| -> Result<_, Error> {
let root_fd = root_fd.try_as_borrowed_fd()?;
let root = RootRef::from_fd(root_fd);
let path = unsafe { utils::parse_path(path) }?; let mode = mode & !libc::S_IFMT;
let perm = Permissions::from_mode(mode);
root.create_file(path, OpenFlags::from_bits_retain(flags), &perm)
}()
.into_c_return()
}
utils::symver! {
fn pathrs_inroot_creat <- (pathrs_inroot_creat, version = "LIBPATHRS_0.2.5", default);
}
#[doc(hidden)]
#[no_mangle]
pub unsafe extern "C" fn __pathrs_inroot_creat_v1(
fd: CBorrowedFd<'_>,
path: *const c_char,
flags: libc::c_int,
mode: c_uint,
) -> RawFd {
unsafe { pathrs_inroot_creat(fd, path, flags as u32 as u64, mode) }
}
utils::symver! {
fn __pathrs_inroot_creat_v1 <- (pathrs_inroot_creat, version = "LIBPATHRS_0.2");
fn __pathrs_inroot_creat_v1 <- (pathrs_creat, version = "LIBPATHRS_0.1", default);
}
#[no_mangle]
pub unsafe extern "C" fn pathrs_inroot_mkdir(
root_fd: CBorrowedFd<'_>,
path: *const c_char,
mode: c_uint,
) -> c_int {
let mode = mode & !libc::S_IFMT;
pathrs_inroot_mknod(root_fd, path, libc::S_IFDIR | mode, 0)
}
utils::symver! {
fn pathrs_inroot_mkdir <- (pathrs_inroot_mkdir, version = "LIBPATHRS_0.2", default);
fn pathrs_inroot_mkdir <- (pathrs_mkdir, version = "LIBPATHRS_0.1", default);
}
#[no_mangle]
pub unsafe extern "C" fn pathrs_inroot_mkdir_all(
root_fd: CBorrowedFd<'_>,
path: *const c_char,
mode: c_uint,
) -> RawFd {
|| -> Result<_, Error> {
let root_fd = root_fd.try_as_borrowed_fd()?;
let root = RootRef::from_fd(root_fd);
let path = unsafe { utils::parse_path(path) }?; let perm = Permissions::from_mode(mode);
root.mkdir_all(path, &perm)
}()
.into_c_return()
}
utils::symver! {
fn pathrs_inroot_mkdir_all <- (pathrs_inroot_mkdir_all, version = "LIBPATHRS_0.2", default);
fn pathrs_inroot_mkdir_all <- (pathrs_mkdir_all, version = "LIBPATHRS_0.1", default);
}
#[no_mangle]
pub unsafe extern "C" fn pathrs_inroot_mknod(
root_fd: CBorrowedFd<'_>,
path: *const c_char,
mode: c_uint,
dev: dev_t,
) -> c_int {
|| -> Result<_, Error> {
let root_fd = root_fd.try_as_borrowed_fd()?;
let root = RootRef::from_fd(root_fd);
let path = unsafe { utils::parse_path(path)? };
let fmt = mode & libc::S_IFMT;
let perms = Permissions::from_mode(mode ^ fmt);
let inode_type = match fmt {
libc::S_IFREG => InodeType::File(perms),
libc::S_IFDIR => InodeType::Directory(perms),
libc::S_IFBLK => InodeType::BlockDevice(perms, dev),
libc::S_IFCHR => InodeType::CharacterDevice(perms, dev),
libc::S_IFIFO => InodeType::Fifo(perms),
libc::S_IFSOCK => Err(ErrorImpl::NotImplemented {
feature: "mknod(S_IFSOCK)".into(),
})?,
_ => Err(ErrorImpl::InvalidArgument {
name: "mode".into(),
description: "invalid S_IFMT mask".into(),
})?,
};
root.create(path, &inode_type)
}()
.into_c_return()
}
utils::symver! {
fn pathrs_inroot_mknod <- (pathrs_inroot_mknod, version = "LIBPATHRS_0.2", default);
fn pathrs_inroot_mknod <- (pathrs_mknod, version = "LIBPATHRS_0.1", default);
}
#[no_mangle]
pub unsafe extern "C" fn pathrs_inroot_symlink(
target: *const c_char,
root_fd: CBorrowedFd<'_>,
linkpath: *const c_char,
) -> c_int {
|| -> Result<_, Error> {
let root_fd = root_fd.try_as_borrowed_fd()?;
let root = RootRef::from_fd(root_fd);
let target = unsafe { utils::parse_path(target)? }; let linkpath = unsafe { utils::parse_path(linkpath)? }; root.create(linkpath, &InodeType::Symlink(target.into()))
}()
.into_c_return()
}
utils::symver! {
fn pathrs_inroot_symlink <- (pathrs_inroot_symlink, version = "LIBPATHRS_0.2.5", default);
}
#[doc(hidden)]
#[no_mangle]
pub unsafe extern "C" fn __pathrs_inroot_symlink_v1(
root_fd: CBorrowedFd<'_>,
path: *const c_char,
target: *const c_char,
) -> c_int {
pathrs_inroot_symlink(target, root_fd, path)
}
utils::symver! {
fn __pathrs_inroot_symlink_v1 <- (pathrs_inroot_symlink, version = "LIBPATHRS_0.2");
fn __pathrs_inroot_symlink_v1 <- (pathrs_symlink, version = "LIBPATHRS_0.1", default);
}
#[no_mangle]
pub unsafe extern "C" fn pathrs_inroot_hardlink(
old_root_fd: CBorrowedFd<'_>,
old_path: *const c_char,
new_root_fd: CBorrowedFd<'_>,
new_path: *const c_char,
flags: u64,
) -> c_int {
|| -> Result<_, Error> {
if flags != 0 {
Err(ErrorImpl::InvalidArgument {
name: "flags".into(),
description: "flags are unsupported".into(),
})?;
}
let old_root_fd = old_root_fd.try_as_borrowed_fd()?;
let new_root_fd = new_root_fd.try_as_borrowed_fd()?;
if old_root_fd.as_raw_fd() != new_root_fd.as_raw_fd() {
Err(ErrorImpl::InvalidArgument {
name: "new_root_fd".into(),
description: "new_root_fd and old_root_fd must have the same fd value".into(),
})?;
}
let root = RootRef::from_fd(new_root_fd);
let old_path = unsafe { utils::parse_path(old_path) }?; let new_path = unsafe { utils::parse_path(new_path) }?; root.create(new_path, &InodeType::Hardlink(old_path.into()))
}()
.into_c_return()
}
utils::symver! {
fn pathrs_inroot_hardlink <- (pathrs_inroot_hardlink, version = "LIBPATHRS_0.2.5", default);
}
#[doc(hidden)]
#[no_mangle]
pub unsafe extern "C" fn __pathrs_inroot_hardlink_v1(
root_fd: CBorrowedFd<'_>,
path: *const c_char,
target: *const c_char,
) -> c_int {
pathrs_inroot_hardlink(root_fd, target, root_fd, path, 0)
}
utils::symver! {
fn __pathrs_inroot_hardlink_v1 <- (pathrs_inroot_hardlink, version = "LIBPATHRS_0.2");
fn __pathrs_inroot_hardlink_v1 <- (pathrs_hardlink, version = "LIBPATHRS_0.1", default);
}