203 lines
5.3 KiB
Rust

use core::ffi::{c_char, c_int, c_short, VaList};
use yggdrasil_rt::io::{FileMode, OpenOptions};
use crate::{
error::{CFdResult, CIntCountResult, EResult, TryFromExt},
io::{raw::RawFile, IntoRawFd},
util::{self, PointerStrExt},
};
use super::{
errno::Errno,
sys_types::{mode_t, off_t, pid_t},
};
#[repr(C)]
pub struct flock {
pub l_type: c_short,
pub l_whence: c_short,
pub l_start: off_t,
pub l_len: off_t,
pub l_pid: pid_t,
}
pub const F_DUPFD: c_int = 1;
pub const F_DUPFD_CLOEXEC: c_int = 2;
pub const F_GETFD: c_int = 3;
pub const F_SETFD: c_int = 4;
pub const F_GETFL: c_int = 5;
pub const F_SETFL: c_int = 6;
pub const F_GETLK: c_int = 7;
pub const F_SETLK: c_int = 8;
pub const F_SETLKW: c_int = 9;
pub const F_GETOWN: c_int = 10;
pub const F_SETOWN: c_int = 11;
pub const FD_CLOEXEC: c_int = 1 << 0;
pub const F_RDLCK: c_int = 1;
pub const F_UNLCK: c_int = 2;
pub const F_WRLCK: c_int = 3;
pub const O_CLOEXEC: c_int = 1 << 16;
pub const O_CREAT: c_int = 1 << 17;
pub const O_DIRECTORY: c_int = 1 << 18;
pub const O_EXCL: c_int = 1 << 19;
pub const O_NOCTTY: c_int = 1 << 20;
pub const O_NOFOLLOW: c_int = 1 << 21;
pub const O_TRUNC: c_int = 1 << 22;
pub const O_TTY_INIT: c_int = 1 << 23;
pub const O_APPEND: c_int = 1 << 24;
pub const O_DSYNC: c_int = 1 << 25;
pub const O_NONBLOCK: c_int = 1 << 26;
pub const O_RSYNC: c_int = 1 << 27;
pub const O_SYNC: c_int = 1 << 28;
pub const O_ACCMODE: c_int = 0xFF;
pub const O_RDONLY: c_int = 1;
pub const O_WRONLY: c_int = 2;
pub const O_RDWR: c_int = 3;
pub const O_EXEC: c_int = 4;
pub const O_SEARCH: c_int = 5;
pub const AT_FDCWD: c_int = -65536;
pub const AT_EACCESS: c_int = 1 << 0;
pub const AT_SYMLINK_NOFOLLOW: c_int = 1 << 1;
pub const AT_REMOVEDIR: c_int = 1 << 2;
pub const POSIX_FADV_DONTNEED: c_int = 1;
pub const POSIX_FADV_NOREUSE: c_int = 2;
pub const POSIX_FADV_NORMAL: c_int = 3;
pub const POSIX_FADV_RANDOM: c_int = 4;
pub const POSIX_FADV_SEQUENTIAL: c_int = 5;
pub const POSIX_FADV_WILLNEED: c_int = 6;
enum OpenMode {
File(OpenOptions, FileMode),
Directory,
}
fn open_opts(opts: c_int, ap: &mut VaList) -> EResult<OpenMode> {
if opts & O_DIRECTORY != 0 {
if opts & !(O_DIRECTORY | O_SEARCH) != 0 {
todo!("***open(O_DIRECTORY | {:#x})", opts & !O_DIRECTORY);
}
return EResult::Ok(OpenMode::Directory);
}
let need_mode = opts & O_CREAT != 0;
let mut res = OpenOptions::empty();
match opts & O_ACCMODE {
O_RDONLY => res |= OpenOptions::READ,
O_WRONLY => res |= OpenOptions::WRITE,
O_RDWR => res |= OpenOptions::READ | OpenOptions::WRITE,
O_EXEC => todo!(),
O_SEARCH => todo!(),
_ => {
return EResult::Err(Errno::EINVAL);
}
}
if opts & O_CREAT != 0 {
res |= OpenOptions::CREATE;
}
if opts & O_EXCL != 0 {
res |= OpenOptions::CREATE_EXCL;
}
if opts & O_APPEND != 0 {
res |= OpenOptions::APPEND;
}
if opts & O_TRUNC != 0 {
res |= OpenOptions::TRUNCATE;
}
if opts & O_NONBLOCK != 0 {
// TODO O_NONBLOCK
}
if opts & O_NOCTTY != 0 {
// TODO O_NOCTTY
}
// TODO O_CLOEXEC
if opts & (O_DSYNC | O_RSYNC | O_SYNC | O_TTY_INIT | O_NOFOLLOW) != 0 {
todo!("Unhandled options: {:#x}", opts);
}
let mode = if need_mode {
let raw = unsafe { ap.arg::<c_int>() };
unsafe { FileMode::from_raw(raw as _) }
} else {
FileMode::empty()
};
EResult::Ok(OpenMode::File(res, mode))
}
#[no_mangle]
unsafe extern "C" fn fcntl(fd: c_int, cmd: c_int, _args: ...) -> CIntCountResult {
// TODO kernel support for fcntl
let _file = RawFile::e_try_from(fd)?;
match cmd {
F_GETFD => CIntCountResult::success(0),
// The only defined option is FD_CLOEXEC, which is not supported
F_SETFD => CIntCountResult::success(0),
_ => {
todo!("fcntl({}, {}, ...)", fd, cmd);
}
}
}
unsafe fn vopenat(atfd: c_int, pathname: *const c_char, opts: c_int, mut ap: VaList) -> CFdResult {
let atfd = util::at_fd(atfd)?;
let pathname = pathname.ensure_str();
let fd = match open_opts(opts, &mut ap)? {
OpenMode::File(opts, mode) => RawFile::open_at(atfd, pathname, opts, mode)?.into_raw_fd(),
OpenMode::Directory => RawFile::open_directory_at(atfd, pathname)?.into_raw_fd(),
};
CFdResult::success(fd)
}
#[no_mangle]
unsafe extern "C" fn creat(pathname: *const c_char, mode: mode_t) -> CFdResult {
openat(AT_FDCWD, pathname, O_CREAT | O_WRONLY | O_TRUNC, mode)
}
#[no_mangle]
unsafe extern "C" fn open(pathname: *const c_char, opts: c_int, mut args: ...) -> CFdResult {
vopenat(AT_FDCWD, pathname, opts, args.as_va_list())
}
#[no_mangle]
unsafe extern "C" fn openat(
atfd: c_int,
pathname: *const c_char,
opts: c_int,
mut args: ...
) -> CFdResult {
vopenat(atfd, pathname, opts, args.as_va_list())
}
#[no_mangle]
unsafe extern "C" fn posix_fadvise(
_fd: c_int,
_offset: off_t,
_len: off_t,
_advice: c_int,
) -> c_int {
log::warn!("posix_fadvise() not implemented yet");
0
}
#[no_mangle]
unsafe extern "C" fn posix_fallocate(_fd: c_int, _offset: off_t, _size: off_t) -> c_int {
// Can be a truncate() call with some extra arg for future compat
todo!("posix_fallocate()")
}