feat(unistd): file I/O syscall wrappers

This commit is contained in:
2026-09-05 01:05:45 -04:00
parent 34408380f0
commit 7b11452b87
14 changed files with 1019 additions and 0 deletions
+214
View File
@@ -0,0 +1,214 @@
#ifndef VLIBC_UNISTD_H
#define VLIBC_UNISTD_H
/*
* vlibc — <unistd.h>.
*
* File descriptors, file I/O, and the access/whence symbolic constants
* (POSIX.1-2008). Every function here is an unbuffered pass-through to the
* kernel: failures are reported as -1 (or the fd/offset on success) with
* errno set by the syscall layer.
*
* Level 1 (onlyposix): read, write, pread, pwrite, open, openat, close,
* lseek, dup, dup2, pipe, fsync, fdatasync, ftruncate,
* sync, access, faccessat.
* Level 2 (muslmimic): dup3, pipe2 (Linux extensions), truncate (XSI),
* lseek64 (glibc LFS alias of lseek on x86_64).
*
* The open-flag constants (O_RDONLY, O_CREAT, O_CLOEXEC, ...) belong to
* <fcntl.h> and are deliberately not defined here; the oflag arguments below
* are plain int and take their values from that header. The optional mode
* argument of open/openat is a mode_t supplied only when oflag contains
* O_CREAT or O_TMPFILE.
*
* None of these declarations carry an intent attribute: every function
* performs I/O with side effects and reports failures through errno, so
* const/pure would be unsound.
*/
#include <vlibc/features.h>
#include <stddef.h>
#include <sys/types.h>
#ifdef __cplusplus
extern "C" {
#endif
/* Level 1 (POSIX base). */
/* Access-check modes for access() and faccessat(). */
#define F_OK 0 /* existence only */
#define X_OK 1 /* execute (search for a directory) */
#define W_OK 2 /* write */
#define R_OK 4 /* read */
/* whence values for lseek() and lseek64() (also defined by <stdio.h>). */
#define SEEK_SET 0 /* from the beginning of the file */
#define SEEK_CUR 1 /* from the current position */
#define SEEK_END 2 /* from the end of the file */
/*
* Read up to nbyte bytes from fildes into buf and return the number of
* bytes read, 0 at end of file, or -1 with errno set on error. Unbuffered.
*/
ssize_t
read(int fildes, void *buf, size_t nbyte);
/*
* Write up to nbyte bytes from buf to fildes and return the number of
* bytes written, or -1 with errno set on error. Unbuffered.
*/
ssize_t
write(int fildes, const void *buf, size_t nbyte);
/*
* Read nbyte bytes from fildes starting at offset, without changing the
* file position; return the number of bytes read, or -1 with errno set.
*/
ssize_t
pread(int fildes, void *buf, size_t nbyte, off_t offset);
/*
* Write nbyte bytes from buf to fildes starting at offset, without
* changing the file position; return the number of bytes written, or -1
* with errno set.
*/
ssize_t
pwrite(int fildes, const void *buf, size_t nbyte, off_t offset);
/*
* Open path with the oflag access mode (from <fcntl.h>) and return a file
* descriptor, or -1 with errno set. A mode argument is required — and read
* from the varargs — only when oflag contains O_CREAT or O_TMPFILE.
*/
int
open(const char *path, int oflag, ...);
/*
* Like open(), but path is relative to the directory named by fd (use
* AT_FDCWD from <fcntl.h> for the current working directory). The mode
* varargs rule is the same as open().
*/
int
openat(int fd, const char *path, int oflag, ...);
/*
* Close the file descriptor fildes; return 0, or -1 with errno set.
*/
int
close(int fildes);
/*
* Reposition the file offset of fildes to offset per whence (SEEK_SET,
* SEEK_CUR, SEEK_END) and return the resulting offset, or (off_t)-1 with
* errno set. The full 64-bit offset is returned; errno is untouched on
* success.
*/
off_t
lseek(int fildes, off_t offset, int whence);
/*
* Duplicate fildes to the lowest-numbered free descriptor; return it, or
* -1 with errno set. The copy shares the file description (position,
* flags, locks) with the original.
*/
int
dup(int fildes);
/*
* Duplicate fildes onto fildes2, closing fildes2 first if it was open;
* return fildes2, or -1 with errno set. dup2(f, f) returns f without
* doing anything (POSIX).
*/
int
dup2(int fildes, int fildes2);
/*
* Create a pipe: fildes[0] becomes the read end, fildes[1] the write end.
* Return 0, or -1 with errno set. No descriptor flags are set (unlike
* pipe2, this is plain POSIX).
*/
int
pipe(int fildes[2]);
/*
* Flush all buffered modifications of fildes and its metadata to stable
* storage; return 0, or -1 with errno set.
*/
int
fsync(int fildes);
/*
* Like fsync(), but may skip the metadata work needed only to preserve
* file contents; return 0, or -1 with errno set.
*/
int
fdatasync(int fildes);
/*
* Truncate fildes to length bytes; return 0, or -1 with errno set.
*/
int
ftruncate(int fildes, off_t length);
/*
* Flush all filesystem caches to stable storage. Returns nothing.
*/
void
sync(void);
/*
* Check accessibility of path under amode (R_OK, W_OK, X_OK, F_OK); return
* 0, or -1 with errno set. Uses the real IDs of the calling process.
*/
int
access(const char *path, int amode);
/*
* Like access(), but path is relative to the directory named by fd (use
* AT_FDCWD for the current working directory) and flag may hold
* AT_EACCESS; return 0, or -1 with errno set.
*/
int
faccessat(int fd, const char *path, int amode, int flag);
#if VLIBC_LEVEL_GE(2)
/* Level 2 (muslmimic): Linux extensions + XSI. */
/*
* Like dup2(), but with descriptor flags (O_CLOEXEC from <fcntl.h>) applied
* atomically; return fildes2, or -1 with errno set. Linux-specific.
*/
int
dup3(int fildes, int fildes2, int flags);
/*
* Like pipe(), but with descriptor flags (e.g. O_CLOEXEC) applied
* atomically; return 0, or -1 with errno set. Linux-specific.
*/
int
pipe2(int fildes[2], int flags);
/*
* Truncate the file named by path to length bytes; return 0, or -1 with
* errno set. XSI.
*/
int
truncate(const char *path, off_t length);
/*
* glibc LFS alias of lseek(): on x86_64 the LFS and non-LFS off_t are
* identical (both 64-bit), so this simply calls lseek(). Provided for
* source compatibility only.
*/
off_t
lseek64(int fildes, off_t offset, int whence);
#endif /* VLIBC_LEVEL_GE(2) */
#ifdef __cplusplus
}
#endif
#endif /* VLIBC_UNISTD_H */