multiple: most of <dirent.h>, <fcntl.h>, <sys/stat.h>
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
#ifndef _YGGDRASIL_DIRENT
|
||||
#define _YGGDRASIL_DIRENT 1
|
||||
|
||||
struct __DIR;
|
||||
|
||||
typedef struct __DIR DIR;
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,8 @@
|
||||
#ifndef _YGGDRASIL_FCNTL_H
|
||||
#define _YGGDRASIL_FCNTL_H 1
|
||||
|
||||
int fcntl(int fd, int cmd, ...);
|
||||
int open(const char *pathname, int opts, ...);
|
||||
int openat(int atfd, const char *pathname, int opts, ...);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,16 @@
|
||||
#ifndef _YGGDRASIL_SYS_STAT_H
|
||||
#define _YGGDRASIL_SYS_STAT_H 1
|
||||
|
||||
#define st_atime st_atim.tv_sec
|
||||
#define st_mtime st_mtim.tv_sec
|
||||
#define st_ctime st_ctim.tv_sec
|
||||
|
||||
#define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK)
|
||||
#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
|
||||
#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
|
||||
#define S_ISFIFO(m) (((m) & S_IFMT) == S_IFFIFO)
|
||||
#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
|
||||
#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
|
||||
#define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,6 @@
|
||||
#ifndef _YGGDRASIL_TIME_H
|
||||
#define _YGGDRASIL_TIME_H 1
|
||||
|
||||
typedef struct timespec __ygg_timespec_t;
|
||||
|
||||
#endif
|
||||
@@ -53,6 +53,12 @@ impl File {
|
||||
EResult::from(unsafe { syscall::close(self.fd) })?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn into_raw_fd(self) -> RawFd {
|
||||
let fd = self.fd;
|
||||
core::mem::forget(self);
|
||||
fd
|
||||
}
|
||||
}
|
||||
|
||||
impl Write for File {
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
language = "C"
|
||||
style = "Type"
|
||||
|
||||
sys_includes = [
|
||||
"locale.h"
|
||||
]
|
||||
no_includes = true
|
||||
|
||||
include_guard = "_CTYPE_H"
|
||||
|
||||
usize_type = "size_t"
|
||||
isize_type = "ssize_t"
|
||||
|
||||
[export]
|
||||
@@ -0,0 +1,142 @@
|
||||
use core::ffi::c_int;
|
||||
|
||||
use super::locale::locale_t;
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn isalnum(c: c_int) -> c_int {
|
||||
(c as u8).is_ascii_alphanumeric() as _
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn isalpha(c: c_int) -> c_int {
|
||||
(c as u8).is_ascii_alphabetic() as _
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn isascii(c: c_int) -> c_int {
|
||||
(c as u8).is_ascii() as _
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn isblank(c: c_int) -> c_int {
|
||||
(c as u8 == b' ' || c as u8 == b'\t') as _
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn iscntrl(c: c_int) -> c_int {
|
||||
(c as u8).is_ascii_control() as _
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn isdigit(c: c_int) -> c_int {
|
||||
(c as u8).is_ascii_digit() as _
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn isgraph(c: c_int) -> c_int {
|
||||
(c as u8).is_ascii_graphic() as _
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn islower(c: c_int) -> c_int {
|
||||
(c as u8).is_ascii_lowercase() as _
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn isprint(c: c_int) -> c_int {
|
||||
((c as u8).is_ascii_graphic() || (c as u8) == b' ') as _
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn ispunct(c: c_int) -> c_int {
|
||||
(c as u8).is_ascii_punctuation() as _
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn isspace(c: c_int) -> c_int {
|
||||
(c as u8).is_ascii_whitespace() as _
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn isupper(c: c_int) -> c_int {
|
||||
(c as u8).is_ascii_uppercase() as _
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn isxdigit(c: c_int) -> c_int {
|
||||
(c as u8).is_ascii_hexdigit() as _
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn toascii(c: c_int) -> c_int {
|
||||
((c as u8) & !0x80) as _
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn tolower(c: c_int) -> c_int {
|
||||
(c as u8).to_ascii_lowercase() as _
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn toupper(c: c_int) -> c_int {
|
||||
(c as u8).to_ascii_uppercase() as _
|
||||
}
|
||||
|
||||
// Locale
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn isalnum_l(c: c_int, locale: locale_t) -> c_int {
|
||||
todo!()
|
||||
}
|
||||
#[no_mangle]
|
||||
extern "C" fn isalpha_l(c: c_int, locale: locale_t) -> c_int {
|
||||
todo!()
|
||||
}
|
||||
#[no_mangle]
|
||||
extern "C" fn isblank_l(c: c_int, locale: locale_t) -> c_int {
|
||||
todo!()
|
||||
}
|
||||
#[no_mangle]
|
||||
extern "C" fn iscntrl_l(c: c_int, locale: locale_t) -> c_int {
|
||||
todo!()
|
||||
}
|
||||
#[no_mangle]
|
||||
extern "C" fn isdigit_l(c: c_int, locale: locale_t) -> c_int {
|
||||
todo!()
|
||||
}
|
||||
#[no_mangle]
|
||||
extern "C" fn isgraph_l(c: c_int, locale: locale_t) -> c_int {
|
||||
todo!()
|
||||
}
|
||||
#[no_mangle]
|
||||
extern "C" fn islower_l(c: c_int, locale: locale_t) -> c_int {
|
||||
todo!()
|
||||
}
|
||||
#[no_mangle]
|
||||
extern "C" fn isprint_l(c: c_int, locale: locale_t) -> c_int {
|
||||
todo!()
|
||||
}
|
||||
#[no_mangle]
|
||||
extern "C" fn ispunct_l(c: c_int, locale: locale_t) -> c_int {
|
||||
todo!()
|
||||
}
|
||||
#[no_mangle]
|
||||
extern "C" fn isspace_l(c: c_int, locale: locale_t) -> c_int {
|
||||
todo!()
|
||||
}
|
||||
#[no_mangle]
|
||||
extern "C" fn isupper_l(c: c_int, locale: locale_t) -> c_int {
|
||||
todo!()
|
||||
}
|
||||
#[no_mangle]
|
||||
extern "C" fn isxdigit_l(c: c_int, locale: locale_t) -> c_int {
|
||||
todo!()
|
||||
}
|
||||
#[no_mangle]
|
||||
extern "C" fn tolower_l(c: c_int, locale: locale_t) -> c_int {
|
||||
todo!()
|
||||
}
|
||||
#[no_mangle]
|
||||
extern "C" fn toupper_l(c: c_int, locale: locale_t) -> c_int {
|
||||
todo!()
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
language = "C"
|
||||
style = "Tag"
|
||||
|
||||
sys_includes = [
|
||||
"stddef.h",
|
||||
"stdint.h",
|
||||
"sys/types.h",
|
||||
"bits/dirent.h",
|
||||
"limits.h",
|
||||
]
|
||||
no_includes = true
|
||||
|
||||
include_guard = "_DIRENT_H"
|
||||
|
||||
usize_type = "size_t"
|
||||
isize_type = "ssize_t"
|
||||
|
||||
[export]
|
||||
include = ["dirent"]
|
||||
exclude = ["DIR"]
|
||||
@@ -0,0 +1,162 @@
|
||||
use core::{
|
||||
ffi::{c_char, c_int, c_long, CStr},
|
||||
mem::MaybeUninit,
|
||||
ptr::null_mut,
|
||||
};
|
||||
|
||||
use alloc::boxed::Box;
|
||||
use yggdrasil_rt::io::{DirectoryEntry, RawFd};
|
||||
|
||||
use crate::{error, io::dir::DirReader, util::Nullable};
|
||||
|
||||
use super::{errno::EBADF, limits::NAME_MAX, sys_types::ino_t};
|
||||
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
pub struct DIR {
|
||||
reader: DirReader,
|
||||
buffer: MaybeUninit<dirent>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||
#[repr(C)]
|
||||
pub struct dirent {
|
||||
pub d_ino: ino_t,
|
||||
pub d_name: [c_char; NAME_MAX],
|
||||
}
|
||||
|
||||
pub type __scandir_filter_fn_t = extern "C" fn(*const dirent) -> c_int;
|
||||
pub type __scandir_compar_fn_t = extern "C" fn(*mut *const dirent, *mut *const dirent) -> c_int;
|
||||
|
||||
impl From<DirectoryEntry> for dirent {
|
||||
fn from(value: DirectoryEntry) -> Self {
|
||||
let mut d_name = [0; NAME_MAX];
|
||||
let len = value.name.len();
|
||||
|
||||
if len + 1 >= NAME_MAX {
|
||||
todo!("Name too long");
|
||||
}
|
||||
|
||||
// SAFETY this is just to cast u8 to i8, so transmute should be safe
|
||||
d_name[..len].copy_from_slice(unsafe { core::mem::transmute(value.name.as_bytes()) });
|
||||
d_name[len] = 0;
|
||||
|
||||
Self {
|
||||
// TODO
|
||||
d_ino: 0,
|
||||
d_name,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Primary stuff
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn opendir(pathname: *const c_char) -> *mut DIR {
|
||||
pathname.ensure();
|
||||
|
||||
let pathname = CStr::from_ptr(pathname).to_str().unwrap();
|
||||
|
||||
match DirReader::open_at(None, pathname) {
|
||||
Ok(reader) => Box::into_raw(Box::new(DIR {
|
||||
reader,
|
||||
buffer: MaybeUninit::uninit(),
|
||||
})),
|
||||
Err(_) => null_mut(),
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn fdopendir(fd: c_int) -> *mut DIR {
|
||||
if fd < 0 {
|
||||
error::set_errno(EBADF);
|
||||
return null_mut();
|
||||
}
|
||||
|
||||
let reader = DirReader::from_raw_fd(RawFd(fd as _));
|
||||
|
||||
Box::into_raw(Box::new(DIR {
|
||||
reader,
|
||||
buffer: MaybeUninit::uninit(),
|
||||
}))
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn closedir(dir: *mut DIR) -> c_int {
|
||||
let result = {
|
||||
let dir = dir.as_mut().unwrap();
|
||||
|
||||
match dir.reader.close() {
|
||||
Ok(_) => 0,
|
||||
Err(_) => -1,
|
||||
}
|
||||
};
|
||||
|
||||
drop(Box::from_raw(dir));
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn dirfd(dir: *mut DIR) -> c_int {
|
||||
let dir = dir.as_mut().unwrap();
|
||||
|
||||
dir.reader.as_raw_fd().0 as _
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn readdir(dir: *mut DIR) -> *mut dirent {
|
||||
let dir = dir.as_mut().unwrap();
|
||||
|
||||
match dir.reader.read_entry() {
|
||||
Ok(Some(entry)) => {
|
||||
dir.buffer.write(dirent::from(entry));
|
||||
dir.buffer.as_mut_ptr()
|
||||
}
|
||||
Ok(None) | Err(_) => null_mut(),
|
||||
}
|
||||
}
|
||||
|
||||
// Deprecated
|
||||
// #[no_mangle]
|
||||
// unsafe extern "C" fn readdir_r(
|
||||
// dir: *mut DIR,
|
||||
// buffer: *mut dirent,
|
||||
// outptr: *mut *mut dirent,
|
||||
// ) -> c_int {
|
||||
// todo!()
|
||||
// }
|
||||
|
||||
// Seeking
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn seekdir(dir: *mut DIR, offset: c_long) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn rewinddir(dir: *mut DIR) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn telldir(dir: *mut DIR) -> c_long {
|
||||
todo!()
|
||||
}
|
||||
|
||||
// Directory scan and sorting
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn scandir(
|
||||
dirp: *const c_char,
|
||||
namelist: *mut *mut *mut dirent,
|
||||
filter: __scandir_filter_fn_t,
|
||||
compar: __scandir_compar_fn_t,
|
||||
) -> c_int {
|
||||
todo!()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn alphasort(a: *const *const dirent, b: *const *const dirent) -> c_int {
|
||||
todo!()
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
language = "C"
|
||||
style = "Tag"
|
||||
|
||||
sys_includes = [
|
||||
"stddef.h",
|
||||
"stdint.h",
|
||||
"sys/types.h",
|
||||
"sys/stat.h",
|
||||
"unistd.h",
|
||||
|
||||
"bits/fcntl.h"
|
||||
]
|
||||
no_includes = true
|
||||
|
||||
include_guard = "_FCNTL_H"
|
||||
|
||||
usize_type = "size_t"
|
||||
isize_type = "ssize_t"
|
||||
|
||||
[export]
|
||||
include = ["flock"]
|
||||
# Varargs are broken for these
|
||||
exclude = ["fcntl", "open", "openat"]
|
||||
@@ -0,0 +1,168 @@
|
||||
use core::ffi::{c_char, c_int, c_short, CStr, VaList};
|
||||
|
||||
use yggdrasil_rt::{
|
||||
io::{FileMode, OpenOptions, RawFd},
|
||||
path::Path,
|
||||
};
|
||||
|
||||
use crate::{error, file::File, header::errno::EINVAL, util::Nullable};
|
||||
|
||||
use super::{
|
||||
errno::Errno,
|
||||
sys_types::{mode_t, off_t, pid_t},
|
||||
};
|
||||
|
||||
/*
|
||||
TODO:
|
||||
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) -> Result<OpenMode, Errno> {
|
||||
if opts & O_DIRECTORY != 0 {
|
||||
if opts & !O_DIRECTORY != 0 {
|
||||
todo!();
|
||||
}
|
||||
|
||||
return 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 error::set_errno_result(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()
|
||||
};
|
||||
|
||||
Ok(OpenMode::File(res, mode))
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn creat(pathname: *const c_char, mode: mode_t) -> c_int {
|
||||
todo!()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn fcntl(fd: c_int, cmd: c_int, args: ...) -> c_int {
|
||||
todo!()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn open(pathname: *const c_char, opts: c_int, mut args: ...) -> c_int {
|
||||
pathname.ensure();
|
||||
let pathname = CStr::from_ptr(pathname).to_str().unwrap();
|
||||
let mut args = args.as_va_list();
|
||||
|
||||
let result = match open_opts(opts, &mut args) {
|
||||
Ok(OpenMode::File(opts, mode)) => {
|
||||
File::open_at(None, pathname, opts, mode).map(File::into_raw_fd)
|
||||
}
|
||||
Ok(OpenMode::Directory) => {
|
||||
todo!();
|
||||
}
|
||||
Err(_) => return -1,
|
||||
};
|
||||
|
||||
match result {
|
||||
Ok(fd) => fd.0.try_into().unwrap(),
|
||||
Err(_) => -1,
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn openat(atfd: c_int, pathname: *const c_char, opts: c_int, ...) -> c_int {
|
||||
todo!()
|
||||
}
|
||||
+10
-5
@@ -3,13 +3,18 @@
|
||||
pub mod sys_types;
|
||||
pub mod sys_wait;
|
||||
|
||||
pub mod ctype;
|
||||
pub mod dirent;
|
||||
pub mod errno;
|
||||
pub mod fcntl;
|
||||
pub mod limits;
|
||||
pub mod locale;
|
||||
pub mod math;
|
||||
pub mod stdio;
|
||||
pub mod stdlib;
|
||||
pub mod string;
|
||||
pub mod sys_stat;
|
||||
pub mod time;
|
||||
pub mod unistd;
|
||||
|
||||
/*
|
||||
@@ -19,11 +24,11 @@ OSSUP arpa/inet.h - definitions for internet operations
|
||||
+++++ assert.h - verify program assertion
|
||||
----- complex.h - complex arithmetic
|
||||
----- cpio.h - cpio archive values
|
||||
----- ctype.h - character types
|
||||
----- dirent.h - format of directory entries
|
||||
+++++ ctype.h - character types TODO locale
|
||||
MOSTLY dirent.h - format of directory entries
|
||||
OSSUP dlfcn.h - dynamic linking
|
||||
MOSTLY errno.h - system error numbers
|
||||
----- fcntl.h - file control options
|
||||
MOSTLY fcntl.h - file control options
|
||||
----- fenv.h - floating-point environment
|
||||
----- float.h - floating types
|
||||
----- fmtmsg.h - message display structures
|
||||
@@ -63,7 +68,7 @@ MAYBE spawn.h - spawn (ADVANCED REALTIME)
|
||||
+++++ stdint.h - integer types
|
||||
+++++ stdio.h - standard buffered input/output
|
||||
MOSTLY stdlib.h - standard library definitions
|
||||
+++++ +++++ string.h - string operations NOTE: no locale yet
|
||||
+++++ +++++ string.h - string operations TODO locale
|
||||
----- strings.h - string operations
|
||||
NEVER stropts.h - STREAMS interface (STREAMS)
|
||||
NEVER sys/ipc.h - XSI interprocess communication access structure
|
||||
@@ -75,7 +80,7 @@ MAYBE sys/select.h - select types NOTE: maybe through PollWait emulati
|
||||
MAYBE sys/sem.h - XSI semaphore facility
|
||||
MAYBE sys/shm.h - XSI shared memory facility
|
||||
OSSUP sys/socket.h - main sockets header
|
||||
----- sys/stat.h - data returned by the stat() function
|
||||
PARTIAL sys/stat.h - data returned by the stat() function
|
||||
----- sys/statvfs.h - VFS File System information structure
|
||||
----- sys/time.h - time types
|
||||
----- sys/times.h - file access and modification times structure
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
language = "C"
|
||||
style = "Tag"
|
||||
|
||||
sys_includes = [
|
||||
"stddef.h",
|
||||
"stdint.h",
|
||||
"sys/types.h",
|
||||
"time.h",
|
||||
"bits/sys/stat.h"
|
||||
]
|
||||
no_includes = true
|
||||
|
||||
include_guard = "_SYS_STAT_H"
|
||||
|
||||
usize_type = "size_t"
|
||||
isize_type = "ssize_t"
|
||||
|
||||
[export]
|
||||
include = ["stat"]
|
||||
@@ -0,0 +1,256 @@
|
||||
use core::{
|
||||
ffi::{c_char, c_int, CStr},
|
||||
mem::MaybeUninit,
|
||||
};
|
||||
|
||||
use yggdrasil_rt::{
|
||||
io::{FileAttr, FileMode, FileType, RawFd},
|
||||
path::Path,
|
||||
sys as syscall,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
error::{self, CZeroResult, EResult},
|
||||
io,
|
||||
util::Nullable,
|
||||
};
|
||||
|
||||
use super::{
|
||||
errno::{Errno, EBADF},
|
||||
fcntl::{AT_FDCWD, AT_SYMLINK_NOFOLLOW},
|
||||
sys_types::{blkcnt_t, blksize_t, dev_t, gid_t, ino_t, mode_t, nlink_t, off_t, uid_t},
|
||||
time::{__ygg_timespec_t, timespec},
|
||||
};
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, Default)]
|
||||
#[repr(C)]
|
||||
pub struct stat {
|
||||
pub st_dev: dev_t,
|
||||
pub st_ino: ino_t,
|
||||
pub st_mode: mode_t,
|
||||
pub st_nlink: nlink_t,
|
||||
pub st_uid: uid_t,
|
||||
pub st_gid: gid_t,
|
||||
pub st_rdev: dev_t,
|
||||
pub st_size: off_t,
|
||||
pub st_atim: __ygg_timespec_t,
|
||||
pub st_mtim: __ygg_timespec_t,
|
||||
pub st_ctim: __ygg_timespec_t,
|
||||
pub st_blksize: blksize_t,
|
||||
pub st_blocks: blkcnt_t,
|
||||
}
|
||||
|
||||
pub const S_IFMT: c_int = 0xF << 16;
|
||||
pub const S_IFBLK: c_int = 1 << 16;
|
||||
pub const S_IFCHR: c_int = 2 << 16;
|
||||
pub const S_IFIFO: c_int = 3 << 16;
|
||||
pub const S_IFREG: c_int = 4 << 16;
|
||||
pub const S_IFDIR: c_int = 5 << 16;
|
||||
pub const S_IFLNK: c_int = 6 << 16;
|
||||
pub const S_IFSOCK: c_int = 7 << 16;
|
||||
|
||||
pub const S_IRWXU: c_int = 0x7 << 6;
|
||||
pub const S_IRUSR: c_int = 0x4 << 6;
|
||||
pub const S_IWUSR: c_int = 0x2 << 6;
|
||||
pub const S_IXUSR: c_int = 0x1 << 6;
|
||||
|
||||
pub const S_IRWXG: c_int = 0x7 << 3;
|
||||
pub const S_IRGRP: c_int = 0x4 << 3;
|
||||
pub const S_IWGRP: c_int = 0x2 << 3;
|
||||
pub const S_IXGRP: c_int = 0x1 << 3;
|
||||
|
||||
pub const S_IRWXO: c_int = 0x7 << 0;
|
||||
pub const S_IROTH: c_int = 0x4 << 0;
|
||||
pub const S_IWOTH: c_int = 0x2 << 0;
|
||||
pub const S_IXOTH: c_int = 0x1 << 0;
|
||||
|
||||
pub const S_ISUID: c_int = 1 << 11;
|
||||
pub const S_ISGID: c_int = 1 << 10;
|
||||
pub const S_ISVTX: c_int = 1 << 9;
|
||||
|
||||
impl From<FileAttr> for stat {
|
||||
fn from(value: FileAttr) -> Self {
|
||||
// TODO no translation for st_dev/st_rdev/st_ino/etc
|
||||
let mut st = Self::default();
|
||||
st.st_mode = (value.mode.bits() & 0o777) as _;
|
||||
match value.ty {
|
||||
FileType::Block => st.st_mode |= S_IFBLK,
|
||||
FileType::Char => st.st_mode |= S_IFCHR,
|
||||
FileType::File => st.st_mode |= S_IFREG,
|
||||
FileType::Directory => st.st_mode |= S_IFDIR,
|
||||
FileType::Symlink => st.st_mode |= S_IFLNK,
|
||||
}
|
||||
st.st_size = value.size.try_into().unwrap();
|
||||
// TODO
|
||||
st.st_uid = 0;
|
||||
st.st_gid = 0;
|
||||
// TODO
|
||||
st.st_blksize = 512;
|
||||
st.st_blocks = (st.st_size + 511) / 512;
|
||||
// TODO
|
||||
st.st_nlink = 1;
|
||||
|
||||
st
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn chmod(pathname: *const c_char, mode: mode_t) -> c_int {
|
||||
todo!()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn fchmod(fd: c_int, mode: mode_t) -> c_int {
|
||||
todo!()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn fchmodat(
|
||||
fd: c_int,
|
||||
pathname: *const c_char,
|
||||
mode: mode_t,
|
||||
opt: c_int,
|
||||
) -> c_int {
|
||||
todo!()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn umask(mode: mode_t) -> mode_t {
|
||||
todo!()
|
||||
}
|
||||
|
||||
// Create stuff
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn mkdir(pathname: *const c_char, mode: mode_t) -> c_int {
|
||||
mkdirat(AT_FDCWD, pathname, mode)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn mkdirat(atfd: c_int, pathname: *const c_char, mode: mode_t) -> c_int {
|
||||
pathname.ensure();
|
||||
let pathname = CStr::from_ptr(pathname).to_str().unwrap();
|
||||
|
||||
// TODO move this to a function
|
||||
let atfd = match atfd {
|
||||
// Same as stat()
|
||||
AT_FDCWD => None,
|
||||
0.. => Some(RawFd(atfd as _)),
|
||||
_ => {
|
||||
error::set_errno(EBADF);
|
||||
return -1;
|
||||
}
|
||||
};
|
||||
|
||||
let mode = FileMode::new((mode & 0o777) as u32);
|
||||
|
||||
io::create_directory(atfd, pathname, mode).into_zero_status()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn mkfifo(pathname: *const c_char, mode: mode_t) -> c_int {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn mkfifoat(atfd: c_int, pathname: *const c_char, mode: mode_t) -> c_int {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn mknod(pathname: *const c_char, mode: mode_t, dev: dev_t) -> c_int {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn mknodat(
|
||||
atfd: c_int,
|
||||
pathname: *const c_char,
|
||||
mode: mode_t,
|
||||
dev: dev_t,
|
||||
) -> c_int {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
// File status
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn fstat(fd: c_int, statbuf: *mut stat) -> c_int {
|
||||
if fd < 0 {
|
||||
error::set_errno(EBADF);
|
||||
return -1;
|
||||
}
|
||||
|
||||
let attr = match io::get_metadata(Some(RawFd(fd as _)), "", false) {
|
||||
Ok(attr) => attr,
|
||||
Err(_) => return -1,
|
||||
};
|
||||
|
||||
if let Some(statbuf) = statbuf.as_mut() {
|
||||
*statbuf = attr.into();
|
||||
}
|
||||
|
||||
0
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn fstatat(
|
||||
atfd: c_int,
|
||||
pathname: *const c_char,
|
||||
statbuf: *mut stat,
|
||||
opt: c_int,
|
||||
) -> c_int {
|
||||
pathname.ensure();
|
||||
let pathname = CStr::from_ptr(pathname).to_str().unwrap();
|
||||
|
||||
// TODO move this to a function
|
||||
let atfd = match atfd {
|
||||
// Same as stat()
|
||||
AT_FDCWD => None,
|
||||
0.. => Some(RawFd(atfd as _)),
|
||||
_ => {
|
||||
error::set_errno(EBADF);
|
||||
return -1;
|
||||
}
|
||||
};
|
||||
|
||||
let follow = opt & AT_SYMLINK_NOFOLLOW == 0;
|
||||
|
||||
let attr = match io::get_metadata(atfd, pathname, follow) {
|
||||
Ok(attr) => attr,
|
||||
Err(_) => return -1,
|
||||
};
|
||||
|
||||
if let Some(statbuf) = statbuf.as_mut() {
|
||||
*statbuf = attr.into();
|
||||
}
|
||||
|
||||
0
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn lstat(pathname: *const c_char, statbuf: *mut stat) -> c_int {
|
||||
fstatat(AT_FDCWD, pathname, statbuf, AT_SYMLINK_NOFOLLOW)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn stat(pathname: *const c_char, statbuf: *mut stat) -> c_int {
|
||||
fstatat(AT_FDCWD, pathname, statbuf, 0)
|
||||
}
|
||||
|
||||
// File time updates
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn futimens(fd: c_int, times: *const __ygg_timespec_t) -> c_int {
|
||||
todo!()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn utimensat(
|
||||
atfd: c_int,
|
||||
pathname: *const c_char,
|
||||
times: *const __ygg_timespec_t,
|
||||
opt: c_int,
|
||||
) -> c_int {
|
||||
todo!()
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
use core::ffi::c_ulong;
|
||||
use core::ffi::{c_int, c_ulong};
|
||||
|
||||
pub type pid_t = i32;
|
||||
pub type uid_t = i32;
|
||||
@@ -10,7 +10,7 @@ pub type dev_t = u32;
|
||||
pub type clockid_t = i32;
|
||||
pub type timer_t = i32;
|
||||
|
||||
pub type mode_t = u32;
|
||||
pub type mode_t = c_int;
|
||||
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
pub type ssize_t = i64;
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
language = "C"
|
||||
style = "Tag"
|
||||
|
||||
sys_includes = [
|
||||
"stddef.h",
|
||||
"stdint.h",
|
||||
"sys/types.h",
|
||||
"bits/time.h"
|
||||
]
|
||||
no_includes = true
|
||||
|
||||
include_guard = "_TIME_H"
|
||||
|
||||
usize_type = "size_t"
|
||||
isize_type = "ssize_t"
|
||||
|
||||
[export]
|
||||
include = ["timespec"]
|
||||
@@ -0,0 +1,12 @@
|
||||
use core::ffi::c_long;
|
||||
|
||||
use super::sys_types::time_t;
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, Default)]
|
||||
#[repr(C)]
|
||||
pub struct timespec {
|
||||
pub tv_sec: time_t,
|
||||
pub tv_nsec: c_long,
|
||||
}
|
||||
|
||||
pub type __ygg_timespec_t = timespec;
|
||||
@@ -0,0 +1,96 @@
|
||||
use core::mem::MaybeUninit;
|
||||
|
||||
use alloc::{boxed::Box, vec::Vec};
|
||||
use yggdrasil_rt::{
|
||||
io::{DirectoryEntry, RawFd},
|
||||
path::Path,
|
||||
sys as syscall,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
error::{self, EResult},
|
||||
header::errno::{Errno, EBADF},
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct DirReader {
|
||||
fd: Option<RawFd>,
|
||||
|
||||
// Read buffer
|
||||
buffer: Box<[MaybeUninit<DirectoryEntry>]>,
|
||||
position: usize,
|
||||
len: usize,
|
||||
}
|
||||
|
||||
impl DirReader {
|
||||
const BUFFER_SIZE: usize = 16;
|
||||
|
||||
pub fn open_at<P: AsRef<Path>>(at: Option<RawFd>, path: P) -> Result<Self, Errno> {
|
||||
let fd = EResult::from(unsafe { syscall::open_directory(None, path.as_ref().as_str()) })?;
|
||||
Ok(unsafe { Self::from_raw_fd(fd) })
|
||||
}
|
||||
|
||||
pub unsafe fn from_raw_fd(fd: RawFd) -> Self {
|
||||
Self {
|
||||
fd: Some(fd),
|
||||
|
||||
buffer: Box::new_uninit_slice(Self::BUFFER_SIZE),
|
||||
position: 0,
|
||||
len: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn close(&mut self) -> Result<(), Errno> {
|
||||
if let Some(fd) = self.fd.take() {
|
||||
EResult::from(unsafe { syscall::close(fd) })?;
|
||||
Ok(())
|
||||
} else {
|
||||
error::set_errno_result(EBADF)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_raw_fd(&self) -> RawFd {
|
||||
self.fd.unwrap()
|
||||
}
|
||||
|
||||
fn fill_buf(&mut self) -> Result<&[DirectoryEntry], Errno> {
|
||||
let Some(fd) = self.fd else {
|
||||
return error::set_errno_result(EBADF);
|
||||
};
|
||||
|
||||
if self.position == self.len {
|
||||
let count =
|
||||
EResult::from(unsafe { syscall::read_directory_entries(fd, &mut self.buffer) })?;
|
||||
|
||||
self.position = 0;
|
||||
self.len = count;
|
||||
}
|
||||
|
||||
Ok(unsafe { MaybeUninit::slice_assume_init_ref(&self.buffer[self.position..self.len]) })
|
||||
}
|
||||
|
||||
fn consume(&mut self, count: usize) {
|
||||
self.position = (self.position + count).min(self.len);
|
||||
}
|
||||
|
||||
pub fn read_entry(&mut self) -> Result<Option<DirectoryEntry>, Errno> {
|
||||
let buf = self.fill_buf()?;
|
||||
|
||||
if let Some(&entry) = buf.get(0) {
|
||||
self.consume(1);
|
||||
Ok(Some(entry))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for DirReader {
|
||||
fn drop(&mut self) {
|
||||
if self.fd.is_some() {
|
||||
unsafe {
|
||||
self.close().ok();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+31
-2
@@ -1,8 +1,18 @@
|
||||
use yggdrasil_rt::io::SeekFrom;
|
||||
use core::mem::MaybeUninit;
|
||||
|
||||
use crate::header::errno::{Errno, EINTR};
|
||||
use yggdrasil_rt::{
|
||||
io::{FileAttr, FileMode, RawFd, SeekFrom},
|
||||
path::Path,
|
||||
sys as syscall,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
error::EResult,
|
||||
header::errno::{Errno, EINTR},
|
||||
};
|
||||
|
||||
pub mod buffered;
|
||||
pub mod dir;
|
||||
|
||||
pub trait Write {
|
||||
fn write(&mut self, data: &[u8]) -> Result<usize, Errno>;
|
||||
@@ -49,3 +59,22 @@ pub trait Seek {
|
||||
self.seek(SeekFrom::Current(0))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_metadata<P: AsRef<Path>>(
|
||||
at: Option<RawFd>,
|
||||
path: P,
|
||||
follow: bool,
|
||||
) -> Result<FileAttr, Errno> {
|
||||
let mut attr = MaybeUninit::uninit();
|
||||
EResult::from(unsafe { syscall::get_metadata(at, path.as_ref().as_str(), &mut attr, follow) })?;
|
||||
Ok(unsafe { attr.assume_init() })
|
||||
}
|
||||
|
||||
pub fn create_directory<P: AsRef<Path>>(
|
||||
at: Option<RawFd>,
|
||||
path: P,
|
||||
mode: FileMode,
|
||||
) -> Result<(), Errno> {
|
||||
EResult::from(unsafe { syscall::create_directory(at, path.as_ref().as_str(), mode) })?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user