Make improvements

- Invent openatemp() API
- Invent O_UNLINK open flag
- Introduce getenv_secure() API
- Remove `git pull` from cosmocc
- Fix utimes() when path is NULL
- Fix mktemp() to never return NULL
- Fix utimensat() UTIME_OMIT on XNU
- Improve utimensat() code for RHEL5
- Turn `argv[0]` C:/ to /C/ on Windows
- Introduce tmpnam() and tmpnam_r() APIs
- Fix more const issues with internal APIs
- Permit utimes() on WIN32 in O_RDONLY mode
- Fix fdopendir() to check fd is a directory
- Fix recent crash regression in landlock make
- Fix futimens(AT_FDCWD, NULL) to return EBADF
- Use workaround so `make -j` doesn't fork bomb
- Rename dontdiscard to __wur (just like glibc)
- Fix st_size for WIN32 symlinks containing UTF-8
- Introduce stdio ext APIs needed by GNU coreutils
- Fix lstat() on WIN32 for symlinks to directories
- Move some constants from normalize.inc to limits.h
- Fix segv with memchr() and memcmp() overlapping page
- Implement POSIX fflush() behavior for reader streams
- Implement AT_SYMLINK_NOFOLLOW for utimensat() on WIN32
- Don't change read-only status of existing files on WIN32
- Correctly handle `0x[^[:xdigit:]]` case in strtol() functions
This commit is contained in:
Justine Tunney 2023-09-06 03:54:42 -07:00
parent 8596e83cce
commit f531acc8f9
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
297 changed files with 1920 additions and 1681 deletions

View file

@ -25,6 +25,7 @@
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/fmt/itoa.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/intrin/strace.internal.h"
@ -92,6 +93,7 @@
* - `O_APPEND` open file for appending only
* - `O_NOFOLLOW` fail with ELOOP if it's a symlink
* - `O_NONBLOCK` asks read/write to fail with `EAGAIN` rather than block
* - `O_UNLINK` delete file automatically on close
* - `O_EXEC` open file for execution only; see fexecve()
* - `O_NOCTTY` prevents `path` from becoming the controlling terminal
* - `O_DIRECTORY` advisory feature for avoiding accidentally opening files
@ -107,7 +109,7 @@
* - `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
* - `O_TMPFILE` EINVALs on non-Linux; please use tmpfd() / tmpfile()
* 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
@ -148,6 +150,7 @@
* @raise EINTR if we needed to block and a signal was delivered instead
* @raise EEXIST if `O_CREAT|O_EXCL` are used and `path` already existed
* @raise EINVAL if ASCII control codes are used in `path` on Windows
* @raise EINVAL if `O_UNLINK` is used without `O_CREAT|O_EXCL`
* @raise EINVAL if `O_TRUNC` is specified in `O_RDONLY` mode
* @raise EINVAL if `flags` contains unsupported bits
* @raise ECANCELED if thread was cancelled in masked mode
@ -180,6 +183,15 @@ int openat(int dirfd, const char *path, int flags, ...) {
if (!path || (IsAsan() && !__asan_is_valid_str(path))) {
rc = efault();
} else if ((flags & O_UNLINK) &&
(flags & (O_CREAT | O_EXCL)) != (O_CREAT | O_EXCL)) {
// O_UNLINK is a non-standard cosmo extension; we've chosen bits for
// this magic number which we believe are unlikely to interfere with
// the bits chosen by operating systems both today and in the future
// however, due to the risks here and the irregularity of using this
// feature for anything but temporary files, we are going to prevent
// the clever use cases for now; please file an issue if you want it
rc = einval();
} else if (__isfdkind(dirfd, kFdZip)) {
rc = enotsup(); // TODO
} else if (_weaken(__zipos_open) &&
@ -190,20 +202,29 @@ int openat(int dirfd, const char *path, int flags, ...) {
rc = enotsup(); // TODO
}
} else if ((flags & O_ACCMODE) == O_RDONLY && (flags & O_TRUNC)) {
rc = einval(); // Every OS except OpenBSD actually does this D:
// Every operating system we've tested (with the notable exception
// of OpenBSD) will gladly truncate files opened in read-only mode
rc = einval();
} else if (IsLinux() || IsXnu() || IsFreebsd() || IsOpenbsd() || IsNetbsd()) {
rc = sys_openat(dirfd, path, flags, mode);
if (IsFreebsd()) {
// Address FreeBSD divergence from IEEE Std 1003.1-2008 (POSIX.1)
// in the case when O_NOFOLLOW is used, but fails due to symlink.
if (rc == -1 && errno == EMLINK) {
// openat unix userspace
rc = sys_openat(dirfd, path, flags & ~O_UNLINK, mode);
if (rc != -1) {
// openat succeeded
if (flags & O_UNLINK) {
// Implement Cosmopolitan O_UNLINK extension for UNIX
// This cannot fail since we require O_CREAT / O_EXCL
unassert(!sys_unlinkat(dirfd, path, 0));
}
} else {
// openat failed
if (IsFreebsd() && errno == EMLINK) {
// Address FreeBSD divergence from IEEE Std 1003.1-2008 (POSIX.1)
// in the case when O_NOFOLLOW is used, but fails due to symlink.
errno = ELOOP;
}
}
if (IsNetbsd()) {
// Address NetBSD divergence from IEEE Std 1003.1-2008 (POSIX.1)
// in the case when O_NOFOLLOW is used but fails due to symlink.
if (rc == -1 && errno == EFTYPE) {
if (IsNetbsd() && errno == EFTYPE) {
// Address NetBSD divergence from IEEE Std 1003.1-2008 (POSIX.1)
// in the case when O_NOFOLLOW is used but fails due to symlink.
errno = ELOOP;
}
}
@ -216,9 +237,8 @@ int openat(int dirfd, const char *path, int flags, ...) {
}
END_CANCELLATION_POINT;
STRACE("openat(%s, %#s, %s, %#o) → %d% m", DescribeDirfd(dirfd), path,
DescribeOpenFlags(flags), (flags & (O_CREAT | O_TMPFILE)) ? mode : 0,
rc);
STRACE("openat(%s, %#s, %s%s) → %d% m", DescribeDirfd(dirfd), path,
DescribeOpenFlags(flags), DescribeOpenMode(flags, mode), rc);
return rc;
}