180 lines
4.5 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,
sys_types::{mode_t, off_t, pid_t},
};
// TODO:
// POSIX_FADV_DONTNEED
// POSIX_FADV_NOREUSE
// POSIX_FADV_NORMAL
// POSIX_FADV_RANDOM
// POSIX_FADV_SEQUENTIAL
// POSIX_FADV_WILLNEED
// int posix_fadvise(int, off_t, off_t, int);
// int posix_fallocate(int, off_t, off_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;
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 != 0 {
todo!();
}
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_DSYNC | O_RSYNC | O_SYNC | O_TTY_INIT | O_NONBLOCK | O_NOFOLLOW | O_CLOEXEC | O_NOCTTY)
!= 0
{
todo!();
}
let mode = if need_mode {
let _raw = unsafe { ap.arg::<c_int>() };
todo!();
} 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 {
_ => 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 => todo!(),
};
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 {
yggdrasil_rt::debug_trace!("&errno = {:p}", &crate::error::errno);
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())
}