feat(fcntl): fcntl/open flag handling
This commit is contained in:
@@ -0,0 +1,21 @@
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "../internal/syscall.h"
|
||||
|
||||
/*
|
||||
* creat ≡ open(path, O_WRONLY | O_CREAT | O_TRUNC, mode) (POSIX). Done as
|
||||
* a direct SYS_openat rather than a call to open(): the flag set is fixed,
|
||||
* the mode is always supplied, and this keeps src/fcntl self-contained
|
||||
* with no inter-object dependency on src/unistd. The kernel applies the
|
||||
* process umask to mode.
|
||||
*/
|
||||
int
|
||||
creat(const char *path, mode_t mode)
|
||||
{
|
||||
return syscall_ret(
|
||||
__syscall4(SYS_openat, AT_FDCWD, (long)path, O_WRONLY | O_CREAT | O_TRUNC, mode));
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "../internal/syscall.h"
|
||||
|
||||
/*
|
||||
* fcntl over SYS_fcntl (72). The third argument is read from the varargs
|
||||
* only for the commands POSIX defines one for (F_DUPFD, F_DUPFD_CLOEXEC,
|
||||
* F_SETFD, F_SETFL, the lock commands, and the owner/signal commands);
|
||||
* every other command passes 0, which the kernel ignores. Pointers (the
|
||||
* struct flock * of F_GETLK/F_SETLK/F_SETLKW/F_OFD_*) ride the varargs
|
||||
* slot as a long — on x86_64 long and void * share one GPR slot, so the
|
||||
* read is ABI-exact.
|
||||
*
|
||||
* F_DUPFD_CLOEXEC passes straight through: the x86_64 kernel has supported
|
||||
* it as a single native operation since 2.6.24, so no F_DUPFD + F_SETFD
|
||||
* fallback is needed. F_SETFL needs no O_LARGEFILE massaging on x86_64
|
||||
* (that is a 32-bit compat concern only).
|
||||
*/
|
||||
int
|
||||
fcntl(int fildes, int cmd, ...)
|
||||
{
|
||||
long arg = 0;
|
||||
va_list ap;
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
case F_DUPFD:
|
||||
case F_DUPFD_CLOEXEC:
|
||||
case F_SETFD:
|
||||
case F_SETFL:
|
||||
case F_GETLK:
|
||||
case F_SETLK:
|
||||
case F_SETLKW:
|
||||
case F_SETOWN:
|
||||
case F_SETSIG:
|
||||
case F_GETOWN_EX:
|
||||
case F_SETOWN_EX:
|
||||
case F_OFD_GETLK:
|
||||
case F_OFD_SETLK:
|
||||
case F_OFD_SETLKW:
|
||||
va_start(ap, cmd);
|
||||
arg = va_arg(ap, long);
|
||||
va_end(ap);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return syscall_ret(__syscall3(SYS_fcntl, fildes, cmd, arg));
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#include "../internal/syscall.h"
|
||||
|
||||
#if VLIBC_LEVEL_GE(2)
|
||||
|
||||
/*
|
||||
* lockf (XSI) over the fcntl record-lock commands: the kernel has no lockf
|
||||
* syscall, so every cmd maps to a struct flock operation on the range
|
||||
* [current offset, current offset + len) — the POSIX definition. len 0
|
||||
* means through EOF, which the kernel's l_len 0 convention already
|
||||
* expresses.
|
||||
*
|
||||
* The region start uses l_whence = SEEK_CUR with l_start = 0: the kernel
|
||||
* resolves the current file offset at syscall time, atomically with the
|
||||
* lock operation, so no lseek round-trip (and no TOCTOU window) is needed.
|
||||
*
|
||||
* F_TEST probes with F_GETLK using a read lock (the probe type that
|
||||
* conflicts with any exclusive lock): if the kernel reports no lock, or
|
||||
* the reported holder is this process itself (a different descriptor of
|
||||
* ours may hold it — POSIX says our own process never conflicts with
|
||||
* itself), the region is lockable. The pid is read via raw SYS_getpid;
|
||||
* the process wrappers are todo 20's and not a dependency of this file.
|
||||
*/
|
||||
int
|
||||
lockf(int fd, int cmd, off_t len)
|
||||
{
|
||||
struct flock lk;
|
||||
|
||||
lk.l_type = F_WRLCK;
|
||||
lk.l_whence = SEEK_CUR;
|
||||
lk.l_start = 0;
|
||||
lk.l_len = len;
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
case F_TEST:
|
||||
lk.l_type = F_RDLCK;
|
||||
if (fcntl(fd, F_GETLK, &lk) == -1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
if (lk.l_type == F_UNLCK || lk.l_pid == (pid_t)__syscall0(SYS_getpid))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
errno = EACCES;
|
||||
return -1;
|
||||
case F_ULOCK:
|
||||
lk.l_type = F_UNLCK;
|
||||
return fcntl(fd, F_SETLK, &lk);
|
||||
case F_LOCK:
|
||||
return fcntl(fd, F_SETLKW, &lk);
|
||||
case F_TLOCK:
|
||||
return fcntl(fd, F_SETLK, &lk);
|
||||
default:
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* VLIBC_LEVEL_GE(2) */
|
||||
@@ -0,0 +1,24 @@
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "../internal/syscall.h"
|
||||
|
||||
/*
|
||||
* posix_fadvise over SYS_fadvise64 (221). POSIX return convention, unlike
|
||||
* the rest of the family: an error NUMBER directly — 0 on success, else
|
||||
* the positive errno value (EBADF, ESPIPE, EINVAL, ...) — and errno is
|
||||
* left untouched. The raw syscall result is therefore mapped without the
|
||||
* syscall_ret() translation (which would write errno): a negative return
|
||||
* is negated, 0 stays 0. On x86_64 the syscall takes the offset as one
|
||||
* 64-bit value (fd, offset, len, advice) — no lo/hi split.
|
||||
*/
|
||||
int
|
||||
posix_fadvise(int fd, off_t offset, off_t len, int advice)
|
||||
{
|
||||
long r = __syscall4(SYS_fadvise64, fd, offset, len, advice);
|
||||
|
||||
return r < 0 ? (int)-r : 0;
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "../internal/syscall.h"
|
||||
|
||||
/*
|
||||
* posix_fallocate over SYS_fallocate (285). The kernel signature is
|
||||
* (fd, mode, offset, len); mode is 0 — POSIX exposes no FALLOC_FL_* flags,
|
||||
* so the plain allocate-and-grow operation is all there is (the kernel
|
||||
* rejects any other mode with EOPNOTSUPP/EINVAL, which is exactly what
|
||||
* POSIX wants). Same error-number return convention as posix_fadvise:
|
||||
* 0 on success, the positive errno value on failure, errno untouched —
|
||||
* so the raw result is negated directly, no syscall_ret().
|
||||
*/
|
||||
int
|
||||
posix_fallocate(int fd, off_t offset, off_t len)
|
||||
{
|
||||
long r = __syscall4(SYS_fallocate, fd, 0, offset, len);
|
||||
|
||||
return r < 0 ? (int)-r : 0;
|
||||
}
|
||||
Reference in New Issue
Block a user