feat(stat): stat/mkdir/chmod and mode macros
This commit is contained in:
@@ -0,0 +1,32 @@
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "../internal/syscall.h"
|
||||
#include "stat_impl.h"
|
||||
|
||||
/*
|
||||
* chmod/chmodat over SYS_fchmodat (the *at form is the modern kernel ABI)
|
||||
* and fchmod over SYS_fchmod. chmod() passes AT_FDCWD and no flags; the
|
||||
* kernel silently ignores the file-type bits of mode and applies only the
|
||||
* permission + special bits.
|
||||
*/
|
||||
int
|
||||
fchmodat(int fd, const char *path, mode_t mode, int flag)
|
||||
{
|
||||
return syscall_ret(__syscall4(SYS_fchmodat, fd, (long)path, (long)mode, flag));
|
||||
}
|
||||
|
||||
int
|
||||
chmod(const char *path, mode_t mode)
|
||||
{
|
||||
return fchmodat(VLIBC_STAT_AT_FDCWD, path, mode, 0);
|
||||
}
|
||||
|
||||
int
|
||||
fchmod(int fd, mode_t mode)
|
||||
{
|
||||
return syscall_ret(__syscall2(SYS_fchmod, fd, (long)mode));
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "../internal/syscall.h"
|
||||
#include "stat_impl.h"
|
||||
|
||||
/*
|
||||
* chown family over SYS_fchownat (the *at form is the modern kernel ABI)
|
||||
* and fchown over SYS_fchown. A uid/gid of (uid_t)-1 (or (gid_t)-1) means
|
||||
* "leave unchanged" — the kernel checks for the all-ones value, so the
|
||||
* wrapper passes the arguments through as-is. chown() passes AT_FDCWD and
|
||||
* no flags; lchown() adds AT_SYMLINK_NOFOLLOW (its whole point: the link
|
||||
* itself is chowned, not the target).
|
||||
*/
|
||||
int
|
||||
fchownat(int fd, const char *path, uid_t owner, gid_t group, int flag)
|
||||
{
|
||||
return syscall_ret(__syscall5(SYS_fchownat, fd, (long)path, (long)owner, (long)group, flag));
|
||||
}
|
||||
|
||||
int
|
||||
chown(const char *path, uid_t owner, gid_t group)
|
||||
{
|
||||
return fchownat(VLIBC_STAT_AT_FDCWD, path, owner, group, 0);
|
||||
}
|
||||
|
||||
int
|
||||
lchown(const char *path, uid_t owner, gid_t group)
|
||||
{
|
||||
return fchownat(VLIBC_STAT_AT_FDCWD, path, owner, group, VLIBC_STAT_AT_SYMLINK_NOFOLLOW);
|
||||
}
|
||||
|
||||
int
|
||||
fchown(int fd, uid_t owner, gid_t group)
|
||||
{
|
||||
return syscall_ret(__syscall3(SYS_fchown, fd, (long)owner, (long)group));
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "../internal/syscall.h"
|
||||
#include "stat_impl.h"
|
||||
|
||||
/*
|
||||
* The stat family over SYS_newfstatat (the modern *at form; SYS_stat/
|
||||
* SYS_lstat exist only for compatibility) and SYS_fstat for the
|
||||
* descriptor-based form. stat()/lstat() are newfstatat on AT_FDCWD with
|
||||
* flag 0 / AT_SYMLINK_NOFOLLOW; the kernel fills the full 144-byte
|
||||
* struct stat pinned by the static assertions in <sys/stat.h>.
|
||||
*/
|
||||
int
|
||||
fstatat(int fd, const char *path, struct stat *buf, int flag)
|
||||
{
|
||||
return syscall_ret(__syscall4(SYS_newfstatat, fd, (long)path, (long)buf, flag));
|
||||
}
|
||||
|
||||
int
|
||||
stat(const char *path, struct stat *buf)
|
||||
{
|
||||
return fstatat(VLIBC_STAT_AT_FDCWD, path, buf, 0);
|
||||
}
|
||||
|
||||
int
|
||||
lstat(const char *path, struct stat *buf)
|
||||
{
|
||||
return fstatat(VLIBC_STAT_AT_FDCWD, path, buf, VLIBC_STAT_AT_SYMLINK_NOFOLLOW);
|
||||
}
|
||||
|
||||
int
|
||||
fstat(int fd, struct stat *buf)
|
||||
{
|
||||
return syscall_ret(__syscall2(SYS_fstat, fd, (long)buf));
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "../internal/syscall.h"
|
||||
|
||||
/*
|
||||
* mkdir over SYS_mkdir and mkdirat over SYS_mkdirat (the *at form takes
|
||||
* the directory fd, so mkdir() cannot simply delegate to it — SYS_mkdir
|
||||
* is the direct ABI). The kernel applies the process umask to mode.
|
||||
*/
|
||||
int
|
||||
mkdirat(int fd, const char *path, mode_t mode)
|
||||
{
|
||||
return syscall_ret(__syscall3(SYS_mkdirat, fd, (long)path, (long)mode));
|
||||
}
|
||||
|
||||
int
|
||||
mkdir(const char *path, mode_t mode)
|
||||
{
|
||||
return syscall_ret(__syscall2(SYS_mkdir, (long)path, (long)mode));
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "../internal/syscall.h"
|
||||
#include "stat_impl.h"
|
||||
|
||||
/*
|
||||
* mkfifo/mkfifoat over SYS_mknodat with the type bits fixed to S_IFIFO:
|
||||
* creating a FIFO is mknodat(..., mode | S_IFIFO, dev = 0). POSIX defines
|
||||
* mkfifo with no device argument, so the dev slot is always 0 here.
|
||||
*/
|
||||
int
|
||||
mkfifoat(int fd, const char *path, mode_t mode)
|
||||
{
|
||||
return syscall_ret(__syscall4(SYS_mknodat, fd, (long)path, (long)(mode | S_IFIFO), 0));
|
||||
}
|
||||
|
||||
int
|
||||
mkfifo(const char *path, mode_t mode)
|
||||
{
|
||||
return mkfifoat(VLIBC_STAT_AT_FDCWD, path, mode);
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "../internal/syscall.h"
|
||||
#include "stat_impl.h"
|
||||
|
||||
#if VLIBC_LEVEL_GE(2)
|
||||
|
||||
/*
|
||||
* mknod/mknodat over SYS_mknodat (XSI, level 2). The mode argument must
|
||||
* carry a file-type bit (S_IFIFO, S_IFCHR, S_IFBLK, S_IFREG, ...); dev is
|
||||
* the raw device id for the S_IFCHR/S_IFBLK cases and is otherwise
|
||||
* ignored by the kernel. Creating device nodes requires privilege
|
||||
* (CAP_MKNOD); creating a FIFO or a regular file does not.
|
||||
*/
|
||||
int
|
||||
mknodat(int fd, const char *path, mode_t mode, dev_t dev)
|
||||
{
|
||||
return syscall_ret(__syscall4(SYS_mknodat, fd, (long)path, (long)mode, (long)dev));
|
||||
}
|
||||
|
||||
int
|
||||
mknod(const char *path, mode_t mode, dev_t dev)
|
||||
{
|
||||
return mknodat(VLIBC_STAT_AT_FDCWD, path, mode, dev);
|
||||
}
|
||||
|
||||
#endif /* VLIBC_LEVEL_GE(2) */
|
||||
@@ -0,0 +1,22 @@
|
||||
#ifndef VLIBC_STAT_INTERNAL_H
|
||||
#define VLIBC_STAT_INTERNAL_H
|
||||
|
||||
/*
|
||||
* vlibc — internal constants for the stat wrappers (temporary).
|
||||
*
|
||||
* include/fcntl.h is owned by todo 21; until it lands, the *at wrappers
|
||||
* need AT_FDCWD and AT_SYMLINK_NOFOLLOW locally. These names carry the
|
||||
* VLIBC_STAT_ prefix so they cannot collide with the real constants todo
|
||||
* 21 will publish. The values are kernel UAPI facts
|
||||
* (asm-generic/fcntl.h), transcribed, not invented:
|
||||
*
|
||||
* AT_FDCWD -100, AT_SYMLINK_NOFOLLOW 0x100.
|
||||
*/
|
||||
|
||||
/* *at syscall base directory (kernel UAPI). */
|
||||
#define VLIBC_STAT_AT_FDCWD (-100)
|
||||
|
||||
/* *at flag: operate on the link itself, not its target (kernel UAPI). */
|
||||
#define VLIBC_STAT_AT_SYMLINK_NOFOLLOW 0x100
|
||||
|
||||
#endif /* VLIBC_STAT_INTERNAL_H */
|
||||
@@ -0,0 +1,18 @@
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "../internal/syscall.h"
|
||||
|
||||
/*
|
||||
* umask over SYS_umask. The kernel always returns the previous mask (even
|
||||
* through the syscall_ret error translation, which never fires here —
|
||||
* umask cannot fail), so no special handling is needed.
|
||||
*/
|
||||
mode_t
|
||||
umask(mode_t cmask)
|
||||
{
|
||||
return (mode_t)syscall_ret(__syscall1(SYS_umask, (long)cmask));
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "../internal/syscall.h"
|
||||
|
||||
/*
|
||||
* utimensat/futimens over SYS_utimensat. A NULL times array is passed
|
||||
* through unchanged: the kernel sets both timestamps to the current time
|
||||
* (the POSIX contract). futimens() is utimensat on the descriptor itself
|
||||
* — Linux applies utimensat(fd, NULL, times, 0) to the file referenced by
|
||||
* fd when the path is NULL, which is exactly futimens(fd, times).
|
||||
*/
|
||||
int
|
||||
utimensat(int fd, const char *path, const struct timespec times[2], int flag)
|
||||
{
|
||||
return syscall_ret(__syscall4(SYS_utimensat, fd, (long)path, (long)times, flag));
|
||||
}
|
||||
|
||||
int
|
||||
futimens(int fd, const struct timespec times[2])
|
||||
{
|
||||
return syscall_ret(__syscall4(SYS_utimensat, fd, 0, (long)times, 0));
|
||||
}
|
||||
Reference in New Issue
Block a user