mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-03-03 07:29:23 +00:00
Improve system call documentation
This change also introduces partial faccessat() support for zipos and makes some slight breaking changes in errno results. close() is fixed to use `EBADF` rather than `EINVAL` and we're now using `ENOTSUP` not `EOPNOTSUPP` to indicate that zipos doesn't support a system call yet
This commit is contained in:
parent
0b5f84dd20
commit
ad97775370
18 changed files with 273 additions and 67 deletions
|
@ -22,9 +22,14 @@
|
|||
/**
|
||||
* Checks if effective user can access path in particular ways.
|
||||
*
|
||||
* This is equivalent to saying:
|
||||
*
|
||||
* faccessat(AT_FDCWD, path, mode, 0);
|
||||
*
|
||||
* @param path is a filename or directory
|
||||
* @param mode can be R_OK, W_OK, X_OK, F_OK
|
||||
* @return 0 if ok, or -1 and sets errno
|
||||
* @return 0 if ok, or -1 w/ errno
|
||||
* @see faccessat() for further documentation
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int access(const char *path, int mode) {
|
||||
|
|
|
@ -32,17 +32,25 @@
|
|||
/**
|
||||
* Closes file descriptor.
|
||||
*
|
||||
* This function may be used for file descriptors returned by functions
|
||||
* like open, socket, accept, epoll_create, and landlock_create_ruleset.
|
||||
* This function releases resources returned by functions such as:
|
||||
*
|
||||
* This function should never be called twice for the same file
|
||||
* descriptor, regardless of whether or not an error happened. However
|
||||
* that doesn't mean the error should be ignored.
|
||||
* - openat()
|
||||
* - socket()
|
||||
* - accept()
|
||||
* - epoll_create()
|
||||
* - landlock_create_ruleset()
|
||||
*
|
||||
* This function should never be reattempted if an error is returned;
|
||||
* however, that doesn't mean the error should be ignored. This goes
|
||||
* against the conventional wisdom of looping on `EINTR`.
|
||||
*
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @error EINTR means a signal was received while closing in which case
|
||||
* close() does not need to be called again, since the fd will close
|
||||
* in the background
|
||||
* @raise EINTR if signal was delivered; do *not* retry
|
||||
* @raise EBADF if `fd` is negative or not open; however, an exception
|
||||
* is made by Cosmopolitan Libc for `close(-1)` which returns zero
|
||||
* and does nothing, in order to assist with code that may wish to
|
||||
* close the same resource multiple times without dirtying `errno`
|
||||
* @raise EIO if a low-level i/o error occurred
|
||||
* @asyncsignalsafe
|
||||
* @vforksafe
|
||||
*/
|
||||
|
@ -51,7 +59,7 @@ int close(int fd) {
|
|||
if (fd == -1) {
|
||||
rc = 0;
|
||||
} else if (fd < 0) {
|
||||
rc = einval();
|
||||
rc = ebadf();
|
||||
} else {
|
||||
// for performance reasons we want to avoid holding __fds_lock()
|
||||
// while sys_close() is happening. this leaves the kernel / libc
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/calls/struct/sigset.internal.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
|
@ -79,6 +80,7 @@ static void copy_file_range_init(void) {
|
|||
* @raise EXDEV if source and destination are on different filesystems
|
||||
* @raise EBADF if `infd` or `outfd` aren't open files or append-only
|
||||
* @raise EPERM if `fdout` refers to an immutable file on Linux
|
||||
* @raise ENOTSUP if `infd` or `outfd` is a zip file descriptor
|
||||
* @raise EINVAL if ranges overlap or `flags` is non-zero
|
||||
* @raise EFBIG if `setrlimit(RLIMIT_FSIZE)` is exceeded
|
||||
* @raise EFAULT if one of the pointers memory is bad
|
||||
|
@ -104,6 +106,8 @@ ssize_t copy_file_range(int infd, int64_t *opt_in_out_inoffset, int outfd,
|
|||
(opt_in_out_outoffset &&
|
||||
!__asan_is_valid(opt_in_out_outoffset, 8)))) {
|
||||
rc = efault();
|
||||
} else if (__isfdkind(infd, kFdZip) || __isfdkind(outfd, kFdZip)) {
|
||||
rc = enotsup();
|
||||
} else {
|
||||
rc = sys_copy_file_range(infd, opt_in_out_inoffset, outfd,
|
||||
opt_in_out_outoffset, uptobytes, flags);
|
||||
|
|
|
@ -21,20 +21,21 @@
|
|||
#include "libc/sysv/consts/o.h"
|
||||
|
||||
/**
|
||||
* Creates new file, returning open()'d file descriptor.
|
||||
* Creates file.
|
||||
*
|
||||
* This function is shorthand for:
|
||||
* This is equivalent to saying:
|
||||
*
|
||||
* open(file, O_CREAT | O_WRONLY | O_TRUNC, mode)
|
||||
* int fd = openat(AT_FDCWD, file, O_CREAT | O_WRONLY | O_TRUNC, mode);
|
||||
*
|
||||
* @param file is a UTF-8 string, which is truncated if it exists
|
||||
* @param mode is an octal user/group/other permission, e.g. 0755
|
||||
* @return a number registered with the system to track the open file,
|
||||
* which must be stored using a 64-bit type in order to support both
|
||||
* System V and Windows, and must be closed later on using close()
|
||||
* @see open(), touch()
|
||||
* @param file specifies filesystem path to create
|
||||
* @param mode is octal bits, e.g. 0644 usually
|
||||
* @return file descriptor, or -1 w/ errno
|
||||
* @see openat() for further documentation
|
||||
* @asyncsignalsafe
|
||||
* @restartable
|
||||
* @threadsafe
|
||||
* @vforksafe
|
||||
*/
|
||||
dontdiscard int creat(const char *file, uint32_t mode) {
|
||||
int creat(const char *file, uint32_t mode) {
|
||||
return openat(AT_FDCWD, file, O_CREAT | O_WRONLY | O_TRUNC, mode);
|
||||
}
|
||||
|
|
|
@ -32,15 +32,16 @@
|
|||
*
|
||||
* @param fd remains open afterwards
|
||||
* @return some arbitrary new number for fd
|
||||
* @raise EOPNOTSUPP if zipos file
|
||||
* @raise EBADF if fd isn't open
|
||||
* @raise EPERM if pledge() is in play without stdio
|
||||
* @raise ENOTSUP if `fd` is a zip file descriptor
|
||||
* @raise EBADF if `fd` is negative or not open
|
||||
* @asyncsignalsafe
|
||||
* @vforksafe
|
||||
*/
|
||||
int dup(int fd) {
|
||||
int rc;
|
||||
if (__isfdkind(fd, kFdZip)) {
|
||||
rc = eopnotsupp();
|
||||
rc = enotsup();
|
||||
} else if (!IsWindows()) {
|
||||
rc = sys_dup(fd);
|
||||
} else {
|
||||
|
|
|
@ -18,10 +18,10 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/calls/syscall-nt.internal.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
|
@ -38,16 +38,19 @@
|
|||
* @param newfd if already assigned, is silently closed beforehand;
|
||||
* unless it's equal to oldfd, in which case dup2() is a no-op
|
||||
* @return new file descriptor, or -1 w/ errno
|
||||
* @raise EBADF is oldfd isn't open
|
||||
* @raise EBADF is newfd negative or too big
|
||||
* @raise EPERM if pledge() is in play without stdio
|
||||
* @raise EMFILE if `RLIMIT_NOFILE` has been reached
|
||||
* @raise ENOTSUP if `oldfd` is on zip file system
|
||||
* @raise EINTR if a signal handler was called
|
||||
* @raise EBADF is `newfd` negative or too big
|
||||
* @raise EBADF is `oldfd` isn't open
|
||||
* @asyncsignalsafe
|
||||
* @vforksafe
|
||||
*/
|
||||
int dup2(int oldfd, int newfd) {
|
||||
int rc;
|
||||
if (__isfdkind(oldfd, kFdZip)) {
|
||||
rc = eopnotsupp();
|
||||
rc = enotsup();
|
||||
} else if (!IsWindows()) {
|
||||
rc = sys_dup2(oldfd, newfd);
|
||||
} else if (newfd < 0) {
|
||||
|
|
|
@ -38,11 +38,13 @@
|
|||
* @param flags may have O_CLOEXEC which is needed to preserve the
|
||||
* close-on-execve() state after file descriptor duplication
|
||||
* @return newfd on success, or -1 w/ errno
|
||||
* @raise EINVAL if flags has unsupported bits
|
||||
* @raise EINVAL if newfd equals oldfd
|
||||
* @raise EBADF is oldfd isn't open
|
||||
* @raise EBADF is newfd negative or too big
|
||||
* @raise ENOTSUP if `oldfd` is a zip file descriptor
|
||||
* @raise EPERM if pledge() is in play without stdio
|
||||
* @raise EINVAL if `flags` has unsupported bits
|
||||
* @raise EINTR if a signal handler was called
|
||||
* @raise EBADF is `newfd` negative or too big
|
||||
* @raise EINVAL if `newfd` equals oldfd
|
||||
* @raise EBADF is `oldfd` isn't open
|
||||
* @see dup(), dup2()
|
||||
*/
|
||||
int dup3(int oldfd, int newfd, int flags) {
|
||||
|
@ -52,7 +54,7 @@ int dup3(int oldfd, int newfd, int flags) {
|
|||
} else if (oldfd < 0 || newfd < 0) {
|
||||
rc = ebadf();
|
||||
} else if (__isfdkind(oldfd, kFdZip)) {
|
||||
rc = eopnotsupp();
|
||||
rc = enotsup();
|
||||
} else if (!IsWindows()) {
|
||||
rc = sys_dup3(oldfd, newfd, flags);
|
||||
} else {
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/syscall-nt.internal.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
|
@ -35,33 +36,42 @@
|
|||
* @param dirfd is normally AT_FDCWD but if it's an open directory and
|
||||
* file is a relative path, then file is opened relative to dirfd
|
||||
* @param path is a filename or directory
|
||||
* @param mode can be R_OK, W_OK, X_OK, F_OK
|
||||
* @param flags can have AT_EACCESS, AT_SYMLINK_NOFOLLOW
|
||||
* @note on Linux flags is only supported on Linux 5.8+
|
||||
* @param amode can be `R_OK`, `W_OK`, `X_OK`, or `F_OK`
|
||||
* @param flags can have `AT_EACCESS` and/or `AT_SYMLINK_NOFOLLOW`
|
||||
* @return 0 if ok, or -1 and sets errno
|
||||
* @raise EINVAL if `mode` has bad value
|
||||
* @raise EPERM if pledge() is in play without rpath promise
|
||||
* @raise EACCES if access for requested `mode` would be denied
|
||||
* @raise ENOTDIR if a directory component in `path` exists as non-directory
|
||||
* @raise ENOENT if component of `path` doesn't exist or `path` is empty
|
||||
* @raise ENOTSUP if `path` is a zip file and `dirfd` isn't `AT_FDCWD`
|
||||
* @note on Linux `flags` is only supported on Linux 5.8+
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int faccessat(int dirfd, const char *path, int mode, uint32_t flags) {
|
||||
int faccessat(int dirfd, const char *path, int amode, uint32_t flags) {
|
||||
int e, rc;
|
||||
if (IsAsan() && !__asan_is_valid(path, 1)) {
|
||||
struct ZiposUri zipname;
|
||||
if (!path || (IsAsan() && !__asan_is_valid(path, 1))) {
|
||||
rc = efault();
|
||||
} else if (_weaken(__zipos_notat) &&
|
||||
_weaken(__zipos_notat)(dirfd, path) == -1) {
|
||||
rc = -1; /* TODO(jart): implement me */
|
||||
} else if (__isfdkind(dirfd, kFdZip)) {
|
||||
rc = enotsup();
|
||||
} else if (_weaken(__zipos_open) &&
|
||||
_weaken(__zipos_parseuri)(path, &zipname) != -1) {
|
||||
rc = _weaken(__zipos_access)(&zipname, amode);
|
||||
} else if (!IsWindows()) {
|
||||
e = errno;
|
||||
if (!flags) goto NoFlags;
|
||||
if ((rc = sys_faccessat2(dirfd, path, mode, flags)) == -1) {
|
||||
if ((rc = sys_faccessat2(dirfd, path, amode, flags)) == -1) {
|
||||
if (errno == ENOSYS) {
|
||||
errno = e;
|
||||
NoFlags:
|
||||
rc = sys_faccessat(dirfd, path, mode, flags);
|
||||
rc = sys_faccessat(dirfd, path, amode, flags);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
rc = sys_faccessat_nt(dirfd, path, mode, flags);
|
||||
rc = sys_faccessat_nt(dirfd, path, amode, flags);
|
||||
}
|
||||
STRACE("faccessat(%s, %#s, %#o, %#x) → %d% m", DescribeDirfd(dirfd), path,
|
||||
mode, flags, rc);
|
||||
amode, flags, rc);
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
* @param path must exist
|
||||
* @param mode contains octal flags (base 8)
|
||||
* @param flags can have `AT_SYMLINK_NOFOLLOW`
|
||||
* @raise ENOTSUP if `dirfd` or `path` use zip file system
|
||||
* @errors ENOENT, ENOTDIR, ENOSYS
|
||||
* @asyncsignalsafe
|
||||
* @see fchmod()
|
||||
|
@ -47,7 +48,7 @@ int fchmodat(int dirfd, const char *path, uint32_t mode, int flags) {
|
|||
rc = efault();
|
||||
} else if (_weaken(__zipos_notat) &&
|
||||
(rc = __zipos_notat(dirfd, path)) == -1) {
|
||||
rc = eopnotsupp();
|
||||
rc = enotsup();
|
||||
} else if (!IsWindows()) {
|
||||
rc = sys_fchmodat(dirfd, path, mode, flags);
|
||||
} else {
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
* @param gid is group id, or -1 to not change
|
||||
* @param flags can have AT_SYMLINK_NOFOLLOW, etc.
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @raise ENOTSUP if `dirfd` or `path` use zip file system
|
||||
* @see chown(), lchown() for shorthand notation
|
||||
* @see /etc/passwd for user ids
|
||||
* @see /etc/group for group ids
|
||||
|
@ -46,7 +47,7 @@ int fchownat(int dirfd, const char *path, uint32_t uid, uint32_t gid,
|
|||
rc = efault();
|
||||
} else if (_weaken(__zipos_notat) &&
|
||||
(rc = __zipos_notat(dirfd, path)) == -1) {
|
||||
STRACE("zipos fchownat not supported yet");
|
||||
rc = enotsup();
|
||||
} else {
|
||||
rc = sys_fchownat(dirfd, path, uid, gid, flags);
|
||||
}
|
||||
|
|
|
@ -24,6 +24,6 @@
|
|||
textwindows int sys_getsetpriority_nt(int which, unsigned who, int value,
|
||||
int (*impl)(int)) {
|
||||
if (which != PRIO_PROCESS && which != PRIO_PGRP) return einval();
|
||||
if (who && who != getpid() && who != gettid()) return eopnotsupp();
|
||||
if (who && who != getpid() && who != gettid()) return esrch();
|
||||
return impl(value);
|
||||
}
|
||||
|
|
|
@ -22,16 +22,17 @@
|
|||
/**
|
||||
* Opens file.
|
||||
*
|
||||
* @param file is a UTF-8 string, preferably relative w/ forward slashes
|
||||
* @param flags should be O_RDONLY, O_WRONLY, or O_RDWR, and can be or'd
|
||||
* with O_CREAT, O_TRUNC, O_APPEND, O_EXCL, O_CLOEXEC, O_TMPFILE
|
||||
* @param mode is an octal user/group/other permission signifier, that's
|
||||
* ignored if O_CREAT or O_TMPFILE weren't passed
|
||||
* @return number needing close(), or -1 w/ errno
|
||||
* @asyncsignalsafe (zip files may have issues)
|
||||
* @vforksafe (raises error if zip file)
|
||||
* This is equivalent to saying:
|
||||
*
|
||||
* int fd = openat(AT_FDCWD, file, flags, ...);
|
||||
*
|
||||
* @param file specifies filesystem path to open
|
||||
* @return file descriptor, or -1 w/ errno
|
||||
* @see openat() for further documentation
|
||||
* @asyncsignalsafe
|
||||
* @restartable
|
||||
* @threadsafe
|
||||
* @vforksafe
|
||||
*/
|
||||
int open(const char *file, int flags, ...) {
|
||||
va_list va;
|
||||
|
|
|
@ -36,17 +36,113 @@
|
|||
/**
|
||||
* Opens file.
|
||||
*
|
||||
* @param dirfd is normally AT_FDCWD but if it's an open directory and
|
||||
* file is a relative path, then file is opened relative to dirfd
|
||||
* @param file is a UTF-8 string, preferably relative w/ forward slashes
|
||||
* @param flags should be O_RDONLY, O_WRONLY, or O_RDWR, and can be or'd
|
||||
* with O_CREAT, O_TRUNC, O_APPEND, O_EXCL, O_CLOEXEC, O_TMPFILE
|
||||
* @param mode is an octal user/group/other permission signifier, that's
|
||||
* ignored if O_CREAT or O_TMPFILE weren't passed
|
||||
* @return number needing close(), or -1 w/ errno
|
||||
* @asyncsignalsafe (zip files may have issues)
|
||||
* @vforksafe (raises error if zip file)
|
||||
* Here's an example of how a file can be created:
|
||||
*
|
||||
* int fd = openat(AT_FDCWD, "hi.txt", O_CREAT | O_WRONLY | O_TRUNC, 0644);
|
||||
* write(fd, "hello\n", 6);
|
||||
* close(fd);
|
||||
*
|
||||
* Here's an example of how that file could read back into memory:
|
||||
*
|
||||
* char data[513] = {0};
|
||||
* int fd = openat(AT_FDCWD, "hi.txt", O_RDONLY);
|
||||
* read(fd, data, 512);
|
||||
* close(fd);
|
||||
* assert(!strcmp(data, "hello\n"));
|
||||
*
|
||||
* If your main() source file has this statement:
|
||||
*
|
||||
* STATIC_YOINK("zip_uri_support");
|
||||
*
|
||||
* Then you can read zip assets by adding a `"/zip/..."` prefix to `file`, e.g.
|
||||
*
|
||||
* // run `zip program.com hi.txt` beforehand
|
||||
* openat(AT_FDCWD, "/zip/hi.txt", O_RDONLY);
|
||||
*
|
||||
* @param dirfd is normally `AT_FDCWD` but if it's an open directory and
|
||||
* `file` names a relative path then it's opened relative to `dirfd`
|
||||
* @param file is a UTF-8 string naming filesystem entity, e.g. `foo/bar.txt`,
|
||||
* which on Windows is bludgeoned into a WIN32 path automatically, e.g.
|
||||
* - `foo/bar.txt` becomes `foo\bar.txt`
|
||||
* - `/tmp/...` becomes whatever GetTempPath() is
|
||||
* - `\\...` or `//...` is passed through to WIN32 unchanged
|
||||
* - `/c/foo` or `\c\foo` becomes `\\?\c:\foo`
|
||||
* - `c:/foo` or `c:\foo` becomes `\\?\c:\foo`
|
||||
* - `/D` becomes `\\?\D:\`
|
||||
* @param flags must have one of the following under the `O_ACCMODE` bits:
|
||||
* - `O_RDONLY` to open `file` for reading only
|
||||
* - `O_WRONLY` to open `file` for writing
|
||||
* - `O_RDWR` to open `file` for reading and writing
|
||||
* The following may optionally be bitwise or'd into `flags`:
|
||||
* - `O_CREAT` create file if it doesn't exist
|
||||
* - `O_TRUNC` automatic `ftruncate(fd,0)` if exists
|
||||
* - `O_CLOEXEC` automatic close() upon execve()
|
||||
* - `O_EXCL` exclusive access (see below)
|
||||
* - `O_APPEND` open file for appending only
|
||||
* - `O_EXEC` open file for execution only; see fexecve()
|
||||
* - `O_NOCTTY` prevents `file` possibly becoming controlling terminal
|
||||
* - `O_NONBLOCK` asks read/write to fail with `EAGAIN` rather than block
|
||||
* - `O_DIRECT` it's complicated (not supported on Apple and OpenBSD)
|
||||
* - `O_DIRECTORY` useful for stat'ing (hint on UNIX but required on NT)
|
||||
* - `O_NOFOLLOW` fail if it's a symlink (zero on Windows)
|
||||
* - `O_DSYNC` it's complicated (zero on non-Linux/Apple)
|
||||
* - `O_RSYNC` it's complicated (zero on non-Linux/Apple)
|
||||
* - `O_VERIFY` it's complicated (zero on non-FreeBSD)
|
||||
* - `O_SHLOCK` it's complicated (zero on non-BSD)
|
||||
* - `O_EXLOCK` it's complicated (zero on non-BSD)
|
||||
* - `O_PATH` open only for metadata (Linux 2.6.39+ otherwise zero)
|
||||
* - `O_NOATIME` don't record access time (zero on non-Linux)
|
||||
* - `O_RANDOM` hint random access intent (zero on non-Windows)
|
||||
* - `O_SEQUENTIAL` hint sequential access intent (zero on non-Windows)
|
||||
* - `O_COMPRESSED` ask fs to abstract compression (zero on non-Windows)
|
||||
* - `O_INDEXED` turns on that slow performance (zero on non-Windows)
|
||||
* - `O_TMPFILE` should not be used; use tmpfd() or tmpfile() instead
|
||||
* There are three regular combinations for the above flags:
|
||||
* - `O_RDONLY`: Opens existing file for reading. If it doesn't
|
||||
* exist then nil is returned and errno will be `ENOENT` (or in
|
||||
* some other cases `ENOTDIR`).
|
||||
* - `O_WRONLY|O_CREAT|O_TRUNC`: Creates file. If it already
|
||||
* exists, then the existing copy is destroyed and the opened
|
||||
* file will start off with a length of zero. This is the
|
||||
* behavior of the traditional creat() system call.
|
||||
* - `O_WRONLY|O_CREAT|O_EXCL`: Create file only if doesn't exist
|
||||
* already. If it does exist then `nil` is returned along with
|
||||
* `errno` set to `EEXIST`.
|
||||
* @param mode is an octal user/group/other permission signifier that's
|
||||
* ignored if `O_CREAT` isn't passed in `flags`; when creating files
|
||||
* you'll usually want `mode` to be `0644` which enables global read
|
||||
* and only permits the owner to write; or when creating executables
|
||||
* you'll usually want `mode` to be `0755` which is the same, except
|
||||
* the executable bit is set thrice too
|
||||
* @return file descriptor (which needs to be close()'d), or -1 w/ errno
|
||||
* @raise EPERM if pledge() is in play w/o appropriate rpath/wpath/cpath
|
||||
* @raise EACCES if unveil() is in play and didn't unveil your `file` path
|
||||
* @raise EACCES if we don't have permission to search a component of `file`
|
||||
* @raise EACCES if file exists but requested `flags & O_ACCMODE` was denied
|
||||
* @raise EACCES if file doesn't exist and parent dir lacks write permissions
|
||||
* @raise EACCES if `O_TRUNC` was specified in `flags` but writing was denied
|
||||
* @raise ENOTSUP if `file` is on zip file system and `dirfd` isn't `AT_FDCWD`
|
||||
* @raise ENOTDIR if a directory component in `file` exists as non-directory
|
||||
* @raise ENOTDIR if `file` is relative and `dirfd` isn't an open directory
|
||||
* @raise EROFS when writing is requested w/ `file` on read-only filesystem
|
||||
* @raise ENAMETOOLONG if symlink-resolved `file` length exceeds `PATH_MAX`
|
||||
* @raise ENAMETOOLONG if component in `file` exists longer than `NAME_MAX`
|
||||
* @raise ENOTSUP if `file` is on zip file system and process is vfork()'d
|
||||
* @raise ENOSPC if file system is full when `file` would be `O_CREAT`ed
|
||||
* @raise EINTR if we needed to block and a signal was delivered instead
|
||||
* @raise ENOENT if `file` doesn't exist when `O_CREAT` isn't in `flags`
|
||||
* @raise ENOENT if `file` points to a string that's empty
|
||||
* @raise ENOMEM if insufficient memory was available
|
||||
* @raise EMFILE if `RLIMIT_NOFILE` has been reached
|
||||
* @raise EOPNOTSUPP if `file` names a named socket
|
||||
* @raise ETXTBSY if writing is requested on `file` that's being executed
|
||||
* @raise ELOOP if `flags` had `O_NOFOLLOW` and `file` is a symbolic link
|
||||
* @raise ELOOP if a loop was detected resolving components of `file`
|
||||
* @raise EISDIR if writing is requested and `file` names a directory
|
||||
* @asyncsignalsafe
|
||||
* @restartable
|
||||
* @threadsafe
|
||||
* @vforksafe
|
||||
*/
|
||||
int openat(int dirfd, const char *file, int flags, ...) {
|
||||
int rc;
|
||||
|
@ -63,7 +159,7 @@ int openat(int dirfd, const char *file, int flags, ...) {
|
|||
if (!__vforked && dirfd == AT_FDCWD) {
|
||||
rc = _weaken(__zipos_open)(&zipname, flags, mode);
|
||||
} else {
|
||||
rc = eopnotsupp(); /* TODO */
|
||||
rc = enotsup(); /* TODO */
|
||||
}
|
||||
} else if (!IsWindows() && !IsMetal()) {
|
||||
rc = sys_openat(dirfd, file, flags, mode);
|
||||
|
@ -73,7 +169,7 @@ int openat(int dirfd, const char *file, int flags, ...) {
|
|||
rc = sys_open_nt(dirfd, file, flags, mode);
|
||||
}
|
||||
} else {
|
||||
rc = eopnotsupp(); /* TODO */
|
||||
rc = enotsup(); /* TODO */
|
||||
}
|
||||
} else {
|
||||
rc = efault();
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
|
@ -64,6 +65,7 @@ static void splice_init(void) {
|
|||
* used as both an input and output parameter for pwrite() behavior
|
||||
* @return number of bytes transferred, 0 on input end, or -1 w/ errno
|
||||
* @raise EBADF if `infd` or `outfd` aren't open files or append-only
|
||||
* @raise ENOTSUP if `infd` or `outfd` is a zip file descriptor
|
||||
* @raise ESPIPE if an offset arg was specified for a pipe fd
|
||||
* @raise EINVAL if offset was given for non-seekable device
|
||||
* @raise EINVAL if file system doesn't support splice()
|
||||
|
@ -85,6 +87,8 @@ ssize_t splice(int infd, int64_t *opt_in_out_inoffset, int outfd,
|
|||
(opt_in_out_outoffset &&
|
||||
!__asan_is_valid(opt_in_out_outoffset, 8)))) {
|
||||
rc = efault();
|
||||
} else if (__isfdkind(infd, kFdZip) || __isfdkind(outfd, kFdZip)) {
|
||||
rc = enotsup();
|
||||
} else {
|
||||
rc = sys_splice(infd, opt_in_out_inoffset, outfd, opt_in_out_outoffset,
|
||||
uptobytes, flags);
|
||||
|
|
67
libc/zipos/access.c
Normal file
67
libc/zipos/access.c
Normal file
|
@ -0,0 +1,67 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2022 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/sysv/consts/ok.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/zip.h"
|
||||
#include "libc/zipos/zipos.internal.h"
|
||||
|
||||
// TODO: this should check parent directory components
|
||||
|
||||
/**
|
||||
* Checks access metadata in αcτµαlly pδrταblε εxεcµταblε object store.
|
||||
*
|
||||
* @param uri is obtained via __zipos_parseuri()
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int __zipos_access(const struct ZiposUri *name, int amode) {
|
||||
ssize_t cf;
|
||||
int rc, mode;
|
||||
struct Zipos *z;
|
||||
if ((z = __zipos_get()) && (cf = __zipos_find(z, name)) != -1) {
|
||||
mode = GetZipCfileMode(z->map + cf);
|
||||
if (amode == F_OK) {
|
||||
rc = 0;
|
||||
} else if (amode == R_OK) {
|
||||
if (mode & 0444) {
|
||||
rc = 0;
|
||||
} else {
|
||||
rc = eacces();
|
||||
}
|
||||
} else if (amode == W_OK) {
|
||||
if (mode & 0222) {
|
||||
rc = 0;
|
||||
} else {
|
||||
rc = eacces();
|
||||
}
|
||||
} else if (amode == X_OK) {
|
||||
if (mode & 0111) {
|
||||
rc = 0;
|
||||
} else {
|
||||
rc = eacces();
|
||||
}
|
||||
} else {
|
||||
rc = einval();
|
||||
}
|
||||
} else {
|
||||
rc = enoent();
|
||||
}
|
||||
return rc;
|
||||
}
|
|
@ -27,6 +27,7 @@
|
|||
.yoink __zipos_close
|
||||
.yoink __zipos_fcntl
|
||||
.yoink __zipos_fstat
|
||||
.yoink __zipos_access
|
||||
.yoink __zipos_lseek
|
||||
.yoink __zipos_open
|
||||
.yoink __zipos_parseuri
|
||||
|
|
|
@ -37,6 +37,7 @@ void __zipos_free(struct Zipos *, struct ZiposHandle *) hidden;
|
|||
ssize_t __zipos_parseuri(const char *, struct ZiposUri *) hidden;
|
||||
ssize_t __zipos_find(struct Zipos *, const struct ZiposUri *);
|
||||
int __zipos_open(const struct ZiposUri *, unsigned, int) hidden;
|
||||
int __zipos_access(const struct ZiposUri *, int) hidden;
|
||||
int __zipos_stat(const struct ZiposUri *, struct stat *) hidden;
|
||||
int __zipos_fstat(const struct ZiposHandle *, struct stat *) hidden;
|
||||
int __zipos_stat_impl(struct Zipos *, size_t, struct stat *) hidden;
|
||||
|
|
Loading…
Add table
Reference in a new issue