From 7a0298b7dad7e73a48e1f9ff4474ae8d125392af Mon Sep 17 00:00:00 2001 From: vibix auto-engineer Date: Tue, 5 May 2026 05:59:38 +0000 Subject: [PATCH] Add vibix_libc and vibix_libc_defs crates vibix_libc exposes C-ABI symbols (open, openat, read, write, close, stat, fstat, lstat, mkdir, rmdir, unlink, link, symlink, readlink, chmod, chown, rename, getcwd, chdir) that delegate to vibix_abi syscall wrappers. This allows the upstream libc and nix crates to link against vibix. vibix_libc_defs provides type definitions (struct stat, timespec, sigaction, dirent64, utsname, iovec) and constants (O_RDONLY, O_CREAT, S_IFMT, S_IFDIR, errno values, syscall numbers, etc.) matching the Linux x86_64 layout that vibix uses. Both crates are added to the workspace Cargo.toml and pass cargo check. The kernel still builds cleanly via cargo xtask build. Closes #855 Co-Authored-By: Claude Opus 4.6 --- Cargo.toml | 2 + userspace/vibix_libc/Cargo.toml | 15 ++ userspace/vibix_libc/src/errno.rs | 7 + userspace/vibix_libc/src/fcntl.rs | 28 +++ userspace/vibix_libc/src/helpers.rs | 15 ++ userspace/vibix_libc/src/lib.rs | 22 ++ userspace/vibix_libc/src/stat.rs | 63 +++++ userspace/vibix_libc/src/unistd.rs | 142 +++++++++++ userspace/vibix_libc_defs/Cargo.toml | 11 + userspace/vibix_libc_defs/src/lib.rs | 356 +++++++++++++++++++++++++++ 10 files changed, 661 insertions(+) create mode 100644 userspace/vibix_libc/Cargo.toml create mode 100644 userspace/vibix_libc/src/errno.rs create mode 100644 userspace/vibix_libc/src/fcntl.rs create mode 100644 userspace/vibix_libc/src/helpers.rs create mode 100644 userspace/vibix_libc/src/lib.rs create mode 100644 userspace/vibix_libc/src/stat.rs create mode 100644 userspace/vibix_libc/src/unistd.rs create mode 100644 userspace/vibix_libc_defs/Cargo.toml create mode 100644 userspace/vibix_libc_defs/src/lib.rs diff --git a/Cargo.toml b/Cargo.toml index c2a0f8f6..f07eed82 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,6 +22,8 @@ members = [ "userspace/repro_fork", "userspace/shell_pipeline", "userspace/vibix_abi", + "userspace/vibix_libc", + "userspace/vibix_libc_defs", ] # tests/pjdfstest is a vendored copy of saidsay-so/pjdfstest (2-clause BSD). It # is intentionally kept outside the workspace until #581 wires it into xtask — diff --git a/userspace/vibix_libc/Cargo.toml b/userspace/vibix_libc/Cargo.toml new file mode 100644 index 00000000..0fe37641 --- /dev/null +++ b/userspace/vibix_libc/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "vibix_libc" +version.workspace = true +edition.workspace = true +authors.workspace = true +license.workspace = true +description = "C-ABI shim that delegates to vibix_abi syscall wrappers" + +[lib] +name = "vibix_libc" +path = "src/lib.rs" +crate-type = ["rlib"] + +[dependencies] +vibix_abi = { path = "../vibix_abi" } diff --git a/userspace/vibix_libc/src/errno.rs b/userspace/vibix_libc/src/errno.rs new file mode 100644 index 00000000..d9403010 --- /dev/null +++ b/userspace/vibix_libc/src/errno.rs @@ -0,0 +1,7 @@ +//! errno support -- re-exports vibix_abi's thread-local ERRNO and +//! __errno_location symbol. +//! +//! The actual `__errno_location` symbol is defined in `vibix_abi::errno`. +//! This module simply re-exports the ERRNO cell for internal use. + +pub use vibix_abi::errno::ERRNO; diff --git a/userspace/vibix_libc/src/fcntl.rs b/userspace/vibix_libc/src/fcntl.rs new file mode 100644 index 00000000..69e523fe --- /dev/null +++ b/userspace/vibix_libc/src/fcntl.rs @@ -0,0 +1,28 @@ +//! File control operations: open, openat. + +use crate::helpers::syscall_ret; +use vibix_abi::syscall; + +// Syscall numbers (Linux x86_64) +const SYS_OPEN: u64 = 2; +const SYS_OPENAT: u64 = 257; + +/// Open a file by path. +/// +/// # Safety +/// `pathname` must be a valid null-terminated C string pointer. +#[no_mangle] +pub unsafe extern "C" fn open(pathname: *const u8, flags: i32, mode: u32) -> i32 { + let ret = syscall!(SYS_OPEN, pathname, flags, mode); + syscall_ret(ret) as i32 +} + +/// Open a file relative to a directory fd. +/// +/// # Safety +/// `pathname` must be a valid null-terminated C string pointer. +#[no_mangle] +pub unsafe extern "C" fn openat(dirfd: i32, pathname: *const u8, flags: i32, mode: u32) -> i32 { + let ret = syscall!(SYS_OPENAT, dirfd, pathname, flags, mode); + syscall_ret(ret) as i32 +} diff --git a/userspace/vibix_libc/src/helpers.rs b/userspace/vibix_libc/src/helpers.rs new file mode 100644 index 00000000..723773e9 --- /dev/null +++ b/userspace/vibix_libc/src/helpers.rs @@ -0,0 +1,15 @@ +//! Internal helpers for converting syscall return values to C-style returns. + +use vibix_abi::errno::ERRNO; + +/// Convert a raw syscall return (negative = -errno) into C return convention: +/// on success returns the non-negative value; on error sets ERRNO and returns -1. +#[inline] +pub(crate) fn syscall_ret(ret: i64) -> i64 { + if ret < 0 { + ERRNO.set((-ret) as i32); + -1 + } else { + ret + } +} diff --git a/userspace/vibix_libc/src/lib.rs b/userspace/vibix_libc/src/lib.rs new file mode 100644 index 00000000..6e7b4579 --- /dev/null +++ b/userspace/vibix_libc/src/lib.rs @@ -0,0 +1,22 @@ +//! `vibix_libc` -- C-ABI shim that exposes POSIX-like symbols backed by +//! vibix_abi syscall wrappers. +//! +//! Each `#[no_mangle] pub unsafe extern "C" fn` delegates to the raw syscall +//! via `vibix_abi::syscall!()`. On error, the function sets errno and returns +//! -1 (matching POSIX semantics). + +#![no_std] + +// The `syscall!` macro is used in submodules via `vibix_abi::syscall!`. + +pub use vibix_abi::errno::ERRNO; + +mod helpers; + +pub mod errno; +pub mod fcntl; +pub mod stat; +pub mod unistd; + +/// Re-export the defs crate types for convenience. +pub use vibix_abi; diff --git a/userspace/vibix_libc/src/stat.rs b/userspace/vibix_libc/src/stat.rs new file mode 100644 index 00000000..f52444ff --- /dev/null +++ b/userspace/vibix_libc/src/stat.rs @@ -0,0 +1,63 @@ +//! File status operations: stat, fstat, lstat, chmod, chown. + +use crate::helpers::syscall_ret; +use vibix_abi::syscall; + +// Syscall numbers (Linux x86_64) +const SYS_STAT: u64 = 4; +const SYS_FSTAT: u64 = 5; +const SYS_LSTAT: u64 = 6; +const SYS_CHMOD: u64 = 90; +const SYS_CHOWN: u64 = 92; + +/// Get file status by path. +/// +/// # Safety +/// `pathname` must be a valid null-terminated C string; `statbuf` must point +/// to a valid `struct stat`-sized buffer. +#[no_mangle] +pub unsafe extern "C" fn stat(pathname: *const u8, statbuf: *mut u8) -> i32 { + let ret = syscall!(SYS_STAT, pathname, statbuf); + syscall_ret(ret) as i32 +} + +/// Get file status by fd. +/// +/// # Safety +/// `statbuf` must point to a valid `struct stat`-sized buffer. +#[no_mangle] +pub unsafe extern "C" fn fstat(fd: i32, statbuf: *mut u8) -> i32 { + let ret = syscall!(SYS_FSTAT, fd, statbuf); + syscall_ret(ret) as i32 +} + +/// Get file status of a symlink (does not follow links). +/// +/// # Safety +/// `pathname` must be a valid null-terminated C string; `statbuf` must point +/// to a valid `struct stat`-sized buffer. +#[no_mangle] +pub unsafe extern "C" fn lstat(pathname: *const u8, statbuf: *mut u8) -> i32 { + let ret = syscall!(SYS_LSTAT, pathname, statbuf); + syscall_ret(ret) as i32 +} + +/// Change file permissions. +/// +/// # Safety +/// `pathname` must be a valid null-terminated C string. +#[no_mangle] +pub unsafe extern "C" fn chmod(pathname: *const u8, mode: u32) -> i32 { + let ret = syscall!(SYS_CHMOD, pathname, mode); + syscall_ret(ret) as i32 +} + +/// Change file owner and group. +/// +/// # Safety +/// `pathname` must be a valid null-terminated C string. +#[no_mangle] +pub unsafe extern "C" fn chown(pathname: *const u8, owner: u32, group: u32) -> i32 { + let ret = syscall!(SYS_CHOWN, pathname, owner, group); + syscall_ret(ret) as i32 +} diff --git a/userspace/vibix_libc/src/unistd.rs b/userspace/vibix_libc/src/unistd.rs new file mode 100644 index 00000000..2316f13f --- /dev/null +++ b/userspace/vibix_libc/src/unistd.rs @@ -0,0 +1,142 @@ +//! Unix-style operations: read, write, close, link, unlink, symlink, readlink, +//! mkdir, rmdir, rename, getcwd, chdir. + +use crate::helpers::syscall_ret; +use vibix_abi::syscall; + +// Syscall numbers (Linux x86_64) +const SYS_READ: u64 = 0; +const SYS_WRITE: u64 = 1; +const SYS_CLOSE: u64 = 3; +const SYS_GETCWD: u64 = 79; +const SYS_CHDIR: u64 = 80; +const SYS_RENAME: u64 = 82; +const SYS_MKDIR: u64 = 83; +const SYS_RMDIR: u64 = 84; +const SYS_LINK: u64 = 86; +const SYS_UNLINK: u64 = 87; +const SYS_SYMLINK: u64 = 88; +const SYS_READLINK: u64 = 89; + +/// Read from a file descriptor. +/// +/// # Safety +/// `buf` must be a valid pointer to a buffer of at least `count` bytes. +#[no_mangle] +pub unsafe extern "C" fn read(fd: i32, buf: *mut u8, count: usize) -> isize { + let ret = syscall!(SYS_READ, fd, buf, count); + syscall_ret(ret) as isize +} + +/// Write to a file descriptor. +/// +/// # Safety +/// `buf` must be a valid pointer to a buffer of at least `count` bytes. +#[no_mangle] +pub unsafe extern "C" fn write(fd: i32, buf: *const u8, count: usize) -> isize { + let ret = syscall!(SYS_WRITE, fd, buf, count); + syscall_ret(ret) as isize +} + +/// Close a file descriptor. +#[no_mangle] +pub unsafe extern "C" fn close(fd: i32) -> i32 { + let ret = syscall!(SYS_CLOSE, fd); + syscall_ret(ret) as i32 +} + +/// Create a hard link. +/// +/// # Safety +/// Both path pointers must be valid null-terminated C strings. +#[no_mangle] +pub unsafe extern "C" fn link(oldpath: *const u8, newpath: *const u8) -> i32 { + let ret = syscall!(SYS_LINK, oldpath, newpath); + syscall_ret(ret) as i32 +} + +/// Remove a file (unlink). +/// +/// # Safety +/// `pathname` must be a valid null-terminated C string. +#[no_mangle] +pub unsafe extern "C" fn unlink(pathname: *const u8) -> i32 { + let ret = syscall!(SYS_UNLINK, pathname); + syscall_ret(ret) as i32 +} + +/// Create a symbolic link. +/// +/// # Safety +/// Both path pointers must be valid null-terminated C strings. +#[no_mangle] +pub unsafe extern "C" fn symlink(target: *const u8, linkpath: *const u8) -> i32 { + let ret = syscall!(SYS_SYMLINK, target, linkpath); + syscall_ret(ret) as i32 +} + +/// Read the target of a symbolic link. +/// +/// # Safety +/// `pathname` must be a valid null-terminated C string; `buf` must point to +/// a buffer of at least `bufsiz` bytes. +#[no_mangle] +pub unsafe extern "C" fn readlink(pathname: *const u8, buf: *mut u8, bufsiz: usize) -> isize { + let ret = syscall!(SYS_READLINK, pathname, buf, bufsiz); + syscall_ret(ret) as isize +} + +/// Create a directory. +/// +/// # Safety +/// `pathname` must be a valid null-terminated C string. +#[no_mangle] +pub unsafe extern "C" fn mkdir(pathname: *const u8, mode: u32) -> i32 { + let ret = syscall!(SYS_MKDIR, pathname, mode); + syscall_ret(ret) as i32 +} + +/// Remove a directory. +/// +/// # Safety +/// `pathname` must be a valid null-terminated C string. +#[no_mangle] +pub unsafe extern "C" fn rmdir(pathname: *const u8) -> i32 { + let ret = syscall!(SYS_RMDIR, pathname); + syscall_ret(ret) as i32 +} + +/// Rename a file. +/// +/// # Safety +/// Both path pointers must be valid null-terminated C strings. +#[no_mangle] +pub unsafe extern "C" fn rename(oldpath: *const u8, newpath: *const u8) -> i32 { + let ret = syscall!(SYS_RENAME, oldpath, newpath); + syscall_ret(ret) as i32 +} + +/// Get current working directory. +/// +/// # Safety +/// `buf` must point to a buffer of at least `size` bytes. +#[no_mangle] +pub unsafe extern "C" fn getcwd(buf: *mut u8, size: usize) -> *mut u8 { + let ret = syscall!(SYS_GETCWD, buf, size); + if ret < 0 { + vibix_abi::errno::ERRNO.set((-ret) as i32); + core::ptr::null_mut() + } else { + buf + } +} + +/// Change working directory. +/// +/// # Safety +/// `path` must be a valid null-terminated C string. +#[no_mangle] +pub unsafe extern "C" fn chdir(path: *const u8) -> i32 { + let ret = syscall!(SYS_CHDIR, path); + syscall_ret(ret) as i32 +} diff --git a/userspace/vibix_libc_defs/Cargo.toml b/userspace/vibix_libc_defs/Cargo.toml new file mode 100644 index 00000000..c036fc24 --- /dev/null +++ b/userspace/vibix_libc_defs/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "vibix_libc_defs" +version.workspace = true +edition.workspace = true +authors.workspace = true +license.workspace = true +description = "Type definitions and constants for vibix matching the Linux x86_64 ABI layout" + +[lib] +name = "vibix_libc_defs" +path = "src/lib.rs" diff --git a/userspace/vibix_libc_defs/src/lib.rs b/userspace/vibix_libc_defs/src/lib.rs new file mode 100644 index 00000000..b329c574 --- /dev/null +++ b/userspace/vibix_libc_defs/src/lib.rs @@ -0,0 +1,356 @@ +//! `vibix_libc_defs` -- type definitions and constants for vibix matching the +//! Linux x86_64 ABI layout. +//! +//! This crate provides the struct layouts, type aliases, and constants that +//! the upstream `libc` and `nix` crates expect. All definitions match the +//! Linux x86_64 layout that vibix uses for its syscall ABI. + +#![no_std] +#![allow(non_camel_case_types)] + +// ============================================================================ +// Primitive type aliases (Linux x86_64) +// ============================================================================ + +pub type c_char = i8; +pub type c_short = i16; +pub type c_int = i32; +pub type c_long = i64; +pub type c_longlong = i64; +pub type c_uchar = u8; +pub type c_ushort = u16; +pub type c_uint = u32; +pub type c_ulong = u64; +pub type c_ulonglong = u64; +pub type c_void = core::ffi::c_void; + +pub type size_t = u64; +pub type ssize_t = i64; +pub type off_t = i64; +pub type pid_t = i32; +pub type uid_t = u32; +pub type gid_t = u32; +pub type mode_t = u32; +pub type dev_t = u64; +pub type ino_t = u64; +pub type nlink_t = u64; +pub type blksize_t = i64; +pub type blkcnt_t = i64; +pub type time_t = i64; +pub type suseconds_t = i64; +pub type clockid_t = i32; +pub type sighandler_t = size_t; + +// ============================================================================ +// struct stat (Linux x86_64 layout, 144 bytes) +// ============================================================================ + +#[repr(C)] +#[derive(Copy, Clone, Debug, Default)] +pub struct stat { + pub st_dev: dev_t, + pub st_ino: ino_t, + pub st_nlink: nlink_t, + pub st_mode: mode_t, + pub st_uid: uid_t, + pub st_gid: gid_t, + pub __pad0: c_int, + pub st_rdev: dev_t, + pub st_size: off_t, + pub st_blksize: blksize_t, + pub st_blocks: blkcnt_t, + pub st_atime: time_t, + pub st_atime_nsec: c_long, + pub st_mtime: time_t, + pub st_mtime_nsec: c_long, + pub st_ctime: time_t, + pub st_ctime_nsec: c_long, + pub __unused: [c_long; 3], +} + +// ============================================================================ +// struct timespec +// ============================================================================ + +#[repr(C)] +#[derive(Copy, Clone, Debug, Default)] +pub struct timespec { + pub tv_sec: time_t, + pub tv_nsec: c_long, +} + +// ============================================================================ +// struct timeval +// ============================================================================ + +#[repr(C)] +#[derive(Copy, Clone, Debug, Default)] +pub struct timeval { + pub tv_sec: time_t, + pub tv_usec: suseconds_t, +} + +// ============================================================================ +// struct sigaction (Linux x86_64) +// ============================================================================ + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct sigaction { + pub sa_handler: sighandler_t, + pub sa_flags: c_ulong, + pub sa_restorer: Option, + pub sa_mask: sigset_t, +} + +pub type sigset_t = c_ulong; + +// ============================================================================ +// struct dirent (getdents64 layout) +// ============================================================================ + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct dirent64 { + pub d_ino: ino_t, + pub d_off: off_t, + pub d_reclen: c_ushort, + pub d_type: c_uchar, + pub d_name: [c_char; 256], +} + +// ============================================================================ +// struct utsname +// ============================================================================ + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct utsname { + pub sysname: [c_char; 65], + pub nodename: [c_char; 65], + pub release: [c_char; 65], + pub version: [c_char; 65], + pub machine: [c_char; 65], + pub domainname: [c_char; 65], +} + +// ============================================================================ +// struct iovec +// ============================================================================ + +#[repr(C)] +#[derive(Copy, Clone, Debug)] +pub struct iovec { + pub iov_base: *mut c_void, + pub iov_len: size_t, +} + +// ============================================================================ +// Open flags (Linux x86_64) +// ============================================================================ + +pub const O_RDONLY: c_int = 0o0; +pub const O_WRONLY: c_int = 0o1; +pub const O_RDWR: c_int = 0o2; +pub const O_CREAT: c_int = 0o100; +pub const O_EXCL: c_int = 0o200; +pub const O_NOCTTY: c_int = 0o400; +pub const O_TRUNC: c_int = 0o1000; +pub const O_APPEND: c_int = 0o2000; +pub const O_NONBLOCK: c_int = 0o4000; +pub const O_DSYNC: c_int = 0o10000; +pub const O_DIRECTORY: c_int = 0o200000; +pub const O_NOFOLLOW: c_int = 0o400000; +pub const O_CLOEXEC: c_int = 0o2000000; + +pub const AT_FDCWD: c_int = -100; + +// ============================================================================ +// File mode bits +// ============================================================================ + +pub const S_IFMT: mode_t = 0o170000; +pub const S_IFSOCK: mode_t = 0o140000; +pub const S_IFLNK: mode_t = 0o120000; +pub const S_IFREG: mode_t = 0o100000; +pub const S_IFBLK: mode_t = 0o060000; +pub const S_IFDIR: mode_t = 0o040000; +pub const S_IFCHR: mode_t = 0o020000; +pub const S_IFIFO: mode_t = 0o010000; + +pub const S_ISUID: mode_t = 0o4000; +pub const S_ISGID: mode_t = 0o2000; +pub const S_ISVTX: mode_t = 0o1000; + +pub const S_IRWXU: mode_t = 0o700; +pub const S_IRUSR: mode_t = 0o400; +pub const S_IWUSR: mode_t = 0o200; +pub const S_IXUSR: mode_t = 0o100; + +pub const S_IRWXG: mode_t = 0o070; +pub const S_IRGRP: mode_t = 0o040; +pub const S_IWGRP: mode_t = 0o020; +pub const S_IXGRP: mode_t = 0o010; + +pub const S_IRWXO: mode_t = 0o007; +pub const S_IROTH: mode_t = 0o004; +pub const S_IWOTH: mode_t = 0o002; +pub const S_IXOTH: mode_t = 0o001; + +// ============================================================================ +// Errno constants +// ============================================================================ + +pub const EPERM: c_int = 1; +pub const ENOENT: c_int = 2; +pub const ESRCH: c_int = 3; +pub const EINTR: c_int = 4; +pub const EIO: c_int = 5; +pub const ENXIO: c_int = 6; +pub const E2BIG: c_int = 7; +pub const ENOEXEC: c_int = 8; +pub const EBADF: c_int = 9; +pub const ECHILD: c_int = 10; +pub const EAGAIN: c_int = 11; +pub const ENOMEM: c_int = 12; +pub const EACCES: c_int = 13; +pub const EFAULT: c_int = 14; +pub const ENOTBLK: c_int = 15; +pub const EBUSY: c_int = 16; +pub const EEXIST: c_int = 17; +pub const EXDEV: c_int = 18; +pub const ENODEV: c_int = 19; +pub const ENOTDIR: c_int = 20; +pub const EISDIR: c_int = 21; +pub const EINVAL: c_int = 22; +pub const ENFILE: c_int = 23; +pub const EMFILE: c_int = 24; +pub const ENOTTY: c_int = 25; +pub const ETXTBSY: c_int = 26; +pub const EFBIG: c_int = 27; +pub const ENOSPC: c_int = 28; +pub const ESPIPE: c_int = 29; +pub const EROFS: c_int = 30; +pub const EMLINK: c_int = 31; +pub const EPIPE: c_int = 32; +pub const EDOM: c_int = 33; +pub const ERANGE: c_int = 34; +pub const ENOSYS: c_int = 38; +pub const ENOTEMPTY: c_int = 39; +pub const ELOOP: c_int = 40; +pub const ENAMETOOLONG: c_int = 36; + +// ============================================================================ +// Syscall numbers (Linux x86_64) +// ============================================================================ + +pub const SYS_READ: u64 = 0; +pub const SYS_WRITE: u64 = 1; +pub const SYS_OPEN: u64 = 2; +pub const SYS_CLOSE: u64 = 3; +pub const SYS_STAT: u64 = 4; +pub const SYS_FSTAT: u64 = 5; +pub const SYS_LSTAT: u64 = 6; +pub const SYS_LSEEK: u64 = 8; +pub const SYS_MMAP: u64 = 9; +pub const SYS_MPROTECT: u64 = 10; +pub const SYS_MUNMAP: u64 = 11; +pub const SYS_IOCTL: u64 = 16; +pub const SYS_ACCESS: u64 = 21; +pub const SYS_DUP: u64 = 32; +pub const SYS_DUP2: u64 = 33; +pub const SYS_FORK: u64 = 57; +pub const SYS_EXECVE: u64 = 59; +pub const SYS_EXIT: u64 = 60; +pub const SYS_WAIT4: u64 = 61; +pub const SYS_KILL: u64 = 62; +pub const SYS_UNAME: u64 = 63; +pub const SYS_FCNTL: u64 = 72; +pub const SYS_GETCWD: u64 = 79; +pub const SYS_CHDIR: u64 = 80; +pub const SYS_RENAME: u64 = 82; +pub const SYS_MKDIR: u64 = 83; +pub const SYS_RMDIR: u64 = 84; +pub const SYS_LINK: u64 = 86; +pub const SYS_UNLINK: u64 = 87; +pub const SYS_SYMLINK: u64 = 88; +pub const SYS_READLINK: u64 = 89; +pub const SYS_CHMOD: u64 = 90; +pub const SYS_FCHMOD: u64 = 91; +pub const SYS_CHOWN: u64 = 92; +pub const SYS_FCHOWN: u64 = 93; +pub const SYS_LCHOWN: u64 = 94; +pub const SYS_GETUID: u64 = 102; +pub const SYS_GETGID: u64 = 104; +pub const SYS_GETEUID: u64 = 107; +pub const SYS_GETEGID: u64 = 108; +pub const SYS_OPENAT: u64 = 257; +pub const SYS_MKDIRAT: u64 = 258; +pub const SYS_NEWFSTATAT: u64 = 262; +pub const SYS_UNLINKAT: u64 = 263; +pub const SYS_RENAMEAT: u64 = 264; +pub const SYS_LINKAT: u64 = 265; +pub const SYS_SYMLINKAT: u64 = 266; +pub const SYS_READLINKAT: u64 = 267; +pub const SYS_FCHMODAT: u64 = 268; + +// ============================================================================ +// dirent d_type constants +// ============================================================================ + +pub const DT_UNKNOWN: c_uchar = 0; +pub const DT_FIFO: c_uchar = 1; +pub const DT_CHR: c_uchar = 2; +pub const DT_DIR: c_uchar = 4; +pub const DT_BLK: c_uchar = 6; +pub const DT_REG: c_uchar = 8; +pub const DT_LNK: c_uchar = 10; +pub const DT_SOCK: c_uchar = 12; + +// ============================================================================ +// Clock IDs +// ============================================================================ + +pub const CLOCK_REALTIME: clockid_t = 0; +pub const CLOCK_MONOTONIC: clockid_t = 1; +pub const CLOCK_PROCESS_CPUTIME_ID: clockid_t = 2; +pub const CLOCK_THREAD_CPUTIME_ID: clockid_t = 3; + +// ============================================================================ +// Helper macros for file type checks +// ============================================================================ + +#[inline] +pub const fn s_isreg(mode: mode_t) -> bool { + (mode & S_IFMT) == S_IFREG +} + +#[inline] +pub const fn s_isdir(mode: mode_t) -> bool { + (mode & S_IFMT) == S_IFDIR +} + +#[inline] +pub const fn s_islnk(mode: mode_t) -> bool { + (mode & S_IFMT) == S_IFLNK +} + +#[inline] +pub const fn s_ischr(mode: mode_t) -> bool { + (mode & S_IFMT) == S_IFCHR +} + +#[inline] +pub const fn s_isblk(mode: mode_t) -> bool { + (mode & S_IFMT) == S_IFBLK +} + +#[inline] +pub const fn s_isfifo(mode: mode_t) -> bool { + (mode & S_IFMT) == S_IFIFO +} + +#[inline] +pub const fn s_issock(mode: mode_t) -> bool { + (mode & S_IFMT) == S_IFSOCK +}