libc: extend libc I/O coverage
This commit is contained in:
parent
69649f1cea
commit
7a9a0ce59e
@ -8,6 +8,8 @@ extern "C" {
|
||||
struct __FILE;
|
||||
typedef struct __FILE FILE;
|
||||
|
||||
#define P_tmpdir "/tmp"
|
||||
|
||||
extern FILE *stdin;
|
||||
extern FILE *stdout;
|
||||
extern FILE *stderr;
|
||||
|
19
userspace/lib/ygglibc/src/headers/aio/cbindgen.toml
Normal file
19
userspace/lib/ygglibc/src/headers/aio/cbindgen.toml
Normal file
@ -0,0 +1,19 @@
|
||||
language = "C"
|
||||
style = "Tag"
|
||||
|
||||
sys_includes = [
|
||||
"stddef.h",
|
||||
"stdint.h",
|
||||
"time.h",
|
||||
"signal.h",
|
||||
"sys/types.h",
|
||||
]
|
||||
no_includes = true
|
||||
|
||||
include_guard = "_AIO_H"
|
||||
|
||||
usize_type = "size_t"
|
||||
isize_type = "ssize_t"
|
||||
|
||||
[export]
|
||||
include = ["aiocb", "__ygg_aiocb_t"]
|
75
userspace/lib/ygglibc/src/headers/aio/mod.rs
Normal file
75
userspace/lib/ygglibc/src/headers/aio/mod.rs
Normal file
@ -0,0 +1,75 @@
|
||||
use core::ffi::{c_int, c_void};
|
||||
|
||||
use super::{signal::__ygg_sigevent_t, sys_time::__ygg_timespec_t, sys_types::off_t};
|
||||
|
||||
#[repr(C)]
|
||||
pub struct aiocb {
|
||||
pub aio_fildes: c_int,
|
||||
pub aio_offset: off_t,
|
||||
pub aio_buf: *mut c_void,
|
||||
pub aio_nbytes: usize,
|
||||
pub aio_reqprio: c_int,
|
||||
pub aio_sigevent: __ygg_sigevent_t,
|
||||
pub aio_lio_opcode: c_int,
|
||||
}
|
||||
|
||||
pub type __ygg_aiocb_t = aiocb;
|
||||
|
||||
pub const AIO_ALLDONE: c_int = 1 << 0;
|
||||
pub const AIO_CANCELED: c_int = 1 << 1;
|
||||
pub const AIO_NOTCANCELED: c_int = 1 << 2;
|
||||
|
||||
pub const LIO_NOP: c_int = 1;
|
||||
pub const LIO_READ: c_int = 2;
|
||||
pub const LIO_WRITE: c_int = 3;
|
||||
pub const LIO_NOWAIT: c_int = 4;
|
||||
pub const LIO_WAIT: c_int = 5;
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn aio_cancel(_fd: c_int, _aiocbp: *mut aiocb) -> c_int {
|
||||
unimplemented!("aio_cancel(): <aio.h> is not implemented in Yggdrasil")
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn aio_error(_aiocbp: *const aiocb) -> c_int {
|
||||
unimplemented!("aio_error(): <aio.h> is not implemented in Yggdrasil")
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn aio_fsync(_fd: c_int, _aiocbp: *mut aiocb) -> c_int {
|
||||
unimplemented!("aio_fsync(): <aio.h> is not implemented in Yggdrasil")
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn aio_read(_aiocbp: *mut aiocb) -> c_int {
|
||||
unimplemented!("aio_read(): <aio.h> is not implemented in Yggdrasil")
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn aio_return(_aiocbp: *mut aiocb) -> isize {
|
||||
unimplemented!("aio_return(): <aio.h> is not implemented in Yggdrasil")
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn aio_suspend(
|
||||
_aiocbps: *const *const aiocb,
|
||||
_fd: c_int,
|
||||
_timeout: *const __ygg_timespec_t,
|
||||
) -> c_int {
|
||||
unimplemented!("aio_suspend(): <aio.h> is not implemented in Yggdrasil")
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn aio_write(_aiocbp: *mut aiocb) -> c_int {
|
||||
unimplemented!("aio_write(): <aio.h> is not implemented in Yggdrasil")
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn lio_listio(
|
||||
_fd: c_int,
|
||||
_aiocb: *const aiocb,
|
||||
_opts: c_int,
|
||||
_sigevent: *mut __ygg_sigevent_t,
|
||||
) -> c_int {
|
||||
unimplemented!("lio_listio(): <aio.h> is not implemented in Yggdrasil")
|
||||
}
|
@ -13,7 +13,7 @@ use crate::{
|
||||
util::{PointerExt, PointerStrExt},
|
||||
};
|
||||
|
||||
use super::{errno::Errno, sys_types::ino_t};
|
||||
use super::{errno::Errno, fcntl::AT_FDCWD, sys_types::ino_t};
|
||||
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
@ -118,46 +118,52 @@ unsafe extern "C" fn readdir(dir: *mut DIR) -> CPtrResult<dirent> {
|
||||
CPtrResult::success(dirent)
|
||||
}
|
||||
|
||||
// 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!()
|
||||
todo!("<dirent.h>: seekdir()")
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn rewinddir(_dir: *mut DIR) {
|
||||
todo!()
|
||||
todo!("<dirent.h>: rewinddir()")
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn telldir(_dir: *mut DIR) -> c_long {
|
||||
todo!()
|
||||
todo!("<dirent.h>: telldir()")
|
||||
}
|
||||
|
||||
// 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 {
|
||||
scandirat(AT_FDCWD, dirp, namelist, filter, compar)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn scandirat(
|
||||
_dirfd: c_int,
|
||||
_dirp: *const c_char,
|
||||
_namelist: *mut *mut *mut dirent,
|
||||
_filter: __scandir_filter_fn_t,
|
||||
_compar: __scandir_compar_fn_t,
|
||||
) -> c_int {
|
||||
todo!()
|
||||
todo!("<dirent.h>: scandirat()")
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn alphasort(_a: *const *const dirent, _b: *const *const dirent) -> c_int {
|
||||
todo!()
|
||||
todo!("<dirent.h>: alphasort()")
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn versionsort(_a: *const *const dirent, _b: *const *const dirent) -> c_int {
|
||||
todo!("<dirent.h>: alphasort()")
|
||||
}
|
||||
|
@ -1,12 +1,9 @@
|
||||
use core::ffi::{c_char, c_int, c_short, VaList};
|
||||
|
||||
use yggdrasil_rt::{
|
||||
io::{AccessMode, FileMode, OpenOptions},
|
||||
sys as syscall,
|
||||
};
|
||||
use yggdrasil_rt::io::{FileMode, OpenOptions};
|
||||
|
||||
use crate::{
|
||||
error::{CFdResult, CIntCountResult, CIntZeroResult, EResult, ResultExt, TryFromExt},
|
||||
error::{CFdResult, CIntCountResult, EResult, TryFromExt},
|
||||
io::{raw::RawFile, IntoRawFd},
|
||||
util::{self, PointerStrExt},
|
||||
};
|
||||
@ -16,16 +13,6 @@ use super::{
|
||||
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,
|
||||
@ -81,10 +68,12 @@ 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 R_OK: c_int = 1 << 0;
|
||||
pub const W_OK: c_int = 1 << 1;
|
||||
pub const X_OK: c_int = 1 << 2;
|
||||
pub const F_OK: c_int = 0;
|
||||
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),
|
||||
@ -155,6 +144,7 @@ unsafe extern "C" fn fcntl(fd: c_int, cmd: c_int, _args: ...) -> CIntCountResult
|
||||
|
||||
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);
|
||||
@ -195,25 +185,18 @@ unsafe extern "C" fn openat(
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub(crate) unsafe extern "C" fn faccessat(
|
||||
atfd: c_int,
|
||||
path: *const c_char,
|
||||
mode: c_int,
|
||||
_flags: c_int,
|
||||
) -> CIntZeroResult {
|
||||
let atfd = util::at_fd(atfd)?;
|
||||
let path = path.ensure_str();
|
||||
let mut access = AccessMode::empty();
|
||||
if mode & R_OK != 0 {
|
||||
access |= AccessMode::READ;
|
||||
}
|
||||
if mode & W_OK != 0 {
|
||||
access |= AccessMode::WRITE;
|
||||
}
|
||||
if mode & X_OK != 0 {
|
||||
access |= AccessMode::EXEC;
|
||||
}
|
||||
syscall::check_access(atfd, path, access).e_map_err(Errno::from)?;
|
||||
|
||||
CIntZeroResult::SUCCESS
|
||||
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()")
|
||||
}
|
||||
|
12
userspace/lib/ygglibc/src/headers/fnmatch/cbindgen.toml
Normal file
12
userspace/lib/ygglibc/src/headers/fnmatch/cbindgen.toml
Normal file
@ -0,0 +1,12 @@
|
||||
language = "C"
|
||||
style = "Type"
|
||||
|
||||
sys_includes = []
|
||||
no_includes = true
|
||||
|
||||
include_guard = "_FNMATCH_H"
|
||||
|
||||
usize_type = "size_t"
|
||||
isize_type = "ssize_t"
|
||||
|
||||
[export]
|
15
userspace/lib/ygglibc/src/headers/fnmatch/mod.rs
Normal file
15
userspace/lib/ygglibc/src/headers/fnmatch/mod.rs
Normal file
@ -0,0 +1,15 @@
|
||||
use core::ffi::{c_char, c_int};
|
||||
|
||||
pub const FNM_NOMATCH: c_int = 1;
|
||||
pub const FNM_PATHNAME: c_int = 1 << 0;
|
||||
pub const FNM_NOESCAPE: c_int = 1 << 1;
|
||||
pub const FNM_PERIOD: c_int = 1 << 2;
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn fnmatch(
|
||||
_pattern: *const c_char,
|
||||
_name: *const c_char,
|
||||
_flags: c_int,
|
||||
) -> c_int {
|
||||
todo!("fnmatch()")
|
||||
}
|
15
userspace/lib/ygglibc/src/headers/ftw/cbindgen.toml
Normal file
15
userspace/lib/ygglibc/src/headers/ftw/cbindgen.toml
Normal file
@ -0,0 +1,15 @@
|
||||
language = "C"
|
||||
style = "Tag"
|
||||
|
||||
sys_includes = [
|
||||
"sys/stat.h",
|
||||
]
|
||||
no_includes = true
|
||||
|
||||
include_guard = "_FTW_H"
|
||||
|
||||
usize_type = "size_t"
|
||||
isize_type = "ssize_t"
|
||||
|
||||
[export]
|
||||
include = ["FTW"]
|
41
userspace/lib/ygglibc/src/headers/ftw/mod.rs
Normal file
41
userspace/lib/ygglibc/src/headers/ftw/mod.rs
Normal file
@ -0,0 +1,41 @@
|
||||
use core::ffi::{c_char, c_int};
|
||||
|
||||
use super::sys_stat::__ygg_stat_t;
|
||||
|
||||
#[repr(C)]
|
||||
pub struct FTW {
|
||||
pub base: c_int,
|
||||
pub level: c_int,
|
||||
}
|
||||
|
||||
pub const FTW_F: c_int = 1;
|
||||
pub const FTW_D: c_int = 2;
|
||||
pub const FTW_DNR: c_int = 3;
|
||||
pub const FTW_DP: c_int = 4;
|
||||
pub const FTW_NS: c_int = 5;
|
||||
pub const FTW_SL: c_int = 6;
|
||||
pub const FTW_SLN: c_int = 7;
|
||||
|
||||
pub const FTW_PHYS: c_int = 1;
|
||||
pub const FTW_MOUNT: c_int = 2;
|
||||
pub const FTW_DEPTH: c_int = 3;
|
||||
pub const FTW_CHDIR: c_int = 4;
|
||||
|
||||
pub type __ftw_func_t = extern "C" fn(*const c_char, *const __ygg_stat_t, c_int) -> c_int;
|
||||
pub type __nftw_func_t =
|
||||
extern "C" fn(*const c_char, *const __ygg_stat_t, c_int, *mut FTW) -> c_int;
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn ftw(_dir: *const c_char, _func: __ftw_func_t, _fds: c_int) -> c_int {
|
||||
todo!("ftw()")
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn nftw(
|
||||
_dir: *const c_char,
|
||||
_func: __nftw_func_t,
|
||||
_fds: c_int,
|
||||
_flag: c_int,
|
||||
) -> c_int {
|
||||
todo!("nftw()")
|
||||
}
|
14
userspace/lib/ygglibc/src/headers/glob/cbindgen.toml
Normal file
14
userspace/lib/ygglibc/src/headers/glob/cbindgen.toml
Normal file
@ -0,0 +1,14 @@
|
||||
language = "C"
|
||||
style = "Type"
|
||||
|
||||
sys_includes = [
|
||||
"sys/types.h"
|
||||
]
|
||||
no_includes = true
|
||||
|
||||
include_guard = "_GLOB_H"
|
||||
|
||||
usize_type = "size_t"
|
||||
isize_type = "ssize_t"
|
||||
|
||||
[export]
|
35
userspace/lib/ygglibc/src/headers/glob/mod.rs
Normal file
35
userspace/lib/ygglibc/src/headers/glob/mod.rs
Normal file
@ -0,0 +1,35 @@
|
||||
use core::ffi::{c_char, c_int};
|
||||
|
||||
#[repr(C)]
|
||||
pub struct glob_t {
|
||||
pub gl_pathc: usize,
|
||||
pub gl_pathv: *mut *mut c_char,
|
||||
pub gl_offs: usize,
|
||||
}
|
||||
|
||||
pub const GLOB_APPEND: c_int = 1 << 0;
|
||||
pub const GLOB_DOOFFS: c_int = 1 << 1;
|
||||
pub const GLOB_ERR: c_int = 1 << 2;
|
||||
pub const GLOB_MARK: c_int = 1 << 3;
|
||||
pub const GLOB_NOCHECK: c_int = 1 << 4;
|
||||
pub const GLOB_NOESCAPE: c_int = 1 << 5;
|
||||
pub const GLOB_NOSORT: c_int = 1 << 6;
|
||||
|
||||
pub const GLOB_ABORTED: c_int = -1;
|
||||
pub const GLOB_NOMATCH: c_int = -2;
|
||||
pub const GLOB_NOSPACE: c_int = -3;
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn glob(
|
||||
_pattern: *const c_char,
|
||||
_flags: c_int,
|
||||
_errfunc: extern "C" fn(*const c_char, c_int) -> c_int,
|
||||
_pglob: *mut glob_t,
|
||||
) -> c_int {
|
||||
todo!("glob()")
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn globfree(_pglob: *mut glob_t) {
|
||||
todo!("globfree()")
|
||||
}
|
@ -1,11 +1,47 @@
|
||||
use core::ffi::c_char;
|
||||
|
||||
use crate::util::PointerStrExt;
|
||||
|
||||
const DOT: *mut c_char = c".".as_ptr().cast_mut();
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn basename(_path: *mut c_char) -> *mut c_char {
|
||||
todo!()
|
||||
unsafe extern "C" fn basename(path: *mut c_char) -> *mut c_char {
|
||||
if path.is_null() {
|
||||
return DOT;
|
||||
}
|
||||
let path_str = path.cast_const().ensure_str();
|
||||
if path_str == "" {
|
||||
DOT
|
||||
} else if path_str == "/" {
|
||||
path
|
||||
} else {
|
||||
let path_str = path_str.trim_end_matches('/');
|
||||
if let Some(last_slash) = path_str.rfind('/') {
|
||||
path.add(last_slash + 1)
|
||||
} else {
|
||||
path
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn dirname(_path: *mut c_char) -> *mut c_char {
|
||||
todo!()
|
||||
unsafe extern "C" fn dirname(path: *mut c_char) -> *mut c_char {
|
||||
if path.is_null() {
|
||||
return DOT;
|
||||
}
|
||||
let path_str = path.cast_const().ensure_str();
|
||||
if path_str.is_empty() {
|
||||
DOT
|
||||
} else if path_str == "/" {
|
||||
path
|
||||
} else {
|
||||
let path_str = path_str.trim_end_matches('/');
|
||||
if let Some(last_slash) = path_str.rfind('/') {
|
||||
// Turn last slash into '\0' to terminate dirname
|
||||
path.add(last_slash).write(0);
|
||||
path
|
||||
} else {
|
||||
DOT
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,102 +1,14 @@
|
||||
#![allow(non_camel_case_types, non_upper_case_globals)]
|
||||
|
||||
// - not yet implemented
|
||||
// = partially implemented
|
||||
// + fully implemented
|
||||
// ! out of scope for now
|
||||
|
||||
// Network
|
||||
// <arpa/inet.h> !
|
||||
// <ndbm.h> !
|
||||
// <net/if.h> !
|
||||
// <netdb.h> !
|
||||
// <netinet/in.h> !
|
||||
// <netinet/tcp.h> !
|
||||
// <sys/socket.h> !
|
||||
// <sys/un.h> !
|
||||
|
||||
// Math
|
||||
// <complex.h> -
|
||||
// <fenv.h> -
|
||||
// <math.h> +
|
||||
|
||||
// I/O utilities
|
||||
// <cpio.h> !
|
||||
// <fmtmsg.h> !
|
||||
// <fnmatch.h> !
|
||||
// <ftw.h> !
|
||||
// <glob.h> !
|
||||
// <mqueue.h> !
|
||||
// <stdlib.h> =
|
||||
// <stropts.h> !
|
||||
// <sys/uio.h> !
|
||||
// <tar.h> !
|
||||
|
||||
// I/O
|
||||
// <aio.h> !
|
||||
// <dirent.h> +
|
||||
// <fcntl.h> +
|
||||
// <poll.h> =
|
||||
// <stdio.h> +
|
||||
// <sys/select.h> =
|
||||
// <sys/shm.h> !
|
||||
// <sys/stat.h> =
|
||||
// <sys/statvfs.h> =
|
||||
// <syslog.h> !
|
||||
// <termios.h> =
|
||||
// <trace.h> !
|
||||
// <unistd.h> ~
|
||||
|
||||
// Misc utilities
|
||||
// <assert.h> +
|
||||
// <dlfcn.h> !
|
||||
// <errno.h> +
|
||||
// <grp.h> =
|
||||
// <libgen.h> =
|
||||
// <pwd.h> =
|
||||
// <sched.h> =
|
||||
// <search.h> !
|
||||
// <sys/resource.h> =
|
||||
// <sys/time.h> =
|
||||
// <sys/times.h> =
|
||||
// <sys/types.h> +
|
||||
// <sys/utsname.h> =
|
||||
// <time.h> =
|
||||
// <utmpx.h> !
|
||||
|
||||
// Process utilities
|
||||
// <pthread.h> !
|
||||
// <semaphore.h> !
|
||||
// <setjmp.h> +
|
||||
// <signal.h> =
|
||||
// <spawn.h> =
|
||||
// <sys/ipc.h> !
|
||||
// <sys/mman.h> =
|
||||
// <sys/msg.h> !
|
||||
// <sys/sem.h> !
|
||||
// <sys/wait.h> =
|
||||
// <ulimit.h> =
|
||||
// <utime.h> =
|
||||
|
||||
// Locale & string utilities
|
||||
// <ctype.h> +
|
||||
// <iconv.h> =
|
||||
// <langinfo.h> =
|
||||
// <locale.h> =
|
||||
// <monetary.h> =
|
||||
// <nl_types.h> =
|
||||
// <regex.h> !
|
||||
// <string.h> +
|
||||
// <strings.h> =
|
||||
// <wchar.h> =
|
||||
// <wctype.h> =
|
||||
// <wordexp.h> !
|
||||
|
||||
pub mod aio;
|
||||
pub mod ctype;
|
||||
pub mod dirent;
|
||||
pub mod dlfcn;
|
||||
pub mod errno;
|
||||
pub mod fcntl;
|
||||
pub mod fnmatch;
|
||||
pub mod ftw;
|
||||
pub mod glob;
|
||||
pub mod grp;
|
||||
pub mod iconv;
|
||||
pub mod langinfo;
|
||||
|
@ -24,5 +24,5 @@ pub const POLLWRBAND: c_short = 1 << 9;
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn poll(_fds: *mut pollfd, _nfds: nfds_t, _flags: c_int) -> c_int {
|
||||
todo!()
|
||||
todo!("poll()")
|
||||
}
|
||||
|
@ -19,5 +19,5 @@ isize_type = "ssize_t"
|
||||
enum_style = "define"
|
||||
|
||||
[export]
|
||||
include = ["sig_handler_t", "sigaction", "sigevent", "SIGABRT"]
|
||||
include = ["sig_handler_t", "sigaction", "sigevent", "__ygg_sigevent_t", "SIGABRT"]
|
||||
exclude = []
|
||||
|
@ -40,6 +40,8 @@ pub struct sigevent {
|
||||
pub sigev_notify_attributes: *mut c_void,
|
||||
}
|
||||
|
||||
pub type __ygg_sigevent_t = sigevent;
|
||||
|
||||
#[repr(C)]
|
||||
pub struct sigaction {
|
||||
pub sa_handler: unsafe extern "C" fn(c_int),
|
||||
|
@ -183,8 +183,13 @@ unsafe extern "C" fn ftello(fp: *mut FILE) -> COffsetResult {
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn ftrylockfile(_fp: *mut FILE) -> c_int {
|
||||
unimplemented!()
|
||||
unsafe extern "C" fn ftrylockfile(fp: *mut FILE) -> c_int {
|
||||
let fp = fp.ensure_mut();
|
||||
if fp.try_lock() {
|
||||
0
|
||||
} else {
|
||||
-1
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@ -203,12 +208,12 @@ unsafe extern "C" fn open_memstream(
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn pclose(_fp: *mut FILE) -> c_int {
|
||||
todo!()
|
||||
todo!("pclose()")
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn popen(_command: *const c_char, _ty: *const c_char) -> CPtrResult<FILE> {
|
||||
todo!()
|
||||
todo!("popen()")
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@ -244,21 +249,11 @@ unsafe extern "C" fn setvbuf(
|
||||
CIntZeroResult::SUCCESS
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn fpurge(_fp: *mut FILE) {
|
||||
todo!("fpurge()")
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn __fpurge(_fp: *mut FILE) {
|
||||
todo!("__fpurge()")
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn freading(fp: *mut FILE) -> c_int {
|
||||
__freading(fp)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn __freading(fp: *mut FILE) -> c_int {
|
||||
let fp = fp.ensure_mut();
|
||||
@ -302,6 +297,7 @@ unsafe extern "C" fn __fwriting(fp: *mut FILE) -> c_int {
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn __fseterr(_fp: *mut FILE) {
|
||||
todo!("__fseterr()")
|
||||
unsafe extern "C" fn __fseterr(fp: *mut FILE) {
|
||||
let fp = fp.ensure_mut();
|
||||
fp.set_error();
|
||||
}
|
||||
|
@ -14,8 +14,8 @@ mod util;
|
||||
// ssize_t from <sys/types.h>
|
||||
//
|
||||
// stdin, stdout, stderr as externs from <bits/stdio.h>
|
||||
// TODO L_ctermid
|
||||
pub const L_tmpnam: c_int = 256;
|
||||
pub const L_tmpnam: c_int = 64;
|
||||
pub const L_ctermid: c_int = 64;
|
||||
|
||||
pub const _IOFBF: c_int = 0;
|
||||
pub const _IOLBF: c_int = 1;
|
||||
|
@ -1,98 +1,23 @@
|
||||
use core::{
|
||||
ffi::{c_char, c_int, VaList},
|
||||
fmt,
|
||||
ptr::NonNull,
|
||||
};
|
||||
|
||||
use format::{FmtOpts, FmtRadix, FmtSign, FmtSize, FmtSpec};
|
||||
use writer::{AllocatedStringWriter, FileWriter, FmtWriter, StringWriter};
|
||||
|
||||
use crate::{
|
||||
error::{CIntCountResult, EResult, TryFromExt},
|
||||
io::{
|
||||
managed::{stdout, FILE},
|
||||
raw::RawFile,
|
||||
Write,
|
||||
},
|
||||
util::{PointerExt, PointerStrExt},
|
||||
};
|
||||
|
||||
mod float;
|
||||
mod format;
|
||||
|
||||
struct FileWriter<'w, W: Write>(&'w mut W);
|
||||
struct StringWriter {
|
||||
buffer: NonNull<c_char>,
|
||||
position: usize,
|
||||
capacity: usize,
|
||||
}
|
||||
|
||||
trait FmtWriter: Write + fmt::Write {}
|
||||
|
||||
impl<W: Write> fmt::Write for FileWriter<'_, W> {
|
||||
fn write_str(&mut self, s: &str) -> fmt::Result {
|
||||
self.0
|
||||
.write_all(s.as_bytes())
|
||||
.into_result(|_| fmt::Error, true)
|
||||
}
|
||||
}
|
||||
|
||||
impl<W: Write> Write for FileWriter<'_, W> {
|
||||
fn write(&mut self, data: &[u8]) -> EResult<usize> {
|
||||
self.0.write(data)
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> EResult<()> {
|
||||
self.0.flush()
|
||||
}
|
||||
}
|
||||
|
||||
impl<W: Write> FmtWriter for FileWriter<'_, W> {}
|
||||
|
||||
impl StringWriter {
|
||||
pub fn new(buffer: NonNull<c_char>, capacity: usize) -> Self {
|
||||
Self {
|
||||
buffer,
|
||||
capacity,
|
||||
position: 0,
|
||||
}
|
||||
}
|
||||
|
||||
fn finish(&mut self) {
|
||||
if self.position < self.capacity {
|
||||
unsafe { self.buffer.add(self.position).write(0) };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Write for StringWriter {
|
||||
fn write_str(&mut self, s: &str) -> fmt::Result {
|
||||
self.write(s.as_bytes()).into_result(|_| fmt::Error, true)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Write for StringWriter {
|
||||
fn write(&mut self, data: &[u8]) -> EResult<usize> {
|
||||
let count = core::cmp::min(self.capacity - self.position, data.len());
|
||||
if count > 0 {
|
||||
let dst = unsafe {
|
||||
core::slice::from_raw_parts_mut(
|
||||
self.buffer.add(self.position).as_ptr().cast(),
|
||||
count,
|
||||
)
|
||||
};
|
||||
dst.copy_from_slice(&data[..count]);
|
||||
self.position += count;
|
||||
}
|
||||
EResult::Ok(count)
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> EResult<()> {
|
||||
EResult::Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl FmtWriter for StringWriter {}
|
||||
mod writer;
|
||||
|
||||
fn printf_inner<W: FmtWriter>(output: &mut W, format: &[u8], mut ap: VaList) -> EResult<usize> {
|
||||
let mut fmt = format.iter();
|
||||
@ -196,17 +121,31 @@ fn printf_inner<W: FmtWriter>(output: &mut W, format: &[u8], mut ap: VaList) ->
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn asprintf(dst: *mut *mut c_char, fmt: *const c_char, mut args: ...) -> c_int {
|
||||
unsafe extern "C" fn asprintf(
|
||||
dst: *mut *mut c_char,
|
||||
fmt: *const c_char,
|
||||
mut args: ...
|
||||
) -> CIntCountResult {
|
||||
vasprintf(dst, fmt, args.as_va_list())
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn vasprintf(
|
||||
_dst: *mut *mut c_char,
|
||||
_fmt: *const c_char,
|
||||
_args: VaList,
|
||||
) -> c_int {
|
||||
todo!()
|
||||
dst: *mut *mut c_char,
|
||||
fmt: *const c_char,
|
||||
args: VaList,
|
||||
) -> CIntCountResult {
|
||||
let dst = dst.ensure_mut();
|
||||
let fmt = fmt.ensure_cstr();
|
||||
if !(*dst).is_null() {
|
||||
// Not sure if the previous pointer needs to be free()d
|
||||
todo!()
|
||||
}
|
||||
let mut writer = AllocatedStringWriter::new(usize::MAX);
|
||||
let count = printf_inner(&mut writer, fmt.to_bytes(), args)?;
|
||||
let ptr = writer.finish()?;
|
||||
*dst = ptr.as_ptr();
|
||||
CIntCountResult::success(count.try_into().unwrap())
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
|
145
userspace/lib/ygglibc/src/headers/stdio/printf/writer.rs
Normal file
145
userspace/lib/ygglibc/src/headers/stdio/printf/writer.rs
Normal file
@ -0,0 +1,145 @@
|
||||
use core::{ffi::c_char, fmt, ptr::NonNull};
|
||||
|
||||
use alloc::vec::Vec;
|
||||
|
||||
use crate::{
|
||||
allocator::c_alloc,
|
||||
error::{self, EResult},
|
||||
headers::errno::Errno,
|
||||
io::Write,
|
||||
};
|
||||
|
||||
pub(super) struct FileWriter<'w, W: Write>(pub(super) &'w mut W);
|
||||
pub(super) struct StringWriter {
|
||||
buffer: NonNull<c_char>,
|
||||
position: usize,
|
||||
capacity: usize,
|
||||
}
|
||||
pub(super) struct AllocatedStringWriter {
|
||||
buffer: Vec<u8>,
|
||||
limit: usize,
|
||||
}
|
||||
|
||||
pub(super) trait FmtWriter: Write + fmt::Write {}
|
||||
|
||||
// File
|
||||
|
||||
impl<W: Write> fmt::Write for FileWriter<'_, W> {
|
||||
fn write_str(&mut self, s: &str) -> fmt::Result {
|
||||
self.0
|
||||
.write_all(s.as_bytes())
|
||||
.into_result(|_| fmt::Error, true)
|
||||
}
|
||||
}
|
||||
|
||||
impl<W: Write> Write for FileWriter<'_, W> {
|
||||
fn write(&mut self, data: &[u8]) -> EResult<usize> {
|
||||
self.0.write(data)
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> EResult<()> {
|
||||
self.0.flush()
|
||||
}
|
||||
}
|
||||
|
||||
impl<W: Write> FmtWriter for FileWriter<'_, W> {}
|
||||
|
||||
// String
|
||||
|
||||
impl StringWriter {
|
||||
pub fn new(buffer: NonNull<c_char>, capacity: usize) -> Self {
|
||||
Self {
|
||||
buffer,
|
||||
capacity,
|
||||
position: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn finish(&mut self) {
|
||||
if self.position < self.capacity {
|
||||
unsafe { self.buffer.add(self.position).write(0) };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Write for StringWriter {
|
||||
fn write_str(&mut self, s: &str) -> fmt::Result {
|
||||
self.write(s.as_bytes()).into_result(|_| fmt::Error, true)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Write for StringWriter {
|
||||
fn write(&mut self, data: &[u8]) -> EResult<usize> {
|
||||
let count = core::cmp::min(self.capacity - self.position, data.len());
|
||||
if count > 0 {
|
||||
let dst = unsafe {
|
||||
core::slice::from_raw_parts_mut(
|
||||
self.buffer.add(self.position).as_ptr().cast(),
|
||||
count,
|
||||
)
|
||||
};
|
||||
dst.copy_from_slice(&data[..count]);
|
||||
self.position += count;
|
||||
}
|
||||
EResult::Ok(count)
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> EResult<()> {
|
||||
EResult::Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl FmtWriter for StringWriter {}
|
||||
|
||||
// Allocated string
|
||||
|
||||
impl AllocatedStringWriter {
|
||||
pub fn new(limit: usize) -> Self {
|
||||
Self {
|
||||
buffer: Vec::new(),
|
||||
limit,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn finish(self) -> EResult<NonNull<c_char>> {
|
||||
assert!(self.buffer.len() < self.limit);
|
||||
let data = c_alloc(self.buffer.len() + 1, 1, false)?.cast::<c_char>();
|
||||
unsafe {
|
||||
let dst_slice =
|
||||
NonNull::slice_from_raw_parts(data.cast::<u8>(), self.buffer.len() + 1).as_mut();
|
||||
dst_slice[..self.buffer.len()].copy_from_slice(&self.buffer[..]);
|
||||
dst_slice[self.buffer.len()] = 0;
|
||||
}
|
||||
EResult::Ok(data)
|
||||
}
|
||||
}
|
||||
|
||||
impl Write for AllocatedStringWriter {
|
||||
fn write(&mut self, data: &[u8]) -> EResult<usize> {
|
||||
let amount = (self.limit - self.buffer.len()).min(data.len());
|
||||
if self.buffer.try_reserve(amount).is_err() {
|
||||
return EResult::Err(Errno::ENOMEM);
|
||||
}
|
||||
self.buffer.extend_from_slice(&data[..amount]);
|
||||
EResult::Ok(data.len())
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> EResult<()> {
|
||||
EResult::Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Write for AllocatedStringWriter {
|
||||
fn write_str(&mut self, s: &str) -> fmt::Result {
|
||||
match self.write_all(s.as_bytes()) {
|
||||
EResult::Ok(()) => Ok(()),
|
||||
EResult::Err(e) => {
|
||||
unsafe { error::errno = e };
|
||||
Err(fmt::Error)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FmtWriter for AllocatedStringWriter {}
|
@ -16,4 +16,4 @@ usize_type = "size_t"
|
||||
isize_type = "ssize_t"
|
||||
|
||||
[export]
|
||||
include = ["stat"]
|
||||
include = ["stat", "__ygg_stat_t"]
|
||||
|
@ -38,6 +38,8 @@ pub struct stat {
|
||||
pub st_blocks: blkcnt_t,
|
||||
}
|
||||
|
||||
pub type __ygg_stat_t = stat;
|
||||
|
||||
pub const S_IFMT: c_int = 0xF << 16;
|
||||
pub const S_IFBLK: c_int = 1 << 16;
|
||||
pub const S_IFCHR: c_int = 2 << 16;
|
||||
|
@ -3,13 +3,16 @@ use core::{
|
||||
ptr::{null_mut, NonNull},
|
||||
};
|
||||
|
||||
use yggdrasil_rt::io::RemoveFlags;
|
||||
use yggdrasil_rt::{
|
||||
io::{AccessMode, RemoveFlags},
|
||||
sys as syscall,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
error::{self, CIntZeroResult, CPtrResult, EResult, ResultExt, TryFromExt},
|
||||
headers::{
|
||||
errno::Errno,
|
||||
fcntl::{faccessat, AT_FDCWD, AT_REMOVEDIR},
|
||||
fcntl::{AT_FDCWD, AT_REMOVEDIR},
|
||||
sys_types::{gid_t, off_t, uid_t},
|
||||
},
|
||||
io::{self, raw::RawFile, FromRawFd},
|
||||
@ -18,6 +21,11 @@ use crate::{
|
||||
|
||||
pub const _PC_PATH_MAX: c_int = 0;
|
||||
|
||||
pub const R_OK: c_int = 1 << 0;
|
||||
pub const W_OK: c_int = 1 << 1;
|
||||
pub const X_OK: c_int = 1 << 2;
|
||||
pub const F_OK: c_int = 0;
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn access(path: *const c_char, mode: c_int) -> CIntZeroResult {
|
||||
faccessat(AT_FDCWD, path, mode, 0)
|
||||
@ -35,6 +43,30 @@ unsafe extern "C" fn chown(path: *const c_char, uid: uid_t, gid: gid_t) -> c_int
|
||||
todo!()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub(crate) unsafe extern "C" fn faccessat(
|
||||
atfd: c_int,
|
||||
path: *const c_char,
|
||||
mode: c_int,
|
||||
_flags: c_int,
|
||||
) -> CIntZeroResult {
|
||||
let atfd = util::at_fd(atfd)?;
|
||||
let path = path.ensure_str();
|
||||
let mut access = AccessMode::empty();
|
||||
if mode & R_OK != 0 {
|
||||
access |= AccessMode::READ;
|
||||
}
|
||||
if mode & W_OK != 0 {
|
||||
access |= AccessMode::WRITE;
|
||||
}
|
||||
if mode & X_OK != 0 {
|
||||
access |= AccessMode::EXEC;
|
||||
}
|
||||
syscall::check_access(atfd, path, access).e_map_err(Errno::from)?;
|
||||
|
||||
CIntZeroResult::SUCCESS
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn fchdir(fd: c_int) -> c_int {
|
||||
todo!()
|
||||
|
@ -30,6 +30,7 @@ use super::{
|
||||
};
|
||||
|
||||
macro locked_op($self:expr, $op:expr) {{
|
||||
#![allow(unused_unsafe)]
|
||||
$self.lock.lock();
|
||||
let result = unsafe { $op };
|
||||
unsafe { $self.lock.release() };
|
||||
@ -286,6 +287,10 @@ impl FILE {
|
||||
self.flags.remove(FileFlags::ERROR);
|
||||
}
|
||||
|
||||
pub fn try_lock(&self) -> bool {
|
||||
self.lock.try_lock()
|
||||
}
|
||||
|
||||
pub unsafe fn lock(&mut self) {
|
||||
self.lock.lock();
|
||||
}
|
||||
@ -348,6 +353,12 @@ impl FILE {
|
||||
locked_op!(self, self.is_line_buffered_locked())
|
||||
}
|
||||
|
||||
pub fn set_error(&mut self) {
|
||||
locked_op!(self, {
|
||||
self.flags |= FileFlags::ERROR;
|
||||
});
|
||||
}
|
||||
|
||||
// pub fn reset(&mut self) {
|
||||
// if let Some(read_buffer) = self.read_buffer.as_mut() {
|
||||
// read_buffer.reset();
|
||||
|
Loading…
x
Reference in New Issue
Block a user