multiple: most of <dirent.h>, <fcntl.h>, <sys/stat.h>

This commit is contained in:
2024-01-12 13:28:33 +02:00
parent c979f5642b
commit ffbac93115
19 changed files with 1017 additions and 9 deletions
+8
View File
@@ -0,0 +1,8 @@
#ifndef _YGGDRASIL_DIRENT
#define _YGGDRASIL_DIRENT 1
struct __DIR;
typedef struct __DIR DIR;
#endif
+8
View File
@@ -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
+16
View File
@@ -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
+6
View File
@@ -0,0 +1,6 @@
#ifndef _YGGDRASIL_TIME_H
#define _YGGDRASIL_TIME_H 1
typedef struct timespec __ygg_timespec_t;
#endif
+6
View File
@@ -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 {
+14
View 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]
+142
View File
@@ -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!()
}
+20
View File
@@ -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"]
+162
View File
@@ -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!()
}
+23
View File
@@ -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"]
+168
View File
@@ -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
View File
@@ -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
+19
View File
@@ -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"]
+256
View File
@@ -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!()
}
+2 -2
View File
@@ -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;
+18
View File
@@ -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"]
+12
View File
@@ -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;
+96
View File
@@ -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
View File
@@ -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(())
}