mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-04-15 12:18:52 +00:00
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:
parent
8596e83cce
commit
f531acc8f9
297 changed files with 1920 additions and 1681 deletions
2
.vscode/c_cpp_properties.json
vendored
2
.vscode/c_cpp_properties.json
vendored
|
@ -15,7 +15,7 @@
|
||||||
"alignas(x)",
|
"alignas(x)",
|
||||||
"alignof(x)",
|
"alignof(x)",
|
||||||
"artificial=",
|
"artificial=",
|
||||||
"dontdiscard=",
|
"__wur=",
|
||||||
"mayalias=",
|
"mayalias=",
|
||||||
"forceinline=",
|
"forceinline=",
|
||||||
"forcealign(x)=",
|
"forcealign(x)=",
|
||||||
|
|
|
@ -181,10 +181,6 @@ fi
|
||||||
|
|
||||||
if [ "$1" = "--update" ]; then
|
if [ "$1" = "--update" ]; then
|
||||||
cd $COSMO || exit
|
cd $COSMO || exit
|
||||||
if GIT=$(command -v git); then
|
|
||||||
echo "running git pull on cosmo..." >&2
|
|
||||||
"$GIT" pull --quiet || exit
|
|
||||||
fi
|
|
||||||
echo "building cosmo host toolchain..." >&2
|
echo "building cosmo host toolchain..." >&2
|
||||||
make --silent -j toolchain MODE= || exit
|
make --silent -j toolchain MODE= || exit
|
||||||
echo "building cosmo target (MODE=$MODE) toolchain..." >&2
|
echo "building cosmo target (MODE=$MODE) toolchain..." >&2
|
||||||
|
|
|
@ -150,10 +150,6 @@ fi
|
||||||
|
|
||||||
if [ "$1" = "--update" ]; then
|
if [ "$1" = "--update" ]; then
|
||||||
cd $COSMO || exit
|
cd $COSMO || exit
|
||||||
if GIT=$(command -v git); then
|
|
||||||
echo "running git pull on cosmo..." >&2
|
|
||||||
"$GIT" pull --quiet || exit
|
|
||||||
fi
|
|
||||||
echo "building cosmo host toolchain..." >&2
|
echo "building cosmo host toolchain..." >&2
|
||||||
make --silent -j toolchain MODE= || exit
|
make --silent -j toolchain MODE= || exit
|
||||||
echo "building cosmo x86_64 target (MODE=$MODE) toolchain..." >&2
|
echo "building cosmo x86_64 target (MODE=$MODE) toolchain..." >&2
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
#include "libc/errno.h"
|
#include "libc/errno.h"
|
||||||
#include "libc/fmt/fmt.h"
|
#include "libc/fmt/fmt.h"
|
||||||
#include "libc/fmt/itoa.h"
|
#include "libc/fmt/itoa.h"
|
||||||
|
#include "libc/limits.h"
|
||||||
#include "libc/log/appendresourcereport.internal.h"
|
#include "libc/log/appendresourcereport.internal.h"
|
||||||
#include "libc/log/internal.h"
|
#include "libc/log/internal.h"
|
||||||
#include "libc/log/log.h"
|
#include "libc/log/log.h"
|
||||||
|
|
|
@ -7,15 +7,16 @@
|
||||||
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
|
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
|
||||||
╚─────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────*/
|
||||||
#endif
|
#endif
|
||||||
|
#include "libc/time/time.h"
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
#include "libc/calls/struct/timespec.h"
|
#include "libc/calls/struct/timespec.h"
|
||||||
#include "libc/fmt/itoa.h"
|
#include "libc/fmt/itoa.h"
|
||||||
|
#include "libc/limits.h"
|
||||||
#include "libc/log/log.h"
|
#include "libc/log/log.h"
|
||||||
#include "libc/math.h"
|
#include "libc/math.h"
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
#include "libc/sysv/consts/ex.h"
|
#include "libc/sysv/consts/ex.h"
|
||||||
#include "libc/time/time.h"
|
|
||||||
#include "libc/x/xspawn.h"
|
#include "libc/x/xspawn.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -26,11 +26,6 @@
|
||||||
#define _POSIX_MEMLOCK_RANGE _POSIX_VERSION
|
#define _POSIX_MEMLOCK_RANGE _POSIX_VERSION
|
||||||
#define _POSIX_SPAWN _POSIX_VERSION
|
#define _POSIX_SPAWN _POSIX_VERSION
|
||||||
|
|
||||||
#define EOF -1 /* end of file */
|
|
||||||
#define WEOF -1u /* end of file (multibyte) */
|
|
||||||
#define _IOFBF 0 /* fully buffered */
|
|
||||||
#define _IOLBF 1 /* line buffered */
|
|
||||||
#define _IONBF 2 /* no buffering */
|
|
||||||
#define SEEK_SET 0 /* relative to beginning */
|
#define SEEK_SET 0 /* relative to beginning */
|
||||||
#define SEEK_CUR 1 /* relative to current position */
|
#define SEEK_CUR 1 /* relative to current position */
|
||||||
#define SEEK_END 2 /* relative to end */
|
#define SEEK_END 2 /* relative to end */
|
||||||
|
@ -99,7 +94,6 @@ int execv(const char *, char *const[]);
|
||||||
int execve(const char *, char *const[], char *const[]);
|
int execve(const char *, char *const[], char *const[]);
|
||||||
int execvp(const char *, char *const[]);
|
int execvp(const char *, char *const[]);
|
||||||
int faccessat(int, const char *, int, int);
|
int faccessat(int, const char *, int, int);
|
||||||
int fadvise(int, uint64_t, uint64_t, int);
|
|
||||||
int fchdir(int);
|
int fchdir(int);
|
||||||
int fchmod(int, unsigned) dontthrow;
|
int fchmod(int, unsigned) dontthrow;
|
||||||
int fchmodat(int, const char *, unsigned, int);
|
int fchmodat(int, const char *, unsigned, int);
|
||||||
|
@ -136,7 +130,6 @@ int mkdirat(int, const char *, unsigned);
|
||||||
int mkfifo(const char *, unsigned);
|
int mkfifo(const char *, unsigned);
|
||||||
int mkfifoat(int, const char *, unsigned);
|
int mkfifoat(int, const char *, unsigned);
|
||||||
int mknod(const char *, unsigned, uint64_t);
|
int mknod(const char *, unsigned, uint64_t);
|
||||||
int mknodat(int, const char *, int, uint64_t);
|
|
||||||
int nice(int);
|
int nice(int);
|
||||||
int open(const char *, int, ...);
|
int open(const char *, int, ...);
|
||||||
int openat(int, const char *, int, ...);
|
int openat(int, const char *, int, ...);
|
||||||
|
@ -205,7 +198,7 @@ int setresgid(unsigned, unsigned, unsigned);
|
||||||
int setresuid(unsigned, unsigned, unsigned);
|
int setresuid(unsigned, unsigned, unsigned);
|
||||||
int getresgid(unsigned *, unsigned *, unsigned *);
|
int getresgid(unsigned *, unsigned *, unsigned *);
|
||||||
int getresuid(unsigned *, unsigned *, unsigned *);
|
int getresuid(unsigned *, unsigned *, unsigned *);
|
||||||
char *get_current_dir_name(void) dontdiscard;
|
char *get_current_dir_name(void) __wur;
|
||||||
int sync_file_range(int, int64_t, int64_t, unsigned);
|
int sync_file_range(int, int64_t, int64_t, unsigned);
|
||||||
ssize_t splice(int, int64_t *, int, int64_t *, size_t, unsigned);
|
ssize_t splice(int, int64_t *, int, int64_t *, size_t, unsigned);
|
||||||
int memfd_create(const char *, unsigned int);
|
int memfd_create(const char *, unsigned int);
|
||||||
|
@ -245,6 +238,7 @@ int tmpfd(void);
|
||||||
int touch(const char *, unsigned);
|
int touch(const char *, unsigned);
|
||||||
int unveil(const char *, const char *);
|
int unveil(const char *, const char *);
|
||||||
long ptrace(int, ...);
|
long ptrace(int, ...);
|
||||||
|
int fadvise(int, uint64_t, uint64_t, int);
|
||||||
ssize_t copyfd(int, int, size_t);
|
ssize_t copyfd(int, int, size_t);
|
||||||
ssize_t readansi(int, char *, size_t);
|
ssize_t readansi(int, char *, size_t);
|
||||||
ssize_t tinyprint(int, const char *, ...) nullterminated();
|
ssize_t tinyprint(int, const char *, ...) nullterminated();
|
||||||
|
|
|
@ -33,7 +33,7 @@
|
||||||
#define _O_EXCL 0x00000080 // kNtCreateNew
|
#define _O_EXCL 0x00000080 // kNtCreateNew
|
||||||
#define _O_TRUNC 0x00000200 // kNtCreateAlways
|
#define _O_TRUNC 0x00000200 // kNtCreateAlways
|
||||||
#define _O_DIRECTORY 0x00010000 // kNtFileFlagBackupSemantics
|
#define _O_DIRECTORY 0x00010000 // kNtFileFlagBackupSemantics
|
||||||
#define _O_TMPFILE 0x00410000 // AttributeTemporary|FlagDeleteOnClose
|
#define _O_UNLINK 0x04000100 // kNtFileAttributeTemporary|DeleteOnClose
|
||||||
#define _O_DIRECT 0x00004000 // kNtFileFlagNoBuffering
|
#define _O_DIRECT 0x00004000 // kNtFileFlagNoBuffering
|
||||||
#define _O_NONBLOCK 0x00000800 // kNtFileFlagWriteThrough (not sent to win32)
|
#define _O_NONBLOCK 0x00000800 // kNtFileFlagWriteThrough (not sent to win32)
|
||||||
#define _O_RANDOM 0x80000000 // kNtFileFlagRandomAccess
|
#define _O_RANDOM 0x80000000 // kNtFileFlagRandomAccess
|
||||||
|
@ -51,11 +51,18 @@ textwindows int GetNtOpenFlags(int flags, int mode, uint32_t *out_perm,
|
||||||
|
|
||||||
if (flags &
|
if (flags &
|
||||||
~(O_ACCMODE | _O_APPEND | _O_CREAT | _O_EXCL | _O_TRUNC | _O_DIRECTORY |
|
~(O_ACCMODE | _O_APPEND | _O_CREAT | _O_EXCL | _O_TRUNC | _O_DIRECTORY |
|
||||||
_O_TMPFILE | _O_NONBLOCK | _O_RANDOM | _O_SEQUENTIAL | _O_COMPRESSED |
|
_O_UNLINK | _O_NONBLOCK | _O_RANDOM | _O_SEQUENTIAL | _O_COMPRESSED |
|
||||||
_O_INDEXED | _O_CLOEXEC | _O_DIRECT)) {
|
_O_INDEXED | _O_CLOEXEC | _O_DIRECT)) {
|
||||||
return einval();
|
return einval();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// "Some of these flags should not be combined. For instance,
|
||||||
|
// combining kNtFileFlagRandomAccess with kNtFileFlagSequentialScan
|
||||||
|
// is self-defeating." -Quoth MSDN § CreateFileW
|
||||||
|
if ((flags & _O_SEQUENTIAL) && (flags & _O_RANDOM)) {
|
||||||
|
return einval();
|
||||||
|
}
|
||||||
|
|
||||||
switch (flags & O_ACCMODE) {
|
switch (flags & O_ACCMODE) {
|
||||||
case O_RDONLY:
|
case O_RDONLY:
|
||||||
perm = kNtFileGenericRead;
|
perm = kNtFileGenericRead;
|
||||||
|
@ -80,7 +87,7 @@ textwindows int GetNtOpenFlags(int flags, int mode, uint32_t *out_perm,
|
||||||
}
|
}
|
||||||
|
|
||||||
attr = 0;
|
attr = 0;
|
||||||
is_creating_file = (flags & _O_CREAT) || (flags & _O_TMPFILE) == _O_TMPFILE;
|
is_creating_file = !!(flags & _O_CREAT);
|
||||||
|
|
||||||
// POSIX O_EXEC doesn't mean the same thing as kNtGenericExecute. We
|
// POSIX O_EXEC doesn't mean the same thing as kNtGenericExecute. We
|
||||||
// request execute access when we can determine it from mode's bits.
|
// request execute access when we can determine it from mode's bits.
|
||||||
|
@ -125,33 +132,64 @@ textwindows int GetNtOpenFlags(int flags, int mode, uint32_t *out_perm,
|
||||||
disp = kNtOpenExisting;
|
disp = kNtOpenExisting;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Please use tmpfd() or tmpfile() instead of O_TMPFILE.
|
|
||||||
if ((flags & _O_TMPFILE) == _O_TMPFILE) {
|
|
||||||
attr |= kNtFileAttributeTemporary | kNtFileFlagDeleteOnClose;
|
|
||||||
} else {
|
|
||||||
attr |= kNtFileAttributeNormal;
|
|
||||||
if (flags & _O_DIRECTORY) {
|
|
||||||
attr |= kNtFileFlagBackupSemantics;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// The Windows content indexing service ravages performance similar to
|
|
||||||
// Windows Defender. Please pass O_INDEXED to openat() to enable this.
|
|
||||||
if (~flags & _O_INDEXED) {
|
if (~flags & _O_INDEXED) {
|
||||||
|
// The Windows content indexing service ravages performance similar to
|
||||||
|
// Windows Defender. Please pass O_INDEXED to openat() to enable this.
|
||||||
attr |= kNtFileAttributeNotContentIndexed;
|
attr |= kNtFileAttributeNotContentIndexed;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Windows' transparent filesystem compression is really cool, as such
|
|
||||||
// we've introduced a nonstandard O_COMPRESSED flag to help you use it
|
|
||||||
if (flags & _O_COMPRESSED) {
|
if (flags & _O_COMPRESSED) {
|
||||||
|
// Windows' transparent filesystem compression is really cool, as such
|
||||||
|
// we've introduced a nonstandard O_COMPRESSED flag to help you use it
|
||||||
attr |= kNtFileAttributeCompressed;
|
attr |= kNtFileAttributeCompressed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (flags & kNtFileAttributeTemporary) { // subset of _O_UNLINK
|
||||||
|
// "Specifying the kNtFileAttributeTemporary attribute causes file
|
||||||
|
// systems to avoid writing data back to mass storage if sufficient
|
||||||
|
// cache memory is available, because an application deletes a
|
||||||
|
// temporary file after a handle is closed. In that case, the
|
||||||
|
// system can entirely avoid writing the data. Although it does not
|
||||||
|
// directly control data caching in the same way as the
|
||||||
|
// [kNtFileFlagNoBuffering, kNtFileFlagWriteThrough,
|
||||||
|
// kNtFileFlagSequentialScan, and kNtFileFlagRandomAccess] flags,
|
||||||
|
// the kNtFileAttributeTemporary attribute does tell the system to
|
||||||
|
// hold as much as possible in the system cache without writing and
|
||||||
|
// therefore may be of concern for certain applications." -MSDN
|
||||||
|
attr |= kNtFileAttributeTemporary;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!attr) {
|
||||||
|
// "All other file attributes override kNtFileAttributeNormal [...]
|
||||||
|
// [which] is valid only if used alone." -Quoth MSDN § CreateFileW
|
||||||
|
attr |= kNtFileAttributeNormal;
|
||||||
|
}
|
||||||
|
|
||||||
|
attr |= flags & kNtFileFlagDeleteOnClose; // subset of _O_UNLINK
|
||||||
|
|
||||||
|
if (flags & _O_DIRECTORY) {
|
||||||
|
// "You must set this flag to obtain a handle to a directory."
|
||||||
|
// -Quoth MSDN § CreateFileW
|
||||||
|
attr |= kNtFileFlagBackupSemantics;
|
||||||
|
}
|
||||||
|
|
||||||
// Not certain yet what benefit these flags offer.
|
// Not certain yet what benefit these flags offer.
|
||||||
if (flags & _O_SEQUENTIAL) attr |= kNtFileFlagSequentialScan;
|
if (flags & _O_SEQUENTIAL) attr |= kNtFileFlagSequentialScan;
|
||||||
if (flags & _O_RANDOM) attr |= kNtFileFlagRandomAccess;
|
if (flags & _O_RANDOM) attr |= kNtFileFlagRandomAccess;
|
||||||
if (flags & _O_DIRECT) attr |= kNtFileFlagNoBuffering;
|
if (flags & _O_DIRECT) attr |= kNtFileFlagNoBuffering;
|
||||||
|
|
||||||
|
// TODO(jart): Should we *always* open with write permission if the
|
||||||
|
// kernel will give it to us? We'd then deny write access
|
||||||
|
// in libc system call wrappers.
|
||||||
|
//
|
||||||
|
// "When an application creates a file across a network, it is better
|
||||||
|
// to use kNtGenericRead | kNtGenericWrite for dwDesiredAccess than
|
||||||
|
// to use kNtGenericWrite alone. The resulting code is faster,
|
||||||
|
// because the redirector can use the cache manager and send fewer
|
||||||
|
// SMBs with more data. This combination also avoids an issue where
|
||||||
|
// writing to a file across a network can occasionally return
|
||||||
|
// kNtErrorAccessDenied." -Quoth MSDN
|
||||||
|
|
||||||
if (out_perm) *out_perm = perm;
|
if (out_perm) *out_perm = perm;
|
||||||
if (out_share) *out_share = share;
|
if (out_share) *out_share = share;
|
||||||
if (out_disp) *out_disp = disp;
|
if (out_disp) *out_disp = disp;
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
|
#include "libc/limits.h"
|
||||||
#include "libc/mem/alloca.h"
|
#include "libc/mem/alloca.h"
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#include "libc/errno.h"
|
#include "libc/errno.h"
|
||||||
#include "libc/intrin/bits.h"
|
#include "libc/intrin/bits.h"
|
||||||
#include "libc/intrin/safemacros.internal.h"
|
#include "libc/intrin/safemacros.internal.h"
|
||||||
|
#include "libc/limits.h"
|
||||||
#include "libc/mem/alloca.h"
|
#include "libc/mem/alloca.h"
|
||||||
#include "libc/paths.h"
|
#include "libc/paths.h"
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
#include "libc/dce.h"
|
#include "libc/dce.h"
|
||||||
#include "libc/intrin/asan.internal.h"
|
#include "libc/intrin/asan.internal.h"
|
||||||
|
#include "libc/limits.h"
|
||||||
#include "libc/mem/alloca.h"
|
#include "libc/mem/alloca.h"
|
||||||
#include "libc/mem/mem.h"
|
#include "libc/mem/mem.h"
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
|
|
|
@ -33,6 +33,7 @@
|
||||||
#include "libc/intrin/safemacros.internal.h"
|
#include "libc/intrin/safemacros.internal.h"
|
||||||
#include "libc/intrin/strace.internal.h"
|
#include "libc/intrin/strace.internal.h"
|
||||||
#include "libc/intrin/weaken.h"
|
#include "libc/intrin/weaken.h"
|
||||||
|
#include "libc/limits.h"
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
#include "libc/sysv/consts/f.h"
|
#include "libc/sysv/consts/f.h"
|
||||||
#include "libc/sysv/consts/fd.h"
|
#include "libc/sysv/consts/fd.h"
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
|
#include "libc/assert.h"
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
#include "libc/calls/internal.h"
|
#include "libc/calls/internal.h"
|
||||||
#include "libc/calls/struct/stat.h"
|
#include "libc/calls/struct/stat.h"
|
||||||
|
@ -25,6 +26,7 @@
|
||||||
#include "libc/intrin/bsr.h"
|
#include "libc/intrin/bsr.h"
|
||||||
#include "libc/intrin/strace.internal.h"
|
#include "libc/intrin/strace.internal.h"
|
||||||
#include "libc/macros.internal.h"
|
#include "libc/macros.internal.h"
|
||||||
|
#include "libc/mem/alloca.h"
|
||||||
#include "libc/nt/enum/fileflagandattributes.h"
|
#include "libc/nt/enum/fileflagandattributes.h"
|
||||||
#include "libc/nt/enum/fileinfobyhandleclass.h"
|
#include "libc/nt/enum/fileinfobyhandleclass.h"
|
||||||
#include "libc/nt/enum/filetype.h"
|
#include "libc/nt/enum/filetype.h"
|
||||||
|
@ -39,102 +41,119 @@
|
||||||
#include "libc/sysv/consts/s.h"
|
#include "libc/sysv/consts/s.h"
|
||||||
#include "libc/sysv/errfuns.h"
|
#include "libc/sysv/errfuns.h"
|
||||||
|
|
||||||
static textwindows uint32_t GetSizeOfReparsePoint(int64_t fh) {
|
static textwindows long GetSizeOfReparsePoint(int64_t fh) {
|
||||||
wint_t x, y;
|
uint32_t mem =
|
||||||
const char16_t *p;
|
sizeof(struct NtReparseDataBuffer) + PATH_MAX * sizeof(char16_t);
|
||||||
uint32_t mem, i, n, z = 0;
|
void *buf = alloca(mem);
|
||||||
struct NtReparseDataBuffer *rdb;
|
uint32_t dwBytesReturned;
|
||||||
long buf[(sizeof(*rdb) + PATH_MAX * sizeof(char16_t)) / sizeof(long)];
|
struct NtReparseDataBuffer *rdb = (struct NtReparseDataBuffer *)buf;
|
||||||
mem = sizeof(buf);
|
if (!DeviceIoControl(fh, kNtFsctlGetReparsePoint, 0, 0, rdb, mem,
|
||||||
rdb = (struct NtReparseDataBuffer *)buf;
|
&dwBytesReturned, 0)) {
|
||||||
if (DeviceIoControl(fh, kNtFsctlGetReparsePoint, 0, 0, rdb, mem, &n, 0)) {
|
return -1;
|
||||||
i = 0;
|
}
|
||||||
n = rdb->SymbolicLinkReparseBuffer.PrintNameLength / sizeof(char16_t);
|
const char16_t *p =
|
||||||
p = (char16_t *)((char *)rdb->SymbolicLinkReparseBuffer.PathBuffer +
|
(const char16_t *)((char *)rdb->SymbolicLinkReparseBuffer.PathBuffer +
|
||||||
rdb->SymbolicLinkReparseBuffer.PrintNameOffset);
|
rdb->SymbolicLinkReparseBuffer.PrintNameOffset);
|
||||||
while (i < n) {
|
uint32_t n =
|
||||||
x = p[i++] & 0xffff;
|
rdb->SymbolicLinkReparseBuffer.PrintNameLength / sizeof(char16_t);
|
||||||
if (!IsUcs2(x)) {
|
uint32_t i = 0;
|
||||||
if (i < n) {
|
uint32_t z = 0;
|
||||||
y = p[i++] & 0xffff;
|
while (i < n) {
|
||||||
x = MergeUtf16(x, y);
|
wint_t x = p[i++] & 0xffff;
|
||||||
} else {
|
if (!IsUcs2(x)) {
|
||||||
x = 0xfffd;
|
if (i < n) {
|
||||||
}
|
wint_t y = p[i++] & 0xffff;
|
||||||
|
x = MergeUtf16(x, y);
|
||||||
|
} else {
|
||||||
|
x = 0xfffd;
|
||||||
}
|
}
|
||||||
z += x < 0200 ? 1 : _bsrl(tpenc(x)) >> 3;
|
|
||||||
}
|
}
|
||||||
} else {
|
if (x >= 0200) {
|
||||||
STRACE("%s failed %m", "GetSizeOfReparsePoint");
|
z += _bsrl(tpenc(x)) >> 3;
|
||||||
|
}
|
||||||
|
++z;
|
||||||
}
|
}
|
||||||
return z;
|
return z;
|
||||||
}
|
}
|
||||||
|
|
||||||
textwindows int sys_fstat_nt(int64_t handle, struct stat *st) {
|
textwindows int sys_fstat_nt(int64_t handle, struct stat *out_st) {
|
||||||
int filetype;
|
struct stat st = {0};
|
||||||
uint32_t umask;
|
|
||||||
uint64_t actualsize;
|
// Always set st_blksize to avoid divide by zero issues.
|
||||||
struct NtFileCompressionInfo fci;
|
// The Linux kernel sets this for /dev/tty and similar too.
|
||||||
struct NtByHandleFileInformation wst;
|
// TODO(jart): GetVolumeInformationByHandle?
|
||||||
if (!st) return efault();
|
st.st_blksize = 4096;
|
||||||
if ((filetype = GetFileType(handle))) {
|
|
||||||
bzero(st, sizeof(*st));
|
// We'll use the "umask" to fake out the mode bits.
|
||||||
umask = atomic_load_explicit(&__umask, memory_order_acquire);
|
uint32_t umask = atomic_load_explicit(&__umask, memory_order_acquire);
|
||||||
switch (filetype) {
|
|
||||||
case kNtFileTypeChar:
|
switch (GetFileType(handle)) {
|
||||||
st->st_mode = S_IFCHR | (0666 & ~umask);
|
case kNtFileTypeUnknown:
|
||||||
break;
|
break;
|
||||||
case kNtFileTypePipe:
|
case kNtFileTypeChar:
|
||||||
st->st_mode = S_IFIFO | (0666 & ~umask);
|
st.st_mode = S_IFCHR | (0666 & ~umask);
|
||||||
break;
|
break;
|
||||||
case kNtFileTypeDisk:
|
case kNtFileTypePipe:
|
||||||
if (GetFileInformationByHandle(handle, &wst)) {
|
st.st_mode = S_IFIFO | (0666 & ~umask);
|
||||||
st->st_mode = 0555 & ~umask;
|
break;
|
||||||
st->st_flags = wst.dwFileAttributes;
|
case kNtFileTypeDisk: {
|
||||||
if (!(wst.dwFileAttributes & kNtFileAttributeReadonly)) {
|
struct NtByHandleFileInformation wst;
|
||||||
st->st_mode |= 0222 & ~umask;
|
if (!GetFileInformationByHandle(handle, &wst)) {
|
||||||
}
|
return __winerr();
|
||||||
if (wst.dwFileAttributes & kNtFileAttributeDirectory) {
|
}
|
||||||
st->st_mode |= S_IFDIR;
|
st.st_mode = 0555 & ~umask;
|
||||||
} else if (wst.dwFileAttributes & kNtFileAttributeReparsePoint) {
|
st.st_flags = wst.dwFileAttributes;
|
||||||
st->st_mode |= S_IFLNK;
|
if (!(wst.dwFileAttributes & kNtFileAttributeReadonly)) {
|
||||||
} else {
|
st.st_mode |= 0222 & ~umask;
|
||||||
st->st_mode |= S_IFREG;
|
}
|
||||||
}
|
if (wst.dwFileAttributes & kNtFileAttributeReparsePoint) {
|
||||||
st->st_atim = FileTimeToTimeSpec(wst.ftLastAccessFileTime);
|
st.st_mode |= S_IFLNK;
|
||||||
st->st_mtim = FileTimeToTimeSpec(wst.ftLastWriteFileTime);
|
} else if (wst.dwFileAttributes & kNtFileAttributeDirectory) {
|
||||||
st->st_ctim = FileTimeToTimeSpec(wst.ftCreationFileTime);
|
st.st_mode |= S_IFDIR;
|
||||||
st->st_birthtim = st->st_ctim;
|
} else {
|
||||||
st->st_gid = st->st_uid = __synthesize_uid();
|
st.st_mode |= S_IFREG;
|
||||||
st->st_size = (uint64_t)wst.nFileSizeHigh << 32 | wst.nFileSizeLow;
|
}
|
||||||
st->st_blksize = 4096;
|
st.st_atim = FileTimeToTimeSpec(wst.ftLastAccessFileTime);
|
||||||
st->st_dev = wst.dwVolumeSerialNumber;
|
st.st_mtim = FileTimeToTimeSpec(wst.ftLastWriteFileTime);
|
||||||
st->st_rdev = 0;
|
st.st_birthtim = FileTimeToTimeSpec(wst.ftCreationFileTime);
|
||||||
st->st_ino = (uint64_t)wst.nFileIndexHigh << 32 | wst.nFileIndexLow;
|
// compute time of last status change
|
||||||
st->st_nlink = wst.nNumberOfLinks;
|
if (timespec_cmp(st.st_atim, st.st_mtim) > 0) {
|
||||||
if (S_ISLNK(st->st_mode)) {
|
st.st_ctim = st.st_atim;
|
||||||
if (!st->st_size) {
|
} else {
|
||||||
st->st_size = GetSizeOfReparsePoint(handle);
|
st.st_ctim = st.st_mtim;
|
||||||
}
|
}
|
||||||
} else {
|
st.st_gid = st.st_uid = __synthesize_uid();
|
||||||
actualsize = st->st_size;
|
st.st_size = (wst.nFileSizeHigh + 0ull) << 32 | wst.nFileSizeLow;
|
||||||
if (S_ISREG(st->st_mode) &&
|
st.st_dev = wst.dwVolumeSerialNumber;
|
||||||
GetFileInformationByHandleEx(handle, kNtFileCompressionInfo,
|
st.st_ino = (wst.nFileIndexHigh + 0ull) << 32 | wst.nFileIndexLow;
|
||||||
&fci, sizeof(fci))) {
|
st.st_nlink = wst.nNumberOfLinks;
|
||||||
actualsize = fci.CompressedFileSize;
|
if (S_ISLNK(st.st_mode)) {
|
||||||
}
|
if (!st.st_size) {
|
||||||
st->st_blocks = ROUNDUP(actualsize, 4096) / 512;
|
long size = GetSizeOfReparsePoint(handle);
|
||||||
}
|
if (size == -1) return -1;
|
||||||
} else {
|
st.st_size = size;
|
||||||
STRACE("%s failed %m", "GetFileInformationByHandle");
|
|
||||||
}
|
}
|
||||||
break;
|
} else {
|
||||||
default:
|
// st_size = uncompressed size
|
||||||
break;
|
// st_blocks*512 = physical size
|
||||||
|
uint64_t physicalsize;
|
||||||
|
struct NtFileCompressionInfo fci;
|
||||||
|
if (!(wst.dwFileAttributes &
|
||||||
|
(kNtFileAttributeDirectory | kNtFileAttributeReparsePoint)) &&
|
||||||
|
GetFileInformationByHandleEx(handle, kNtFileCompressionInfo, &fci,
|
||||||
|
sizeof(fci))) {
|
||||||
|
physicalsize = fci.CompressedFileSize;
|
||||||
|
} else {
|
||||||
|
physicalsize = st.st_size;
|
||||||
|
}
|
||||||
|
st.st_blocks = ROUNDUP(physicalsize, st.st_blksize) / 512;
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return 0;
|
default:
|
||||||
} else {
|
__builtin_unreachable();
|
||||||
STRACE("%s failed %m", "GetFileType");
|
|
||||||
return __winerr();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
memcpy(out_st, &st, sizeof(st));
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,16 +17,9 @@
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/calls/struct/metastat.internal.h"
|
#include "libc/calls/struct/metastat.internal.h"
|
||||||
#include "libc/calls/struct/stat.h"
|
#include "libc/calls/struct/stat.internal.h"
|
||||||
#include "libc/calls/syscall-sysv.internal.h"
|
#include "libc/calls/syscall-sysv.internal.h"
|
||||||
#include "libc/dce.h"
|
|
||||||
#include "libc/intrin/asan.internal.h"
|
|
||||||
#include "libc/sysv/errfuns.h"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Forms fstat() on System Five.
|
|
||||||
* @asyncsignalsafe
|
|
||||||
*/
|
|
||||||
int32_t sys_fstat(int32_t fd, struct stat *st) {
|
int32_t sys_fstat(int32_t fd, struct stat *st) {
|
||||||
void *p;
|
void *p;
|
||||||
union metastat ms;
|
union metastat ms;
|
||||||
|
|
|
@ -34,7 +34,9 @@ textwindows int sys_fstatat_nt(int dirfd, const char *path, struct stat *st,
|
||||||
uint16_t path16[PATH_MAX];
|
uint16_t path16[PATH_MAX];
|
||||||
if (__mkntpathat(dirfd, path, 0, path16) == -1) return -1;
|
if (__mkntpathat(dirfd, path, 0, path16) == -1) return -1;
|
||||||
if ((fh = CreateFile(
|
if ((fh = CreateFile(
|
||||||
path16, kNtFileReadAttributes, 0, 0, kNtOpenExisting,
|
path16, kNtFileReadAttributes,
|
||||||
|
kNtFileShareRead | kNtFileShareWrite | kNtFileShareDelete, 0,
|
||||||
|
kNtOpenExisting,
|
||||||
kNtFileAttributeNormal | kNtFileFlagBackupSemantics |
|
kNtFileAttributeNormal | kNtFileFlagBackupSemantics |
|
||||||
((flags & AT_SYMLINK_NOFOLLOW) ? kNtFileFlagOpenReparsePoint
|
((flags & AT_SYMLINK_NOFOLLOW) ? kNtFileFlagOpenReparsePoint
|
||||||
: 0),
|
: 0),
|
||||||
|
|
|
@ -17,10 +17,8 @@
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/calls/struct/metastat.internal.h"
|
#include "libc/calls/struct/metastat.internal.h"
|
||||||
|
#include "libc/calls/struct/stat.internal.h"
|
||||||
#include "libc/calls/syscall-sysv.internal.h"
|
#include "libc/calls/syscall-sysv.internal.h"
|
||||||
#include "libc/dce.h"
|
|
||||||
#include "libc/intrin/asan.internal.h"
|
|
||||||
#include "libc/sysv/errfuns.h"
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Performs fstatat() on System Five.
|
* Performs fstatat() on System Five.
|
||||||
|
@ -30,7 +28,6 @@ int32_t sys_fstatat(int32_t dirfd, const char *path, struct stat *st,
|
||||||
int32_t flags) {
|
int32_t flags) {
|
||||||
void *p;
|
void *p;
|
||||||
union metastat ms;
|
union metastat ms;
|
||||||
if (IsAsan() && !__asan_is_valid_str(path)) return efault();
|
|
||||||
if (st) {
|
if (st) {
|
||||||
p = &ms;
|
p = &ms;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -44,7 +44,11 @@
|
||||||
*/
|
*/
|
||||||
int futimens(int fd, const struct timespec ts[2]) {
|
int futimens(int fd, const struct timespec ts[2]) {
|
||||||
int rc;
|
int rc;
|
||||||
rc = __utimens(fd, 0, ts, 0);
|
if (fd < 0) {
|
||||||
|
rc = ebadf(); // so we don't confuse __utimens if caller passes AT_FDCWD
|
||||||
|
} else {
|
||||||
|
rc = __utimens(fd, 0, ts, 0);
|
||||||
|
}
|
||||||
STRACE("futimens(%d, {%s, %s}) → %d% m", fd, DescribeTimespec(0, ts),
|
STRACE("futimens(%d, {%s, %s}) → %d% m", fd, DescribeTimespec(0, ts),
|
||||||
DescribeTimespec(0, ts ? ts + 1 : 0), rc);
|
DescribeTimespec(0, ts ? ts + 1 : 0), rc);
|
||||||
return rc;
|
return rc;
|
||||||
|
|
|
@ -42,19 +42,16 @@
|
||||||
int futimes(int fd, const struct timeval tv[2]) {
|
int futimes(int fd, const struct timeval tv[2]) {
|
||||||
int rc;
|
int rc;
|
||||||
struct timespec ts[2];
|
struct timespec ts[2];
|
||||||
|
if (fd < 0) {
|
||||||
if (tv) {
|
rc = ebadf(); // so we don't confuse __utimens if caller passes AT_FDCWD
|
||||||
ts[0].tv_sec = tv[0].tv_sec;
|
} else if (tv) {
|
||||||
ts[0].tv_nsec = tv[0].tv_usec * 1000;
|
ts[0] = timeval_totimespec(tv[0]);
|
||||||
ts[1].tv_sec = tv[1].tv_sec;
|
ts[1] = timeval_totimespec(tv[1]);
|
||||||
ts[1].tv_nsec = tv[1].tv_usec * 1000;
|
|
||||||
rc = __utimens(fd, 0, ts, 0);
|
rc = __utimens(fd, 0, ts, 0);
|
||||||
} else {
|
} else {
|
||||||
rc = __utimens(fd, 0, 0, 0);
|
rc = __utimens(fd, 0, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
STRACE("futimes(%d, {%s, %s}) → %d% m", fd, DescribeTimeval(0, tv),
|
STRACE("futimes(%d, {%s, %s}) → %d% m", fd, DescribeTimeval(0, tv),
|
||||||
DescribeTimeval(0, tv ? tv + 1 : 0), rc);
|
DescribeTimeval(0, tv ? tv + 1 : 0), rc);
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
#include "libc/dce.h"
|
#include "libc/dce.h"
|
||||||
#include "libc/intrin/strace.internal.h"
|
#include "libc/intrin/strace.internal.h"
|
||||||
#include "libc/intrin/weaken.h"
|
#include "libc/intrin/weaken.h"
|
||||||
|
#include "libc/limits.h"
|
||||||
#include "libc/log/backtrace.internal.h"
|
#include "libc/log/backtrace.internal.h"
|
||||||
#include "libc/mem/mem.h"
|
#include "libc/mem/mem.h"
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#include "libc/cosmo.h"
|
#include "libc/cosmo.h"
|
||||||
#include "libc/dce.h"
|
#include "libc/dce.h"
|
||||||
#include "libc/errno.h"
|
#include "libc/errno.h"
|
||||||
|
#include "libc/limits.h"
|
||||||
#include "libc/macros.internal.h"
|
#include "libc/macros.internal.h"
|
||||||
#include "libc/nt/runtime.h"
|
#include "libc/nt/runtime.h"
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
|
|
|
@ -16,21 +16,46 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
|
#include "libc/assert.h"
|
||||||
|
#include "libc/atomic.h"
|
||||||
|
#include "libc/cosmo.h"
|
||||||
#include "libc/dce.h"
|
#include "libc/dce.h"
|
||||||
#include "libc/errno.h"
|
#include "libc/errno.h"
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
#include "libc/sysv/consts/pr.h"
|
#include "libc/sysv/consts/pr.h"
|
||||||
|
|
||||||
bool __is_linux_2_6_23(void) {
|
|
||||||
#ifdef __x86_64__
|
#ifdef __x86_64__
|
||||||
|
|
||||||
|
static struct {
|
||||||
|
atomic_uint once;
|
||||||
|
bool res;
|
||||||
|
} __is_linux_2_6_23_data;
|
||||||
|
|
||||||
|
static bool __is_linux_2_6_23_impl(void) {
|
||||||
int rc;
|
int rc;
|
||||||
if (!IsLinux()) return false;
|
|
||||||
if (IsGenuineBlink()) return true;
|
if (IsGenuineBlink()) return true;
|
||||||
asm volatile("syscall"
|
asm volatile("syscall"
|
||||||
: "=a"(rc)
|
: "=a"(rc)
|
||||||
: "0"(157), "D"(PR_GET_SECCOMP)
|
: "0"(157), "D"(PR_GET_SECCOMP)
|
||||||
: "rcx", "r11", "memory");
|
: "rcx", "r11", "memory");
|
||||||
return rc != -EINVAL;
|
return rc != -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __is_linux_2_6_23_init(void) {
|
||||||
|
__is_linux_2_6_23_data.res = __is_linux_2_6_23_impl();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* x86 */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if we're running on non-ancient Linux.
|
||||||
|
* @note this function must only be called on Linux
|
||||||
|
*/
|
||||||
|
bool __is_linux_2_6_23(void) {
|
||||||
|
unassert(IsLinux()); // should be checked by caller
|
||||||
|
#ifdef __x86_64__
|
||||||
|
cosmo_once(&__is_linux_2_6_23_data.once, __is_linux_2_6_23_init);
|
||||||
|
return __is_linux_2_6_23_data.res;
|
||||||
#else
|
#else
|
||||||
return true;
|
return true;
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -37,7 +37,7 @@ int issetugid(void) {
|
||||||
int rc;
|
int rc;
|
||||||
if (IsLinux()) {
|
if (IsLinux()) {
|
||||||
rc = !!__getauxval(AT_SECURE).value;
|
rc = !!__getauxval(AT_SECURE).value;
|
||||||
} else if (IsMetal()) {
|
} else if (IsMetal() || IsWindows()) {
|
||||||
rc = 0;
|
rc = 0;
|
||||||
} else {
|
} else {
|
||||||
rc = sys_issetugid();
|
rc = sys_issetugid();
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
#include "libc/dce.h"
|
#include "libc/dce.h"
|
||||||
|
#include "libc/limits.h"
|
||||||
#include "libc/macros.internal.h"
|
#include "libc/macros.internal.h"
|
||||||
#include "libc/nt/systeminfo.h"
|
#include "libc/nt/systeminfo.h"
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
|
|
|
@ -27,10 +27,8 @@
|
||||||
int lutimes(const char *filename, const struct timeval tv[2]) {
|
int lutimes(const char *filename, const struct timeval tv[2]) {
|
||||||
struct timespec ts[2];
|
struct timespec ts[2];
|
||||||
if (tv) {
|
if (tv) {
|
||||||
ts[0].tv_sec = tv[0].tv_sec;
|
ts[0] = timeval_totimespec(tv[0]);
|
||||||
ts[0].tv_nsec = tv[0].tv_usec * 1000;
|
ts[1] = timeval_totimespec(tv[1]);
|
||||||
ts[1].tv_sec = tv[1].tv_sec;
|
|
||||||
ts[1].tv_nsec = tv[1].tv_usec * 1000;
|
|
||||||
return utimensat(AT_FDCWD, filename, ts, AT_SYMLINK_NOFOLLOW);
|
return utimensat(AT_FDCWD, filename, ts, AT_SYMLINK_NOFOLLOW);
|
||||||
} else {
|
} else {
|
||||||
return utimensat(AT_FDCWD, filename, 0, AT_SYMLINK_NOFOLLOW);
|
return utimensat(AT_FDCWD, filename, 0, AT_SYMLINK_NOFOLLOW);
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
#include "libc/calls/struct/stat.h"
|
#include "libc/calls/struct/stat.h"
|
||||||
#include "libc/errno.h"
|
#include "libc/errno.h"
|
||||||
|
#include "libc/limits.h"
|
||||||
#include "libc/str/path.h"
|
#include "libc/str/path.h"
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
#include "libc/sysv/consts/s.h"
|
#include "libc/sysv/consts/s.h"
|
||||||
|
|
|
@ -18,47 +18,45 @@
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
#include "libc/errno.h"
|
#include "libc/errno.h"
|
||||||
|
#include "libc/intrin/bits.h"
|
||||||
#include "libc/stdio/rand.h"
|
#include "libc/stdio/rand.h"
|
||||||
#include "libc/stdio/temp.h"
|
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
#include "libc/sysv/errfuns.h"
|
#include "libc/sysv/errfuns.h"
|
||||||
|
#include "libc/temp.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates temporary directory, e.g.
|
* Creates temporary directory, e.g.
|
||||||
*
|
*
|
||||||
* char path[PATH_MAX];
|
* char path[] = "/tmp/foo.XXXXXX";
|
||||||
* snprintf(path, sizeof(path), "%s%s.XXXXXX",
|
* mkdtemp(path);
|
||||||
* kTmpPath, program_invocation_short_name);
|
|
||||||
* printf("%s\n", mkdtemp(path));
|
|
||||||
* rmdir(path);
|
* rmdir(path);
|
||||||
*
|
*
|
||||||
* @param template must end with XXXXXX which is replaced with
|
* @param template must end with XXXXXX which will be replaced
|
||||||
* nondeterministic base36 random data
|
* with random text on success (and not modified on error)
|
||||||
* @return pointer to template on success, or NULL w/ errno
|
* @return pointer to template on success, or NULL w/ errno
|
||||||
* @raise EINVAL if template didn't end with XXXXXX
|
* @raise EINVAL if template didn't end with XXXXXX
|
||||||
*/
|
*/
|
||||||
char *mkdtemp(char *template) {
|
char *mkdtemp(char *template) {
|
||||||
unsigned x;
|
int n;
|
||||||
int i, j, n;
|
if ((n = strlen(template)) < 6 ||
|
||||||
if ((n = strlen(template)) >= 6 && !memcmp(template + n - 6, "XXXXXX", 6)) {
|
READ32LE(template + n - 6) != READ32LE("XXXX") ||
|
||||||
for (i = 0; i < 10; ++i) {
|
READ16LE(template + n - 6 + 4) != READ16LE("XX")) {
|
||||||
x = _rand64();
|
|
||||||
for (j = 0; j < 6; ++j) {
|
|
||||||
template[n - 6 + j] = "0123456789abcdefghijklmnopqrstuvwxyz"[x % 36];
|
|
||||||
x /= 36;
|
|
||||||
}
|
|
||||||
if (!mkdir(template, 0700)) {
|
|
||||||
return template;
|
|
||||||
}
|
|
||||||
if (errno != EEXIST) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (j = 0; j < 6; ++j) {
|
|
||||||
template[n - 6 + j] = 'X';
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
einval();
|
einval();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
for (;;) {
|
||||||
|
int x = _rand64();
|
||||||
|
for (int i = 0; i < 6; ++i) {
|
||||||
|
template[n - 6 + i] = "0123456789abcdefghikmnpqrstvwxyz"[x & 31];
|
||||||
|
x >>= 5;
|
||||||
|
}
|
||||||
|
int e = errno;
|
||||||
|
if (!mkdir(template, 0700)) {
|
||||||
|
return template;
|
||||||
|
} else if (errno != EEXIST) {
|
||||||
|
memcpy(template + n - 6, "XXXXXX", 6);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
errno = e;
|
||||||
}
|
}
|
||||||
return 0;
|
|
||||||
}
|
}
|
42
libc/calls/mkostemp.c
Normal file
42
libc/calls/mkostemp.c
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
/*-*- 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 2020 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/temp.h"
|
||||||
|
#include "libc/sysv/consts/at.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates temporary file name and file descriptor, e.g.
|
||||||
|
*
|
||||||
|
* char path[] = "/tmp/foo.XXXXXX";
|
||||||
|
* int fd = mkostemp(path, O_CLOEXEC);
|
||||||
|
* printf("%s is opened as %d\n", path, fd);
|
||||||
|
*
|
||||||
|
* @param template is mutated to replace last six X's with rng
|
||||||
|
* @return open file descriptor r + w exclusive or -1 w/ errno
|
||||||
|
* @raise EINVAL if `template` didn't end with `XXXXXX`
|
||||||
|
* @see openatemp() for one temp roller to rule them all
|
||||||
|
* @see mkostemps() if you need a suffix
|
||||||
|
* @see mkstemp() if you don't need flags
|
||||||
|
* @see mktemp() if you don't need an fd
|
||||||
|
* @see tmpfd() if you don't need a path
|
||||||
|
*/
|
||||||
|
int mkostemp(char *template, unsigned flags) {
|
||||||
|
return openatemp(AT_FDCWD, template, 0, flags, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
__strong_reference(mkostemp, mkostemp64);
|
43
libc/calls/mkostemps.c
Normal file
43
libc/calls/mkostemps.c
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
/*-*- 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 2020 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/temp.h"
|
||||||
|
#include "libc/sysv/consts/at.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates temporary file name and file descriptor, e.g.
|
||||||
|
*
|
||||||
|
* char path[] = "/tmp/foo.XXXXXX";
|
||||||
|
* int fd = mkostemp(path, O_CLOEXEC);
|
||||||
|
* printf("%s is opened as %d\n", path, fd);
|
||||||
|
*
|
||||||
|
* @param template is mutated to replace last six X's with rng
|
||||||
|
* @return open file descriptor r + w exclusive or -1 w/ errno
|
||||||
|
* @raise EINVAL if `template` didn't end with `XXXXXX`
|
||||||
|
* @see openatemp() for one temp roller to rule them all
|
||||||
|
* @see mkstemp() if you don't need suffix/flags
|
||||||
|
* @see mkstemps() if you don't need flags
|
||||||
|
* @see mkostemp() if you don't need suffix
|
||||||
|
* @see mktemp() if you don't need an fd
|
||||||
|
* @see tmpfd() if you don't need a path
|
||||||
|
*/
|
||||||
|
int mkostemps(char *template, int suffixlen, unsigned flags) {
|
||||||
|
return openatemp(AT_FDCWD, template, suffixlen, flags, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
__strong_reference(mkostemps, mkostemps64);
|
|
@ -16,67 +16,27 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/temp.h"
|
||||||
#include "libc/dce.h"
|
#include "libc/sysv/consts/at.h"
|
||||||
#include "libc/errno.h"
|
|
||||||
#include "libc/intrin/bits.h"
|
|
||||||
#include "libc/stdio/rand.h"
|
|
||||||
#include "libc/stdio/temp.h"
|
|
||||||
#include "libc/str/str.h"
|
|
||||||
#include "libc/sysv/consts/o.h"
|
|
||||||
#include "libc/sysv/errfuns.h"
|
|
||||||
|
|
||||||
int _mkstemp(char *template, int oflags) {
|
|
||||||
uint64_t w;
|
|
||||||
int i, n, e, fd;
|
|
||||||
if ((n = strlen(template)) < 6 ||
|
|
||||||
READ16LE(template + n - 2) != READ16LE("XX") ||
|
|
||||||
READ32LE(template + n - 6) != READ32LE("XXXX")) {
|
|
||||||
return einval();
|
|
||||||
}
|
|
||||||
for (;;) {
|
|
||||||
w = _rand64();
|
|
||||||
for (i = 0; i < 6; ++i) {
|
|
||||||
template[n - 6 + i] = "0123456789abcdefghijklmnopqrstuvwxyz"[w % 36];
|
|
||||||
w /= 36;
|
|
||||||
}
|
|
||||||
e = errno;
|
|
||||||
if ((fd = open(template, O_RDWR | O_CREAT | O_EXCL | oflags, 0600)) != -1) {
|
|
||||||
return fd;
|
|
||||||
} else if (errno == EEXIST) {
|
|
||||||
errno = e;
|
|
||||||
} else {
|
|
||||||
template[0] = 0;
|
|
||||||
return fd;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates temporary file name and file descriptor.
|
* Creates temporary file name and file descriptor, e.g.
|
||||||
*
|
*
|
||||||
* The best way to construct your path template is:
|
* char path[] = "/tmp/foo.XXXXXX";
|
||||||
*
|
* int fd = mkstemp(path);
|
||||||
* char path[PATH_MAX+1];
|
* printf("%s is opened as %d\n", path, fd);
|
||||||
* strlcat(path, kTmpDir, sizeof(path));
|
|
||||||
* strlcat(path, "sauce.XXXXXX", sizeof(path));
|
|
||||||
*
|
|
||||||
* This usage pattern makes mkstemp() equivalent to tmpfd():
|
|
||||||
*
|
|
||||||
* int fd;
|
|
||||||
* fd = mkstemp(path);
|
|
||||||
* unlink(path);
|
|
||||||
*
|
|
||||||
* This usage pattern makes mkstemp() equivalent to mktemp():
|
|
||||||
*
|
|
||||||
* close(mkstemp(path));
|
|
||||||
* puts(path);
|
|
||||||
*
|
*
|
||||||
* @param template is mutated to replace last six X's with rng
|
* @param template is mutated to replace last six X's with rng
|
||||||
* @return open file descriptor r + w exclusive or -1 w/ errno
|
* @return open file descriptor r + w exclusive or -1 w/ errno
|
||||||
* @raise EINVAL if `template` didn't end with `XXXXXX`
|
* @raise EINVAL if `template` didn't end with `XXXXXX`
|
||||||
|
* @see openatemp() for one temp roller to rule them all
|
||||||
|
* @see mkostemp() if you you need a `O_CLOEXEC`, `O_APPEND`, etc.
|
||||||
|
* @see mkstemps() if you you need a suffix
|
||||||
|
* @see mktemp() if you don't need an fd
|
||||||
* @see tmpfd() if you don't need a path
|
* @see tmpfd() if you don't need a path
|
||||||
*/
|
*/
|
||||||
int mkstemp(char *template) {
|
int mkstemp(char *template) {
|
||||||
return _mkstemp(template, 0);
|
return openatemp(AT_FDCWD, template, 0, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
__strong_reference(mkstemp, mkstemp64);
|
||||||
|
|
44
libc/calls/mkstemps.c
Normal file
44
libc/calls/mkstemps.c
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
/*-*- 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 2020 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/temp.h"
|
||||||
|
#include "libc/sysv/consts/at.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates temporary file name and file descriptor, e.g.
|
||||||
|
*
|
||||||
|
* char path[] = "/tmp/foo.XXXXXX.txt";
|
||||||
|
* int fd = mkstemps(path, 4);
|
||||||
|
* printf("%s is opened as %d\n", path, fd);
|
||||||
|
*
|
||||||
|
* @param template is mutated to replace last six X's with rng
|
||||||
|
* @param suffixlen may be nonzero to permit characters after the "XXXXXX"
|
||||||
|
* @return open file descriptor r + w exclusive or -1 w/ errno
|
||||||
|
* @raise EINVAL if `template` (less the `suffixlen` region) didn't
|
||||||
|
* end with the string "XXXXXXX"
|
||||||
|
* @see mkostemp() if you you need a `O_CLOEXEC`, `O_APPEND`, etc.
|
||||||
|
* @see openatemp() for one temp roller to rule them all
|
||||||
|
* @see mkstemp() if you don't need `suffixlen`
|
||||||
|
* @see mktemp() if you don't need an fd
|
||||||
|
* @see tmpfd() if you don't need a path
|
||||||
|
*/
|
||||||
|
int mkstemps(char *template, int suffixlen) {
|
||||||
|
return openatemp(AT_FDCWD, template, suffixlen, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
__strong_reference(mkstemps, mkstemps64);
|
|
@ -16,8 +16,10 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
|
#include "libc/assert.h"
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
#include "libc/stdio/temp.h"
|
#include "libc/sysv/consts/at.h"
|
||||||
|
#include "libc/temp.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates temporary filename.
|
* Generates temporary filename.
|
||||||
|
@ -27,15 +29,20 @@
|
||||||
*
|
*
|
||||||
* @param template is mutated to replace last six X's with rng
|
* @param template is mutated to replace last six X's with rng
|
||||||
* @raise EINVAL if `template` didn't end with `XXXXXX`
|
* @raise EINVAL if `template` didn't end with `XXXXXX`
|
||||||
* @return pointer to mutated `template`, or 0 w/ errno
|
* @return always `template` which on success will have its XXXXXX bytes
|
||||||
* @see mkstemp()
|
* mutated to a random value, otherwise on error it'll hold an empty
|
||||||
|
* string and `errno` will be set
|
||||||
|
* @see mkstemp() if you you need a file descriptor
|
||||||
|
* @see mkstemps() if you you need a file extension
|
||||||
|
* @see openatemp() for one temp roller to rule them all
|
||||||
|
* @see mkostemp() if you you need a `O_CLOEXEC`, `O_APPEND`, etc.
|
||||||
*/
|
*/
|
||||||
char *mktemp(char *template) {
|
char *mktemp(char *template) {
|
||||||
int fd;
|
int fd;
|
||||||
if ((fd = mkstemp(template)) != -1) {
|
if ((fd = openatemp(AT_FDCWD, template, 0, 0, 0)) != -1) {
|
||||||
close(fd);
|
unassert(!close(fd));
|
||||||
return template;
|
|
||||||
} else {
|
} else {
|
||||||
return 0;
|
*template = 0;
|
||||||
}
|
}
|
||||||
|
return template;
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,9 +66,11 @@ struct SpawnBlock {
|
||||||
*/
|
*/
|
||||||
textwindows int ntspawn(
|
textwindows int ntspawn(
|
||||||
const char *prog, char *const argv[], char *const envp[],
|
const char *prog, char *const argv[], char *const envp[],
|
||||||
const char *extravar, struct NtSecurityAttributes *opt_lpProcessAttributes,
|
const char *extravar,
|
||||||
struct NtSecurityAttributes *opt_lpThreadAttributes, bool32 bInheritHandles,
|
const struct NtSecurityAttributes *opt_lpProcessAttributes,
|
||||||
uint32_t dwCreationFlags, const char16_t *opt_lpCurrentDirectory,
|
const struct NtSecurityAttributes *opt_lpThreadAttributes,
|
||||||
|
bool32 bInheritHandles, uint32_t dwCreationFlags,
|
||||||
|
const char16_t *opt_lpCurrentDirectory,
|
||||||
const struct NtStartupInfo *lpStartupInfo,
|
const struct NtStartupInfo *lpStartupInfo,
|
||||||
struct NtProcessInformation *opt_out_lpProcessInformation) {
|
struct NtProcessInformation *opt_out_lpProcessInformation) {
|
||||||
int rc;
|
int rc;
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#ifndef COSMOPOLITAN_LIBC_CALLS_NTSPAWN_H_
|
#ifndef COSMOPOLITAN_LIBC_CALLS_NTSPAWN_H_
|
||||||
#define COSMOPOLITAN_LIBC_CALLS_NTSPAWN_H_
|
#define COSMOPOLITAN_LIBC_CALLS_NTSPAWN_H_
|
||||||
|
#include "libc/limits.h"
|
||||||
#include "libc/nt/struct/processinformation.h"
|
#include "libc/nt/struct/processinformation.h"
|
||||||
#include "libc/nt/struct/securityattributes.h"
|
#include "libc/nt/struct/securityattributes.h"
|
||||||
#include "libc/nt/struct/startupinfo.h"
|
#include "libc/nt/struct/startupinfo.h"
|
||||||
|
@ -10,8 +11,9 @@ int mkntcmdline(char16_t[ARG_MAX / 2], char *const[]);
|
||||||
int mkntenvblock(char16_t[ARG_MAX / 2], char *const[], const char *,
|
int mkntenvblock(char16_t[ARG_MAX / 2], char *const[], const char *,
|
||||||
char[ARG_MAX]);
|
char[ARG_MAX]);
|
||||||
int ntspawn(const char *, char *const[], char *const[], const char *,
|
int ntspawn(const char *, char *const[], char *const[], const char *,
|
||||||
struct NtSecurityAttributes *, struct NtSecurityAttributes *,
|
const struct NtSecurityAttributes *,
|
||||||
bool32, uint32_t, const char16_t *, const struct NtStartupInfo *,
|
const struct NtSecurityAttributes *, bool32, uint32_t,
|
||||||
|
const char16_t *, const struct NtStartupInfo *,
|
||||||
struct NtProcessInformation *);
|
struct NtProcessInformation *);
|
||||||
|
|
||||||
COSMOPOLITAN_C_END_
|
COSMOPOLITAN_C_END_
|
||||||
|
|
|
@ -23,14 +23,17 @@
|
||||||
#include "libc/calls/syscall-nt.internal.h"
|
#include "libc/calls/syscall-nt.internal.h"
|
||||||
#include "libc/calls/syscall_support-nt.internal.h"
|
#include "libc/calls/syscall_support-nt.internal.h"
|
||||||
#include "libc/errno.h"
|
#include "libc/errno.h"
|
||||||
#include "libc/intrin/kprintf.h"
|
#include "libc/macros.internal.h"
|
||||||
#include "libc/nt/createfile.h"
|
#include "libc/nt/createfile.h"
|
||||||
|
#include "libc/nt/enum/accessmask.h"
|
||||||
#include "libc/nt/enum/creationdisposition.h"
|
#include "libc/nt/enum/creationdisposition.h"
|
||||||
#include "libc/nt/enum/fileflagandattributes.h"
|
#include "libc/nt/enum/fileflagandattributes.h"
|
||||||
|
#include "libc/nt/enum/filesharemode.h"
|
||||||
#include "libc/nt/enum/filetype.h"
|
#include "libc/nt/enum/filetype.h"
|
||||||
#include "libc/nt/files.h"
|
#include "libc/nt/files.h"
|
||||||
#include "libc/nt/process.h"
|
#include "libc/nt/process.h"
|
||||||
#include "libc/nt/runtime.h"
|
#include "libc/nt/runtime.h"
|
||||||
|
#include "libc/nt/synchronization.h"
|
||||||
#include "libc/nt/thunk/msabi.h"
|
#include "libc/nt/thunk/msabi.h"
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
#include "libc/sysv/consts/fileno.h"
|
#include "libc/sysv/consts/fileno.h"
|
||||||
|
@ -98,6 +101,16 @@ static textwindows int64_t sys_open_nt_impl(int dirfd, const char *path,
|
||||||
return kNtInvalidHandleValue;
|
return kNtInvalidHandleValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (fattr != -1u) {
|
||||||
|
// "We have been asked to create a read-only file. "If the file
|
||||||
|
// already exists, the semantics of the Unix open system call is to
|
||||||
|
// preserve the existing permissions. If we pass CREATE_ALWAYS and
|
||||||
|
// FILE_ATTRIBUTE_READONLY to CreateFile, and the file already
|
||||||
|
// exists, CreateFile will change the file permissions. Avoid that to
|
||||||
|
// preserve the Unix semantics." -Quoth GoLang syscall_windows.go
|
||||||
|
attr &= ~kNtFileAttributeReadonly;
|
||||||
|
}
|
||||||
|
|
||||||
// kNtTruncateExisting always returns kNtErrorInvalidParameter :'(
|
// kNtTruncateExisting always returns kNtErrorInvalidParameter :'(
|
||||||
if (disp == kNtTruncateExisting) {
|
if (disp == kNtTruncateExisting) {
|
||||||
if (fattr != -1u) {
|
if (fattr != -1u) {
|
||||||
|
@ -107,10 +120,24 @@ static textwindows int64_t sys_open_nt_impl(int dirfd, const char *path,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We optimistically request some write permissions in O_RDONLY mode.
|
||||||
|
// But that might prevent opening some files. So reactively back off.
|
||||||
|
int extra_perm = 0;
|
||||||
|
if ((flags & O_ACCMODE) == O_RDONLY) {
|
||||||
|
extra_perm = kNtFileWriteAttributes | kNtFileWriteEa;
|
||||||
|
}
|
||||||
|
|
||||||
// open the file, following symlinks
|
// open the file, following symlinks
|
||||||
return __fix_enotdir(CreateFile(path16, perm, share, &kNtIsInheritable, disp,
|
int e = errno;
|
||||||
attr | extra_attr, 0),
|
int64_t hand = CreateFile(path16, perm | extra_perm, share, &kNtIsInheritable,
|
||||||
path16);
|
disp, attr | extra_attr, 0);
|
||||||
|
if (hand == -1 && errno == EACCES && (flags & O_ACCMODE) == O_RDONLY) {
|
||||||
|
errno = e;
|
||||||
|
hand = CreateFile(path16, perm, share, &kNtIsInheritable, disp,
|
||||||
|
attr | extra_attr, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return __fix_enotdir(hand, path16);
|
||||||
}
|
}
|
||||||
|
|
||||||
static textwindows int sys_open_nt_console(int dirfd,
|
static textwindows int sys_open_nt_console(int dirfd,
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include "libc/calls/syscall-sysv.internal.h"
|
#include "libc/calls/syscall-sysv.internal.h"
|
||||||
#include "libc/dce.h"
|
#include "libc/dce.h"
|
||||||
#include "libc/errno.h"
|
#include "libc/errno.h"
|
||||||
|
#include "libc/fmt/itoa.h"
|
||||||
#include "libc/intrin/asan.internal.h"
|
#include "libc/intrin/asan.internal.h"
|
||||||
#include "libc/intrin/describeflags.internal.h"
|
#include "libc/intrin/describeflags.internal.h"
|
||||||
#include "libc/intrin/strace.internal.h"
|
#include "libc/intrin/strace.internal.h"
|
||||||
|
@ -92,6 +93,7 @@
|
||||||
* - `O_APPEND` open file for appending only
|
* - `O_APPEND` open file for appending only
|
||||||
* - `O_NOFOLLOW` fail with ELOOP if it's a symlink
|
* - `O_NOFOLLOW` fail with ELOOP if it's a symlink
|
||||||
* - `O_NONBLOCK` asks read/write to fail with `EAGAIN` rather than block
|
* - `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_EXEC` open file for execution only; see fexecve()
|
||||||
* - `O_NOCTTY` prevents `path` from becoming the controlling terminal
|
* - `O_NOCTTY` prevents `path` from becoming the controlling terminal
|
||||||
* - `O_DIRECTORY` advisory feature for avoiding accidentally opening files
|
* - `O_DIRECTORY` advisory feature for avoiding accidentally opening files
|
||||||
|
@ -107,7 +109,7 @@
|
||||||
* - `O_SEQUENTIAL` hint sequential 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_COMPRESSED` ask fs to abstract compression (zero on non-Windows)
|
||||||
* - `O_INDEXED` turns on that slow performance (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:
|
* There are three regular combinations for the above flags:
|
||||||
* - `O_RDONLY`: Opens existing file for reading. If it doesn't
|
* - `O_RDONLY`: Opens existing file for reading. If it doesn't
|
||||||
* exist then nil is returned and errno will be `ENOENT` (or in
|
* 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 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 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 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 `O_TRUNC` is specified in `O_RDONLY` mode
|
||||||
* @raise EINVAL if `flags` contains unsupported bits
|
* @raise EINVAL if `flags` contains unsupported bits
|
||||||
* @raise ECANCELED if thread was cancelled in masked mode
|
* @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))) {
|
if (!path || (IsAsan() && !__asan_is_valid_str(path))) {
|
||||||
rc = efault();
|
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)) {
|
} else if (__isfdkind(dirfd, kFdZip)) {
|
||||||
rc = enotsup(); // TODO
|
rc = enotsup(); // TODO
|
||||||
} else if (_weaken(__zipos_open) &&
|
} else if (_weaken(__zipos_open) &&
|
||||||
|
@ -190,20 +202,29 @@ int openat(int dirfd, const char *path, int flags, ...) {
|
||||||
rc = enotsup(); // TODO
|
rc = enotsup(); // TODO
|
||||||
}
|
}
|
||||||
} else if ((flags & O_ACCMODE) == O_RDONLY && (flags & O_TRUNC)) {
|
} 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()) {
|
} else if (IsLinux() || IsXnu() || IsFreebsd() || IsOpenbsd() || IsNetbsd()) {
|
||||||
rc = sys_openat(dirfd, path, flags, mode);
|
// openat unix userspace
|
||||||
if (IsFreebsd()) {
|
rc = sys_openat(dirfd, path, flags & ~O_UNLINK, mode);
|
||||||
// Address FreeBSD divergence from IEEE Std 1003.1-2008 (POSIX.1)
|
if (rc != -1) {
|
||||||
// in the case when O_NOFOLLOW is used, but fails due to symlink.
|
// openat succeeded
|
||||||
if (rc == -1 && errno == EMLINK) {
|
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;
|
errno = ELOOP;
|
||||||
}
|
}
|
||||||
}
|
if (IsNetbsd() && errno == EFTYPE) {
|
||||||
if (IsNetbsd()) {
|
// Address NetBSD divergence from IEEE Std 1003.1-2008 (POSIX.1)
|
||||||
// Address NetBSD divergence from IEEE Std 1003.1-2008 (POSIX.1)
|
// in the case when O_NOFOLLOW is used but fails due to symlink.
|
||||||
// in the case when O_NOFOLLOW is used but fails due to symlink.
|
|
||||||
if (rc == -1 && errno == EFTYPE) {
|
|
||||||
errno = ELOOP;
|
errno = ELOOP;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -216,9 +237,8 @@ int openat(int dirfd, const char *path, int flags, ...) {
|
||||||
}
|
}
|
||||||
|
|
||||||
END_CANCELLATION_POINT;
|
END_CANCELLATION_POINT;
|
||||||
STRACE("openat(%s, %#s, %s, %#o) → %d% m", DescribeDirfd(dirfd), path,
|
STRACE("openat(%s, %#s, %s%s) → %d% m", DescribeDirfd(dirfd), path,
|
||||||
DescribeOpenFlags(flags), (flags & (O_CREAT | O_TMPFILE)) ? mode : 0,
|
DescribeOpenFlags(flags), DescribeOpenMode(flags, mode), rc);
|
||||||
rc);
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
127
libc/calls/openatemp.c
Normal file
127
libc/calls/openatemp.c
Normal file
|
@ -0,0 +1,127 @@
|
||||||
|
/*-*- 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 2020 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/errno.h"
|
||||||
|
#include "libc/intrin/bits.h"
|
||||||
|
#include "libc/stdio/rand.h"
|
||||||
|
#include "libc/str/str.h"
|
||||||
|
#include "libc/sysv/consts/o.h"
|
||||||
|
#include "libc/sysv/errfuns.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opens unique temporary file with maximum generality.
|
||||||
|
*
|
||||||
|
* This function is similar to mkstemp() in that it does two things:
|
||||||
|
*
|
||||||
|
* 1. Generate a unique filename by mutating `template`
|
||||||
|
* 2. Return a newly opened file descriptor to the name
|
||||||
|
*
|
||||||
|
* Exclusive secure access is assured even if `/tmp` is being used on a
|
||||||
|
* UNIX system like Super Dimensional Fortress or CPanel where multiple
|
||||||
|
* hostile adverserial users may exist on a single multi-tenant system.
|
||||||
|
*
|
||||||
|
* The substring XXXXXX is replaced with 30 bits of base32 entropy and a
|
||||||
|
* hundred retries are attempted in the event of collisions. The XXXXXXX
|
||||||
|
* pattern must be present at the end of the supplied template string.
|
||||||
|
*
|
||||||
|
* If the generated filename needs to have a file extension (rather than
|
||||||
|
* ending with random junk) then this API has the helpful `suffixlen` to
|
||||||
|
* specify exactly how long that suffix in the template actually is. For
|
||||||
|
* example if the template is `"/tmp/notes.XXXXXX.txt"` then `suffixlen`
|
||||||
|
* should be `4`.
|
||||||
|
*
|
||||||
|
* The flags `O_RDWR | O_CREAT | O_EXCL` are always set and don't need
|
||||||
|
* to be specified by the caller. It's a good idea to pass `O_CLOEXEC`
|
||||||
|
* and some applications may want `O_APPEND`. Cosmopolitan also offers
|
||||||
|
* `O_UNLINK` which will ensure the created file will delete itself on
|
||||||
|
* close similar to calling unlink() after this function on `template`
|
||||||
|
* which is mutated on success, except `O_UNLINK` will work right when
|
||||||
|
* running on Windows and it's polyfilled automatically on UNIX.
|
||||||
|
*
|
||||||
|
* The `mode` parameter should usually be `0600` to ensure owner-only
|
||||||
|
* read/write access. However it may be useful to set this to `0700`
|
||||||
|
* when creating executable files. Please note that sometimes `/tmp` is
|
||||||
|
* mounted by system administrators as `noexec`. It's also permissible
|
||||||
|
* to pass `0` here, since the `0600` bits are always set implicitly.
|
||||||
|
*
|
||||||
|
* ### Examples
|
||||||
|
*
|
||||||
|
* Here's an example of how to replicate the functionality of tmpfile()
|
||||||
|
* which creates an unnamed temporary file as an stdio handle, which is
|
||||||
|
* guaranteed to either not have a name (unlinked on UNIX), or shall be
|
||||||
|
* deleted once closed (will perform kNtFileFlagDeleteOnClose on WIN32)
|
||||||
|
*
|
||||||
|
* char path[] = "/tmp/XXXXXX";
|
||||||
|
* int fd = openatemp(AT_FDCWD, path, 0, O_UNLINK, 0);
|
||||||
|
* FILE *tmp = fdopen(fd, "w+");
|
||||||
|
*
|
||||||
|
* Here's an example of how to do mktemp() does, where a temporary file
|
||||||
|
* name is generated with pretty good POSIX and security best practices
|
||||||
|
*
|
||||||
|
* char path[PATH_MAX+1];
|
||||||
|
* const char *tmpdir = getenv("TMPDIR");
|
||||||
|
* strlcpy(path, tmpdir ? tmpdir : "/tmp", sizeof(path));
|
||||||
|
* strlcat(path, "/notes.XXXXXX.txt", sizeof(path));
|
||||||
|
* close(openatemp(AT_FDCWD, path, 4, O_UNLINK, 0));
|
||||||
|
* printf("you can use %s to store your notes\n", path);
|
||||||
|
*
|
||||||
|
* @param dirfd is open directory file descriptor, which is ignored if
|
||||||
|
* `template` is an absolute path; or `AT_FDCWD` to specify getcwd
|
||||||
|
* @param template is a pathname relative to current directory by default,
|
||||||
|
* that needs to have "XXXXXX" at the end of the string; this memory
|
||||||
|
* must be mutable and should be owned by the calling thread; it will
|
||||||
|
* be modified (only on success) to return the generated filename; it
|
||||||
|
* is recommended that the caller use `kTmpPath` at the beginning of
|
||||||
|
* the generated `template` path and then set `dirfd` to `AT_FDCWD`
|
||||||
|
* @param suffixlen may be nonzero to permit characters after the "XXXXXX"
|
||||||
|
* @param mode is conventionally 0600, for owner-only non-exec access
|
||||||
|
* @param flags could have O_APPEND, O_CLOEXEC, O_UNLINK, O_SYNC, etc.
|
||||||
|
* @return exclusive open file descriptor for file at the generated path
|
||||||
|
* stored to `template`, or -1 w/ errno
|
||||||
|
* @raise EINVAL if `template` (less the `suffixlen` region) didn't
|
||||||
|
* end with the string "XXXXXXX"
|
||||||
|
* @raise EINVAL if `suffixlen` was negative or too large
|
||||||
|
*/
|
||||||
|
int openatemp(int dirfd, char *template, int suffixlen, int flags, int mode) {
|
||||||
|
flags &= ~O_ACCMODE;
|
||||||
|
flags |= O_RDWR | O_CREAT | O_EXCL;
|
||||||
|
int len = strlen(template);
|
||||||
|
if (6 + suffixlen < 6 || 6 + suffixlen > len ||
|
||||||
|
READ32LE(template + len - suffixlen - 6) != READ32LE("XXXX") ||
|
||||||
|
READ16LE(template + len - suffixlen - 6 + 4) != READ16LE("XX")) {
|
||||||
|
return einval();
|
||||||
|
}
|
||||||
|
for (;;) {
|
||||||
|
int w = _rand64();
|
||||||
|
for (int i = 0; i < 6; ++i) {
|
||||||
|
template[len - suffixlen - 6 + i] =
|
||||||
|
"0123456789abcdefghikmnpqrstvwxyz"[w & 31];
|
||||||
|
w >>= 5;
|
||||||
|
}
|
||||||
|
int fd, e = errno;
|
||||||
|
if ((fd = openat(dirfd, template, flags, mode | 0600)) != -1) {
|
||||||
|
return fd;
|
||||||
|
} else if (errno == EEXIST) {
|
||||||
|
errno = e;
|
||||||
|
} else {
|
||||||
|
memcpy(template + len - suffixlen - 6, "XXXXXX", 6);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
/*-*- 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│
|
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||||
│ Copyright 2022 Justine Alexandra Roberts Tunney │
|
│ Copyright 2023 Justine Alexandra Roberts Tunney │
|
||||||
│ │
|
│ │
|
||||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||||
│ any purpose with or without fee is hereby granted, provided that the │
|
│ any purpose with or without fee is hereby granted, provided that the │
|
||||||
|
@ -16,13 +16,21 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/calls/struct/termios.h"
|
#include "libc/calls/calls.h"
|
||||||
#include "libc/calls/termios.h"
|
#include "libc/runtime/runtime.h"
|
||||||
#include "libc/sysv/consts/termios.h"
|
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
/**
|
||||||
struct termios t;
|
* Returns environment variable, securely.
|
||||||
if (tcgetattr(0, &t) == -1) return 1;
|
*
|
||||||
t.c_lflag ^= ECHOCTL;
|
* This is the same as getenv() except it'll return null if current
|
||||||
if (tcsetattr(0, TCSANOW, &t) == -1) return 2;
|
* process is a setuid / setgid program.
|
||||||
|
*
|
||||||
|
* @param name is environment variable key name, which may not be null
|
||||||
|
*/
|
||||||
|
char *secure_getenv(const char *name) {
|
||||||
|
if (!issetugid()) {
|
||||||
|
return getenv(name);
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -14,8 +14,8 @@ struct dirent { /* linux getdents64 abi */
|
||||||
struct dirstream;
|
struct dirstream;
|
||||||
typedef struct dirstream DIR;
|
typedef struct dirstream DIR;
|
||||||
|
|
||||||
DIR *fdopendir(int) dontdiscard;
|
DIR *fdopendir(int) __wur;
|
||||||
DIR *opendir(const char *) dontdiscard;
|
DIR *opendir(const char *) __wur;
|
||||||
int closedir(DIR *);
|
int closedir(DIR *);
|
||||||
int dirfd(DIR *);
|
int dirfd(DIR *);
|
||||||
long telldir(DIR *);
|
long telldir(DIR *);
|
||||||
|
|
|
@ -25,7 +25,7 @@ int sys_nanosleep_xnu(const struct timespec *, struct timespec *);
|
||||||
int sys_sem_timedwait(int64_t, const struct timespec *);
|
int sys_sem_timedwait(int64_t, const struct timespec *);
|
||||||
int sys_utimensat(int, const char *, const struct timespec[2], int);
|
int sys_utimensat(int, const char *, const struct timespec[2], int);
|
||||||
int sys_utimensat_nt(int, const char *, const struct timespec[2], int);
|
int sys_utimensat_nt(int, const char *, const struct timespec[2], int);
|
||||||
int sys_utimensat_xnu(int, const char *, const struct timespec[2], int);
|
int sys_utimensat_old(int, const char *, const struct timespec[2], int);
|
||||||
|
|
||||||
const char *DescribeTimespec(char[45], int, const struct timespec *);
|
const char *DescribeTimespec(char[45], int, const struct timespec *);
|
||||||
#define DescribeTimespec(rc, ts) DescribeTimespec(alloca(45), rc, ts)
|
#define DescribeTimespec(rc, ts) DescribeTimespec(alloca(45), rc, ts)
|
||||||
|
|
|
@ -26,7 +26,7 @@ int sys_linkat_nt(int, const char *, int, const char *);
|
||||||
int sys_madvise_nt(void *, size_t, int);
|
int sys_madvise_nt(void *, size_t, int);
|
||||||
int sys_mkdirat_nt(int, const char *, uint32_t);
|
int sys_mkdirat_nt(int, const char *, uint32_t);
|
||||||
int sys_msync_nt(char *, size_t, int);
|
int sys_msync_nt(char *, size_t, int);
|
||||||
int sys_open_nt(int, const char *, uint32_t, int32_t) dontdiscard;
|
int sys_open_nt(int, const char *, uint32_t, int32_t) __wur;
|
||||||
int sys_pipe_nt(int[hasatleast 2], unsigned);
|
int sys_pipe_nt(int[hasatleast 2], unsigned);
|
||||||
int sys_renameat_nt(int, const char *, int, const char *);
|
int sys_renameat_nt(int, const char *, int, const char *);
|
||||||
int sys_sched_yield_nt(void);
|
int sys_sched_yield_nt(void);
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#ifndef COSMOPOLITAN_LIBC_CALLS_SYSCALL_SUPPORT_NT_INTERNAL_H_
|
#ifndef COSMOPOLITAN_LIBC_CALLS_SYSCALL_SUPPORT_NT_INTERNAL_H_
|
||||||
#define COSMOPOLITAN_LIBC_CALLS_SYSCALL_SUPPORT_NT_INTERNAL_H_
|
#define COSMOPOLITAN_LIBC_CALLS_SYSCALL_SUPPORT_NT_INTERNAL_H_
|
||||||
|
#include "libc/limits.h"
|
||||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||||
COSMOPOLITAN_C_START_
|
COSMOPOLITAN_C_START_
|
||||||
|
|
||||||
|
|
|
@ -15,13 +15,13 @@ int tcsetattr(int, int, const struct termios *);
|
||||||
int openpty(int *, int *, char *, const struct termios *,
|
int openpty(int *, int *, char *, const struct termios *,
|
||||||
const struct winsize *) paramsnonnull((1, 2));
|
const struct winsize *) paramsnonnull((1, 2));
|
||||||
int forkpty(int *, char *, const struct termios *, const struct winsize *)
|
int forkpty(int *, char *, const struct termios *, const struct winsize *)
|
||||||
paramsnonnull((1, 2)) dontdiscard;
|
paramsnonnull((1, 2)) __wur;
|
||||||
char *ptsname(int);
|
char *ptsname(int);
|
||||||
errno_t ptsname_r(int, char *, size_t);
|
errno_t ptsname_r(int, char *, size_t);
|
||||||
|
|
||||||
int grantpt(int);
|
int grantpt(int);
|
||||||
int unlockpt(int);
|
int unlockpt(int);
|
||||||
int posix_openpt(int) dontdiscard;
|
int posix_openpt(int) __wur;
|
||||||
|
|
||||||
int tcdrain(int);
|
int tcdrain(int);
|
||||||
int tcgetsid(int);
|
int tcgetsid(int);
|
||||||
|
|
|
@ -20,12 +20,14 @@
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
#include "libc/dce.h"
|
#include "libc/dce.h"
|
||||||
#include "libc/errno.h"
|
#include "libc/errno.h"
|
||||||
|
#include "libc/limits.h"
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
#include "libc/stdio/temp.h"
|
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
|
#include "libc/sysv/consts/at.h"
|
||||||
#include "libc/sysv/consts/o.h"
|
#include "libc/sysv/consts/o.h"
|
||||||
|
#include "libc/temp.h"
|
||||||
|
|
||||||
#define _O_TMPFILE 000020200000
|
#define O_TMPFILE_LINUX 0x00410000
|
||||||
|
|
||||||
int _mkstemp(char *, int);
|
int _mkstemp(char *, int);
|
||||||
|
|
||||||
|
@ -79,7 +81,7 @@ int tmpfd(void) {
|
||||||
char path[PATH_MAX + 1];
|
char path[PATH_MAX + 1];
|
||||||
if (IsLinux()) {
|
if (IsLinux()) {
|
||||||
e = errno;
|
e = errno;
|
||||||
if ((fd = open(kTmpPath, O_RDWR | _O_TMPFILE, 0600)) != -1) {
|
if ((fd = open(kTmpPath, O_RDWR | O_TMPFILE_LINUX, 0600)) != -1) {
|
||||||
return fd;
|
return fd;
|
||||||
} else {
|
} else {
|
||||||
errno = e;
|
errno = e;
|
||||||
|
@ -90,7 +92,6 @@ int tmpfd(void) {
|
||||||
if (!(prog = program_invocation_short_name)) prog = "tmp";
|
if (!(prog = program_invocation_short_name)) prog = "tmp";
|
||||||
strlcat(path, prog, sizeof(path));
|
strlcat(path, prog, sizeof(path));
|
||||||
strlcat(path, ".XXXXXX", sizeof(path));
|
strlcat(path, ".XXXXXX", sizeof(path));
|
||||||
if ((fd = _mkstemp(path, IsWindows() ? 0x00410000 : 0)) == -1) return -1;
|
if ((fd = openatemp(AT_FDCWD, path, 0, O_UNLINK, 0)) == -1) return -1;
|
||||||
if (!IsWindows()) unassert(!unlink(path));
|
|
||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
#include "libc/fmt/conv.h"
|
#include "libc/fmt/conv.h"
|
||||||
#include "libc/fmt/libgen.h"
|
#include "libc/fmt/libgen.h"
|
||||||
#include "libc/intrin/strace.internal.h"
|
#include "libc/intrin/strace.internal.h"
|
||||||
|
#include "libc/limits.h"
|
||||||
#include "libc/macros.internal.h"
|
#include "libc/macros.internal.h"
|
||||||
#include "libc/nexgen32e/vendor.internal.h"
|
#include "libc/nexgen32e/vendor.internal.h"
|
||||||
#include "libc/runtime/internal.h"
|
#include "libc/runtime/internal.h"
|
||||||
|
@ -175,7 +176,7 @@ static int unveil_init(void) {
|
||||||
.handled_access_fs = State.fs_mask,
|
.handled_access_fs = State.fs_mask,
|
||||||
};
|
};
|
||||||
// [undocumented] landlock_create_ruleset() always returns O_CLOEXEC
|
// [undocumented] landlock_create_ruleset() always returns O_CLOEXEC
|
||||||
// assert(__sys_fcntl(rc, F_GETFD, 0) == FD_CLOEXEC);
|
// assert(__sys_fcntl(rc, F_GETFD) == FD_CLOEXEC);
|
||||||
if ((rc = landlock_create_ruleset(&attr, sizeof(attr), 0)) < 0) return -1;
|
if ((rc = landlock_create_ruleset(&attr, sizeof(attr), 0)) < 0) return -1;
|
||||||
// grant file descriptor a higher number that's less likely to interfere
|
// grant file descriptor a higher number that's less likely to interfere
|
||||||
if ((fd = __sys_fcntl(rc, F_DUPFD_CLOEXEC, 100)) == -1) {
|
if ((fd = __sys_fcntl(rc, F_DUPFD_CLOEXEC, 100)) == -1) {
|
||||||
|
|
|
@ -48,12 +48,16 @@ int __utimens(int fd, const char *path, const struct timespec ts[2],
|
||||||
(path && (_weaken(__zipos_parseuri) &&
|
(path && (_weaken(__zipos_parseuri) &&
|
||||||
_weaken(__zipos_parseuri)(path, &zipname) != -1))) {
|
_weaken(__zipos_parseuri)(path, &zipname) != -1))) {
|
||||||
rc = erofs();
|
rc = erofs();
|
||||||
} else if (IsLinux() && !__is_linux_2_6_23() && fd == AT_FDCWD && !flags) {
|
} else if (IsXnu() || (IsLinux() && !__is_linux_2_6_23())) {
|
||||||
rc = sys_utimes(path, (void *)ts); // rhel5 truncates to seconds
|
rc = sys_utimensat_old(fd, path, ts, flags);
|
||||||
} else if (!IsWindows()) {
|
} else if (IsLinux() || IsFreebsd() || IsOpenbsd() || IsNetbsd()) {
|
||||||
rc = sys_utimensat(fd, path, ts, flags);
|
rc = sys_utimensat(fd, path, ts, flags);
|
||||||
} else {
|
} else if (IsWindows()) {
|
||||||
rc = sys_utimensat_nt(fd, path, ts, flags);
|
rc = sys_utimensat_nt(fd, path, ts, flags);
|
||||||
|
} else if (IsMetal()) {
|
||||||
|
rc = enosys();
|
||||||
|
} else {
|
||||||
|
rc = enosys();
|
||||||
}
|
}
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,8 +41,14 @@ textwindows int sys_utimensat_nt(int dirfd, const char *path,
|
||||||
|
|
||||||
if (path) {
|
if (path) {
|
||||||
if (__mkntpathat(dirfd, path, 0, path16) == -1) return -1;
|
if (__mkntpathat(dirfd, path, 0, path16) == -1) return -1;
|
||||||
if ((fh = CreateFile(path16, kNtFileWriteAttributes, kNtFileShareRead, NULL,
|
if ((fh = CreateFile(
|
||||||
kNtOpenExisting, kNtFileAttributeNormal, 0)) != -1) {
|
path16, kNtFileWriteAttributes,
|
||||||
|
kNtFileShareRead | kNtFileShareWrite | kNtFileShareDelete, NULL,
|
||||||
|
kNtOpenExisting,
|
||||||
|
kNtFileAttributeNormal | kNtFileFlagBackupSemantics |
|
||||||
|
((flags & AT_SYMLINK_NOFOLLOW) ? kNtFileFlagOpenReparsePoint
|
||||||
|
: 0),
|
||||||
|
0)) != -1) {
|
||||||
closeme = fh;
|
closeme = fh;
|
||||||
} else {
|
} else {
|
||||||
return __winerr();
|
return __winerr();
|
||||||
|
|
|
@ -16,27 +16,78 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
|
#include "libc/assert.h"
|
||||||
|
#include "libc/calls/calls.h"
|
||||||
#include "libc/calls/struct/stat.h"
|
#include "libc/calls/struct/stat.h"
|
||||||
|
#include "libc/calls/struct/stat.internal.h"
|
||||||
|
#include "libc/calls/struct/timespec.internal.h"
|
||||||
#include "libc/calls/struct/timeval.h"
|
#include "libc/calls/struct/timeval.h"
|
||||||
#include "libc/calls/struct/timeval.internal.h"
|
#include "libc/calls/struct/timeval.internal.h"
|
||||||
#include "libc/fmt/conv.h"
|
#include "libc/dce.h"
|
||||||
#include "libc/nexgen32e/nexgen32e.h"
|
#include "libc/fmt/itoa.h"
|
||||||
|
#include "libc/limits.h"
|
||||||
|
#include "libc/str/str.h"
|
||||||
#include "libc/sysv/consts/at.h"
|
#include "libc/sysv/consts/at.h"
|
||||||
#include "libc/sysv/consts/utime.h"
|
#include "libc/sysv/consts/utime.h"
|
||||||
#include "libc/sysv/errfuns.h"
|
#include "libc/sysv/errfuns.h"
|
||||||
#include "libc/time/time.h"
|
|
||||||
|
|
||||||
int sys_utimensat_xnu(int dirfd, const char *path, const struct timespec ts[2],
|
int sys_utimensat_old(int dirfd, const char *path, const struct timespec ts[2],
|
||||||
int flags) {
|
int flags) {
|
||||||
struct stat st;
|
char buf[PATH_MAX + 1];
|
||||||
struct timeval now, tv[2];
|
|
||||||
if (flags) return einval();
|
// validate usage
|
||||||
|
if (path) {
|
||||||
|
if (dirfd != AT_FDCWD) {
|
||||||
|
return enotsup();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
unassert(dirfd >= 0);
|
||||||
|
}
|
||||||
|
if (flags) {
|
||||||
|
return einval();
|
||||||
|
}
|
||||||
|
|
||||||
|
// xnu has futimes(), but rhel5 only has utimes()
|
||||||
|
// on linux we'll try to get the path from procfs
|
||||||
|
if (IsLinux() && !path) {
|
||||||
|
char procpath[36];
|
||||||
|
char *p = procpath;
|
||||||
|
p = stpcpy(p, "/proc/");
|
||||||
|
p = FormatInt32(p, getpid());
|
||||||
|
p = stpcpy(p, "/fd/");
|
||||||
|
p = FormatInt32(p, dirfd);
|
||||||
|
ssize_t got;
|
||||||
|
if ((got = readlink(procpath, buf, sizeof(buf))) == -1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (got == sizeof(buf)) {
|
||||||
|
return enametoolong();
|
||||||
|
}
|
||||||
|
unassert(buf[0] == '/');
|
||||||
|
buf[got] = 0;
|
||||||
|
path = buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
// perform preliminary system calls ahead of time
|
||||||
|
struct timeval now;
|
||||||
if (!ts || ts[0].tv_nsec == UTIME_NOW || ts[1].tv_nsec == UTIME_NOW) {
|
if (!ts || ts[0].tv_nsec == UTIME_NOW || ts[1].tv_nsec == UTIME_NOW) {
|
||||||
gettimeofday(&now, NULL);
|
unassert(!gettimeofday(&now, 0));
|
||||||
}
|
}
|
||||||
if (ts && (ts[0].tv_nsec == UTIME_NOW || ts[1].tv_nsec == UTIME_NOW)) {
|
struct stat st;
|
||||||
if (fstatat(dirfd, path, &st, flags) == -1) return -1;
|
if (ts && (ts[0].tv_nsec == UTIME_OMIT || ts[1].tv_nsec == UTIME_OMIT)) {
|
||||||
|
if (path) {
|
||||||
|
if (sys_fstatat(AT_FDCWD, path, &st, 0) == -1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (sys_fstat(dirfd, &st) == -1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// change the timestamps
|
||||||
|
struct timeval tv[2];
|
||||||
if (ts) {
|
if (ts) {
|
||||||
if (ts[0].tv_nsec == UTIME_NOW) {
|
if (ts[0].tv_nsec == UTIME_NOW) {
|
||||||
tv[0] = now;
|
tv[0] = now;
|
||||||
|
@ -56,17 +107,11 @@ int sys_utimensat_xnu(int dirfd, const char *path, const struct timespec ts[2],
|
||||||
tv[0] = now;
|
tv[0] = now;
|
||||||
tv[1] = now;
|
tv[1] = now;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// apply the new timestamps
|
||||||
if (path) {
|
if (path) {
|
||||||
if (dirfd == AT_FDCWD) {
|
return sys_utimes(path, tv);
|
||||||
return sys_utimes(path, tv);
|
|
||||||
} else {
|
|
||||||
return enosys();
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if (dirfd != AT_FDCWD) {
|
return sys_futimes(dirfd, tv);
|
||||||
return sys_futimes(dirfd, tv);
|
|
||||||
} else {
|
|
||||||
return einval();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -16,39 +16,37 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
|
#include "libc/assert.h"
|
||||||
#include "libc/calls/struct/timespec.internal.h"
|
#include "libc/calls/struct/timespec.internal.h"
|
||||||
#include "libc/calls/struct/timeval.internal.h"
|
#include "libc/calls/struct/timeval.internal.h"
|
||||||
#include "libc/dce.h"
|
#include "libc/dce.h"
|
||||||
#include "libc/errno.h"
|
#include "libc/errno.h"
|
||||||
#include "libc/fmt/conv.h"
|
#include "libc/fmt/conv.h"
|
||||||
|
#include "libc/runtime/zipos.internal.h"
|
||||||
#include "libc/sysv/consts/at.h"
|
#include "libc/sysv/consts/at.h"
|
||||||
#include "libc/time/time.h"
|
#include "libc/time/time.h"
|
||||||
#include "libc/runtime/zipos.internal.h"
|
|
||||||
|
|
||||||
int sys_utimensat(int dirfd, const char *path, const struct timespec ts[2],
|
int sys_utimensat(int dirfd, const char *path, const struct timespec ts[2],
|
||||||
int flags) {
|
int flags) {
|
||||||
int rc, olderr;
|
int rc, olderr;
|
||||||
struct timeval tv[2];
|
struct timeval tv[2];
|
||||||
if (!IsXnu()) {
|
unassert(!IsWindows() && !IsXnu());
|
||||||
if (!path && (IsFreebsd() || IsNetbsd() || IsOpenbsd())) {
|
if (!path && (IsFreebsd() || IsNetbsd() || IsOpenbsd())) {
|
||||||
rc = sys_futimens(dirfd, ts);
|
rc = sys_futimens(dirfd, ts);
|
||||||
} else {
|
} else {
|
||||||
olderr = errno;
|
olderr = errno;
|
||||||
rc = __sys_utimensat(dirfd, path, ts, flags);
|
rc = __sys_utimensat(dirfd, path, ts, flags);
|
||||||
// TODO(jart): How does RHEL5 do futimes()?
|
// TODO(jart): How does RHEL5 do futimes()?
|
||||||
if (rc == -1 && errno == ENOSYS && path) {
|
if (rc == -1 && errno == ENOSYS && path) {
|
||||||
errno = olderr;
|
errno = olderr;
|
||||||
if (ts) {
|
if (ts) {
|
||||||
tv[0] = timespec_totimeval(ts[0]);
|
tv[0] = timespec_totimeval(ts[0]);
|
||||||
tv[1] = timespec_totimeval(ts[1]);
|
tv[1] = timespec_totimeval(ts[1]);
|
||||||
rc = sys_utimes(path, tv);
|
rc = sys_utimes(path, tv);
|
||||||
} else {
|
} else {
|
||||||
rc = sys_utimes(path, NULL);
|
rc = sys_utimes(path, NULL);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return rc;
|
|
||||||
} else {
|
|
||||||
return sys_utimensat_xnu(dirfd, path, ts, flags);
|
|
||||||
}
|
}
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,17 +16,10 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/calls/asan.internal.h"
|
#include "libc/calls/struct/timespec.h"
|
||||||
#include "libc/calls/calls.h"
|
|
||||||
#include "libc/calls/internal.h"
|
|
||||||
#include "libc/calls/struct/timespec.internal.h"
|
#include "libc/calls/struct/timespec.internal.h"
|
||||||
#include "libc/dce.h"
|
|
||||||
#include "libc/intrin/asan.internal.h"
|
|
||||||
#include "libc/intrin/describeflags.internal.h"
|
#include "libc/intrin/describeflags.internal.h"
|
||||||
#include "libc/intrin/strace.internal.h"
|
#include "libc/intrin/strace.internal.h"
|
||||||
#include "libc/intrin/weaken.h"
|
|
||||||
#include "libc/runtime/zipos.internal.h"
|
|
||||||
#include "libc/sysv/consts/at.h"
|
|
||||||
#include "libc/sysv/errfuns.h"
|
#include "libc/sysv/errfuns.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -43,9 +36,10 @@
|
||||||
* @param dirfd can be `AT_FDCWD` or an open directory
|
* @param dirfd can be `AT_FDCWD` or an open directory
|
||||||
* @param path is filename whose timestamps should be modified
|
* @param path is filename whose timestamps should be modified
|
||||||
* @param ts is {access, modified} timestamps, or null for current time
|
* @param ts is {access, modified} timestamps, or null for current time
|
||||||
* @param flags can have `AT_SYMLINK_NOFOLLOW` when `path` is specified
|
* @param flags can have `AT_SYMLINK_NOFOLLOW`
|
||||||
* @return 0 on success, or -1 w/ errno
|
* @return 0 on success, or -1 w/ errno
|
||||||
* @raise EINVAL if `flags` had an unrecognized value
|
* @raise EINVAL if `flags` had an unrecognized value
|
||||||
|
* @raise EINVAL on XNU or RHEL5 when any `flags` are used
|
||||||
* @raise EPERM if pledge() is in play without `fattr` promise
|
* @raise EPERM if pledge() is in play without `fattr` promise
|
||||||
* @raise EACCES if unveil() is in play and `path` isn't unveiled
|
* @raise EACCES if unveil() is in play and `path` isn't unveiled
|
||||||
* @raise EINVAL if `ts` specifies a nanosecond value that's out of range
|
* @raise EINVAL if `ts` specifies a nanosecond value that's out of range
|
||||||
|
@ -54,23 +48,21 @@
|
||||||
* @raise EBADF if `dirfd` isn't a valid fd or `AT_FDCWD`
|
* @raise EBADF if `dirfd` isn't a valid fd or `AT_FDCWD`
|
||||||
* @raise EFAULT if `path` or `ts` memory was invalid
|
* @raise EFAULT if `path` or `ts` memory was invalid
|
||||||
* @raise EROFS if `path` is on read-only filesystem (e.g. zipos)
|
* @raise EROFS if `path` is on read-only filesystem (e.g. zipos)
|
||||||
* @raise ENOSYS on bare metal or on rhel5 when `dirfd` or `flags` is used
|
* @raise ENOTSUP on XNU or RHEL5 when `dirfd` isn't `AT_FDCWD`
|
||||||
|
* @raise ENOSYS on bare metal
|
||||||
* @asyncsignalsafe
|
* @asyncsignalsafe
|
||||||
* @threadsafe
|
* @threadsafe
|
||||||
*/
|
*/
|
||||||
int utimensat(int dirfd, const char *path, const struct timespec ts[2],
|
int utimensat(int dirfd, const char *path, const struct timespec ts[2],
|
||||||
int flags) {
|
int flags) {
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
if (!path) {
|
if (!path) {
|
||||||
rc = efault(); // linux kernel abi behavior isn't supported
|
rc = efault(); // linux kernel abi behavior isn't supported
|
||||||
} else {
|
} else {
|
||||||
rc = __utimens(dirfd, path, ts, flags);
|
rc = __utimens(dirfd, path, ts, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
STRACE("utimensat(%s, %#s, {%s, %s}, %#o) → %d% m", DescribeDirfd(dirfd),
|
STRACE("utimensat(%s, %#s, {%s, %s}, %#o) → %d% m", DescribeDirfd(dirfd),
|
||||||
path, DescribeTimespec(0, ts), DescribeTimespec(0, ts ? ts + 1 : 0),
|
path, DescribeTimespec(0, ts), DescribeTimespec(0, ts ? ts + 1 : 0),
|
||||||
flags, rc);
|
flags, rc);
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#include "libc/calls/struct/timeval.internal.h"
|
#include "libc/calls/struct/timeval.internal.h"
|
||||||
#include "libc/intrin/strace.internal.h"
|
#include "libc/intrin/strace.internal.h"
|
||||||
#include "libc/sysv/consts/at.h"
|
#include "libc/sysv/consts/at.h"
|
||||||
|
#include "libc/sysv/errfuns.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Changes last accessed/modified timestamps on file.
|
* Changes last accessed/modified timestamps on file.
|
||||||
|
@ -36,7 +37,9 @@
|
||||||
int utimes(const char *path, const struct timeval tv[2]) {
|
int utimes(const char *path, const struct timeval tv[2]) {
|
||||||
int rc;
|
int rc;
|
||||||
struct timespec ts[2];
|
struct timespec ts[2];
|
||||||
if (tv) {
|
if (!path) {
|
||||||
|
rc = efault();
|
||||||
|
} else if (tv) {
|
||||||
ts[0] = timeval_totimespec(tv[0]);
|
ts[0] = timeval_totimespec(tv[0]);
|
||||||
ts[1] = timeval_totimespec(tv[1]);
|
ts[1] = timeval_totimespec(tv[1]);
|
||||||
rc = __utimens(AT_FDCWD, path, ts, 0);
|
rc = __utimens(AT_FDCWD, path, ts, 0);
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#ifndef COSMOPOLITAN_LIBC_FMT_STRTOL_H_
|
#ifndef COSMOPOLITAN_LIBC_FMT_STRTOL_H_
|
||||||
#define COSMOPOLITAN_LIBC_FMT_STRTOL_H_
|
#define COSMOPOLITAN_LIBC_FMT_STRTOL_H_
|
||||||
#include "libc/errno.h"
|
#include "libc/errno.h"
|
||||||
|
#include "libc/str/str.h"
|
||||||
|
|
||||||
#define CONSUME_SPACES(t, s, c) \
|
#define CONSUME_SPACES(t, s, c) \
|
||||||
if (endptr) *endptr = (t *)(s); \
|
if (endptr) *endptr = (t *)(s); \
|
||||||
|
@ -10,33 +11,34 @@
|
||||||
d = c == '-' ? -1 : 1; \
|
d = c == '-' ? -1 : 1; \
|
||||||
if (c == '-' || c == '+') c = *++s
|
if (c == '-' || c == '+') c = *++s
|
||||||
|
|
||||||
#define GET_RADIX(s, c, r) \
|
#define GET_RADIX(s, c, r) \
|
||||||
if (!r) { \
|
if (!r) { \
|
||||||
if (c == '0') { \
|
if (c == '0') { \
|
||||||
t |= 1; \
|
t |= 1; \
|
||||||
c = *++s; \
|
c = *++s; \
|
||||||
if (c == 'x' || c == 'X') { \
|
if ((c == 'x' || c == 'X') && isxdigit(s[1])) { \
|
||||||
c = *++s; \
|
c = *++s; \
|
||||||
r = 16; \
|
r = 16; \
|
||||||
} else if (c == 'b' || c == 'B') { \
|
} else if ((c == 'b' || c == 'B') && (s[1] == '0' || s[1] == '1')) { \
|
||||||
c = *++s; \
|
c = *++s; \
|
||||||
r = 2; \
|
r = 2; \
|
||||||
} else { \
|
} else { \
|
||||||
r = 8; \
|
r = 8; \
|
||||||
} \
|
} \
|
||||||
} else { \
|
} else { \
|
||||||
r = 10; \
|
r = 10; \
|
||||||
} \
|
} \
|
||||||
} else if (!(2 <= r && r <= 36)) { \
|
} else if (!(2 <= r && r <= 36)) { \
|
||||||
errno = EINVAL; \
|
errno = EINVAL; \
|
||||||
return 0; \
|
return 0; \
|
||||||
} else if (c == '0') { \
|
} else if (c == '0') { \
|
||||||
t |= 1; \
|
t |= 1; \
|
||||||
c = *++s; \
|
c = *++s; \
|
||||||
if ((r == 2 && (c == 'b' || c == 'B')) || \
|
if ((r == 2 && \
|
||||||
(r == 16 && (c == 'x' || c == 'X'))) { \
|
((c == 'b' || c == 'B') && (s[1] == '0' || s[1] == '1'))) || \
|
||||||
c = *++s; \
|
(r == 16 && ((c == 'x' || c == 'X') && isxdigit(s[1])))) { \
|
||||||
} \
|
c = *++s; \
|
||||||
|
} \
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* COSMOPOLITAN_LIBC_FMT_STRTOL_H_ */
|
#endif /* COSMOPOLITAN_LIBC_FMT_STRTOL_H_ */
|
||||||
|
|
|
@ -156,7 +156,7 @@ typedef struct {
|
||||||
#define memcpyesque libcesque
|
#define memcpyesque libcesque
|
||||||
#define strlenesque libcesque nosideeffect paramsnonnull()
|
#define strlenesque libcesque nosideeffect paramsnonnull()
|
||||||
#define vallocesque \
|
#define vallocesque \
|
||||||
libcesque dontdiscard returnsaligned((65536)) returnspointerwithnoaliases
|
libcesque __wur returnsaligned((65536)) returnspointerwithnoaliases
|
||||||
#define reallocesque libcesque returnsaligned((16))
|
#define reallocesque libcesque returnsaligned((16))
|
||||||
#define mallocesque reallocesque returnspointerwithnoaliases
|
#define mallocesque reallocesque returnspointerwithnoaliases
|
||||||
#define interruptfn nocallersavedregisters forcealignargpointer
|
#define interruptfn nocallersavedregisters forcealignargpointer
|
||||||
|
@ -268,13 +268,13 @@ typedef struct {
|
||||||
#endif /* __cplusplus */
|
#endif /* __cplusplus */
|
||||||
#endif /* forceinline */
|
#endif /* forceinline */
|
||||||
|
|
||||||
#ifndef dontdiscard
|
#ifndef __wur
|
||||||
#if !defined(__STRICT_ANSI__) && \
|
#if !defined(__STRICT_ANSI__) && \
|
||||||
((__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 304 || \
|
((__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 304 || \
|
||||||
__has_attribute(__warn_unused_result__))
|
__has_attribute(__warn_unused_result__))
|
||||||
#define dontdiscard __attribute__((__warn_unused_result__))
|
#define __wur __attribute__((__warn_unused_result__))
|
||||||
#else
|
#else
|
||||||
#define dontdiscard
|
#define __wur
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -79,15 +79,7 @@
|
||||||
#define _PAGESIZE 4096
|
#define _PAGESIZE 4096
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define BUFSIZ 0x1000 /* best stdio default */
|
#define NSIG 128 /* b/c freebsd */
|
||||||
#define CHAR_BIT 8 /* b/c von neumann */
|
|
||||||
#define ARG_MAX 0xfffe /* for argv and envp; see CreateProcess (32767*2) */
|
|
||||||
#define PATH_MAX 1024 /* b/c _XOPEN_PATH_MAX */
|
|
||||||
#define NAME_MAX 255 /* 511 on netbsd */
|
|
||||||
#define CHILD_MAX 16 /* only if malloc isn't linked */
|
|
||||||
#define OPEN_MAX 16 /* only if malloc isn't linked */
|
|
||||||
#define ATEXIT_MAX 32 /* only if malloc isn't linked */
|
|
||||||
#define NSIG 128 /* b/c freebsd */
|
|
||||||
|
|
||||||
#if defined(__LP64__) && !defined(__INT64_TYPE__)
|
#if defined(__LP64__) && !defined(__INT64_TYPE__)
|
||||||
#include "libc/integral/lp64.inc"
|
#include "libc/integral/lp64.inc"
|
||||||
|
|
|
@ -347,7 +347,7 @@ static void __asan_exit(void) {
|
||||||
_Exit(99);
|
_Exit(99);
|
||||||
}
|
}
|
||||||
|
|
||||||
dontdiscard static __asan_die_f *__asan_die(void) {
|
static __wur __asan_die_f *__asan_die(void) {
|
||||||
if (_weaken(__die)) {
|
if (_weaken(__die)) {
|
||||||
return _weaken(__die);
|
return _weaken(__die);
|
||||||
} else {
|
} else {
|
||||||
|
@ -707,8 +707,7 @@ static const char *__asan_describe_access_poison(signed char kind) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static dontdiscard __asan_die_f *__asan_report_invalid_pointer(
|
static __wur __asan_die_f *__asan_report_invalid_pointer(const void *addr) {
|
||||||
const void *addr) {
|
|
||||||
kprintf("\n\e[J\e[1;31masan error\e[0m: this corruption at %p shadow %p\n",
|
kprintf("\n\e[J\e[1;31masan error\e[0m: this corruption at %p shadow %p\n",
|
||||||
addr, SHADOW(addr));
|
addr, SHADOW(addr));
|
||||||
return __asan_die();
|
return __asan_die();
|
||||||
|
@ -825,9 +824,9 @@ static void __asan_report_memory_origin(const unsigned char *addr, int size,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dontdiscard static __asan_die_f *__asan_report(const void *addr, int size,
|
static __wur __asan_die_f *__asan_report(const void *addr, int size,
|
||||||
const char *message,
|
const char *message,
|
||||||
signed char kind) {
|
signed char kind) {
|
||||||
int i;
|
int i;
|
||||||
wint_t c;
|
wint_t c;
|
||||||
signed char t;
|
signed char t;
|
||||||
|
@ -940,8 +939,8 @@ void __asan_verify_str(const char *p) {
|
||||||
__asan_verify_failed(UNSHADOW(f.shadow), 8, f);
|
__asan_verify_failed(UNSHADOW(f.shadow), 8, f);
|
||||||
}
|
}
|
||||||
|
|
||||||
static dontdiscard __asan_die_f *__asan_report_memory_fault(
|
static __wur __asan_die_f *__asan_report_memory_fault(void *addr, int size,
|
||||||
void *addr, int size, const char *message) {
|
const char *message) {
|
||||||
return __asan_report(addr, size, message,
|
return __asan_report(addr, size, message,
|
||||||
__asan_fault(SHADOW(addr), -128).kind);
|
__asan_fault(SHADOW(addr), -128).kind);
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,9 +8,9 @@ int _bsrl(long) pureconst;
|
||||||
int _bsrll(long long) pureconst;
|
int _bsrll(long long) pureconst;
|
||||||
|
|
||||||
#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
|
#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
|
||||||
#define _bsr(x) (__builtin_clz(x) ^ (sizeof(int) * CHAR_BIT - 1))
|
#define _bsr(x) (__builtin_clz(x) ^ (sizeof(int) * 8 - 1))
|
||||||
#define _bsrl(x) (__builtin_clzl(x) ^ (sizeof(long) * CHAR_BIT - 1))
|
#define _bsrl(x) (__builtin_clzl(x) ^ (sizeof(long) * 8 - 1))
|
||||||
#define _bsrll(x) (__builtin_clzll(x) ^ (sizeof(long long) * CHAR_BIT - 1))
|
#define _bsrll(x) (__builtin_clzll(x) ^ (sizeof(long long) * 8 - 1))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
COSMOPOLITAN_C_END_
|
COSMOPOLITAN_C_END_
|
||||||
|
|
|
@ -139,6 +139,10 @@ void bzero(void *p, size_t n) {
|
||||||
#ifdef __x86_64__
|
#ifdef __x86_64__
|
||||||
asm("xorl\t%k0,%k0" : "=r"(x));
|
asm("xorl\t%k0,%k0" : "=r"(x));
|
||||||
#else
|
#else
|
||||||
|
if (1) {
|
||||||
|
memset(p, 0, n);
|
||||||
|
return;
|
||||||
|
}
|
||||||
x = 0;
|
x = 0;
|
||||||
#endif
|
#endif
|
||||||
if (n <= 16) {
|
if (n <= 16) {
|
||||||
|
|
|
@ -31,11 +31,11 @@ __msabi extern typeof(CreateDirectory) *const __imp_CreateDirectoryW;
|
||||||
* @note this wrapper takes care of ABI, STRACE(), and __winerr()
|
* @note this wrapper takes care of ABI, STRACE(), and __winerr()
|
||||||
*/
|
*/
|
||||||
textwindows bool32 CreateDirectory(const char16_t *lpPathName,
|
textwindows bool32 CreateDirectory(const char16_t *lpPathName,
|
||||||
struct NtSecurityAttributes *lpSecurity) {
|
const struct NtSecurityAttributes *lpSec) {
|
||||||
bool32 ok;
|
bool32 ok;
|
||||||
ok = __imp_CreateDirectoryW(lpPathName, lpSecurity);
|
ok = __imp_CreateDirectoryW(lpPathName, lpSec);
|
||||||
if (!ok) __winerr();
|
if (!ok) __winerr();
|
||||||
NTTRACE("CreateDirectory(%#hs, %s) → %hhhd% m", lpPathName,
|
NTTRACE("CreateDirectory(%#hs, %s) → %hhhd% m", lpPathName,
|
||||||
DescribeNtSecurityAttributes(lpSecurity), ok);
|
DescribeNtSecurityAttributes(lpSec), ok);
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,8 +32,8 @@ __msabi extern typeof(CreateProcess) *const __imp_CreateProcessW;
|
||||||
*/
|
*/
|
||||||
textwindows bool32
|
textwindows bool32
|
||||||
CreateProcess(const char16_t *opt_lpApplicationName, char16_t *lpCommandLine,
|
CreateProcess(const char16_t *opt_lpApplicationName, char16_t *lpCommandLine,
|
||||||
struct NtSecurityAttributes *opt_lpProcessAttributes,
|
const struct NtSecurityAttributes *opt_lpProcessAttributes,
|
||||||
struct NtSecurityAttributes *opt_lpThreadAttributes,
|
const struct NtSecurityAttributes *opt_lpThreadAttributes,
|
||||||
bool32 bInheritHandles, uint32_t dwCreationFlags,
|
bool32 bInheritHandles, uint32_t dwCreationFlags,
|
||||||
void *opt_lpEnvironment, const char16_t *opt_lpCurrentDirectory,
|
void *opt_lpEnvironment, const char16_t *opt_lpCurrentDirectory,
|
||||||
const struct NtStartupInfo *lpStartupInfo,
|
const struct NtStartupInfo *lpStartupInfo,
|
||||||
|
|
|
@ -32,7 +32,7 @@ __msabi extern typeof(CreateThread) *const __imp_CreateThread;
|
||||||
* @note this wrapper takes care of ABI, STRACE()
|
* @note this wrapper takes care of ABI, STRACE()
|
||||||
*/
|
*/
|
||||||
textwindows int64_t
|
textwindows int64_t
|
||||||
CreateThread(struct NtSecurityAttributes *lpThreadAttributes,
|
CreateThread(const struct NtSecurityAttributes *lpThreadAttributes,
|
||||||
size_t dwStackSize, void *lpStartAddress, void *lpParameter,
|
size_t dwStackSize, void *lpStartAddress, void *lpParameter,
|
||||||
uint32_t dwCreationFlags, uint32_t *opt_lpThreadId) {
|
uint32_t dwCreationFlags, uint32_t *opt_lpThreadId) {
|
||||||
int64_t hHandle;
|
int64_t hHandle;
|
||||||
|
|
|
@ -46,7 +46,6 @@ dontasan int __cxa_atexit(void *fp, void *arg, void *pred) {
|
||||||
/* asan runtime depends on this function */
|
/* asan runtime depends on this function */
|
||||||
unsigned i;
|
unsigned i;
|
||||||
struct CxaAtexitBlock *b, *b2;
|
struct CxaAtexitBlock *b, *b2;
|
||||||
_Static_assert(ATEXIT_MAX == CHAR_BIT * sizeof(b->mask), "");
|
|
||||||
__cxa_lock();
|
__cxa_lock();
|
||||||
b = __cxa_blocks.p;
|
b = __cxa_blocks.p;
|
||||||
if (!b) b = __cxa_blocks.p = &__cxa_blocks.root;
|
if (!b) b = __cxa_blocks.p = &__cxa_blocks.root;
|
||||||
|
|
|
@ -14,7 +14,7 @@ struct CxaAtexitBlocks {
|
||||||
void *fp;
|
void *fp;
|
||||||
void *arg;
|
void *arg;
|
||||||
void *pred;
|
void *pred;
|
||||||
} p[ATEXIT_MAX];
|
} p[32];
|
||||||
} * p, root;
|
} * p, root;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -44,6 +44,7 @@ const char *DescribeNtProcAccessFlags(char[256], uint32_t);
|
||||||
const char *DescribeNtStartFlags(char[128], uint32_t);
|
const char *DescribeNtStartFlags(char[128], uint32_t);
|
||||||
const char *DescribeNtSymlinkFlags(char[64], uint32_t);
|
const char *DescribeNtSymlinkFlags(char[64], uint32_t);
|
||||||
const char *DescribeOpenFlags(char[128], int);
|
const char *DescribeOpenFlags(char[128], int);
|
||||||
|
const char *DescribeOpenMode(char[15], int, int);
|
||||||
const char *DescribePersonalityFlags(char[128], int);
|
const char *DescribePersonalityFlags(char[128], int);
|
||||||
const char *DescribePollFlags(char[64], int);
|
const char *DescribePollFlags(char[64], int);
|
||||||
const char *DescribePrctlOperation(int);
|
const char *DescribePrctlOperation(int);
|
||||||
|
@ -97,6 +98,7 @@ const char *DescribeWhichPrio(char[12], int);
|
||||||
#define DescribeNtStartFlags(x) DescribeNtStartFlags(alloca(128), x)
|
#define DescribeNtStartFlags(x) DescribeNtStartFlags(alloca(128), x)
|
||||||
#define DescribeNtSymlinkFlags(x) DescribeNtSymlinkFlags(alloca(64), x)
|
#define DescribeNtSymlinkFlags(x) DescribeNtSymlinkFlags(alloca(64), x)
|
||||||
#define DescribeOpenFlags(x) DescribeOpenFlags(alloca(128), x)
|
#define DescribeOpenFlags(x) DescribeOpenFlags(alloca(128), x)
|
||||||
|
#define DescribeOpenMode(x, y) DescribeOpenMode(alloca(15), x, y)
|
||||||
#define DescribePersonalityFlags(p) DescribePersonalityFlags(alloca(128), p)
|
#define DescribePersonalityFlags(p) DescribePersonalityFlags(alloca(128), p)
|
||||||
#define DescribePollFlags(p) DescribePollFlags(alloca(64), p)
|
#define DescribePollFlags(p) DescribePollFlags(alloca(64), p)
|
||||||
#define DescribeProtFlags(x) DescribeProtFlags(alloca(48), x)
|
#define DescribeProtFlags(x) DescribeProtFlags(alloca(48), x)
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
#include "libc/intrin/kprintf.h"
|
#include "libc/intrin/kprintf.h"
|
||||||
#include "libc/macros.internal.h"
|
#include "libc/macros.internal.h"
|
||||||
|
|
||||||
const char *(DescribeNtOverlapped)(char b[128], struct NtOverlapped *o) {
|
const char *(DescribeNtOverlapped)(char b[128], const struct NtOverlapped *o) {
|
||||||
int i = 0, n = 128;
|
int i = 0, n = 128;
|
||||||
bool gotsome = false;
|
bool gotsome = false;
|
||||||
if (!o) return "NULL";
|
if (!o) return "NULL";
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||||
COSMOPOLITAN_C_START_
|
COSMOPOLITAN_C_START_
|
||||||
|
|
||||||
const char *DescribeNtOverlapped(char[128], struct NtOverlapped *);
|
const char *DescribeNtOverlapped(char[128], const struct NtOverlapped *);
|
||||||
#define DescribeNtOverlapped(x) DescribeNtOverlapped(alloca(128), x)
|
#define DescribeNtOverlapped(x) DescribeNtOverlapped(alloca(128), x)
|
||||||
|
|
||||||
COSMOPOLITAN_C_END_
|
COSMOPOLITAN_C_END_
|
||||||
|
|
|
@ -21,8 +21,9 @@
|
||||||
#include "libc/intrin/describeflags.internal.h"
|
#include "libc/intrin/describeflags.internal.h"
|
||||||
#include "libc/nt/struct/securityattributes.h"
|
#include "libc/nt/struct/securityattributes.h"
|
||||||
|
|
||||||
const char *(DescribeNtSecurityAttributes)(char buf[32],
|
const char *(
|
||||||
struct NtSecurityAttributes *p) {
|
DescribeNtSecurityAttributes)(char buf[32],
|
||||||
|
const struct NtSecurityAttributes *p) {
|
||||||
if (p == &kNtIsInheritable) return "&kNtIsInheritable";
|
if (p == &kNtIsInheritable) return "&kNtIsInheritable";
|
||||||
FormatInt64(buf, (uintptr_t)p);
|
FormatInt64(buf, (uintptr_t)p);
|
||||||
return buf;
|
return buf;
|
||||||
|
|
40
libc/intrin/describeopenmode.c
Normal file
40
libc/intrin/describeopenmode.c
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
/*-*- 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 2023 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/dce.h"
|
||||||
|
#include "libc/fmt/itoa.h"
|
||||||
|
#include "libc/intrin/describeflags.internal.h"
|
||||||
|
#include "libc/sysv/consts/o.h"
|
||||||
|
|
||||||
|
#define O_TMPFILE_LINUX 0x00410000
|
||||||
|
|
||||||
|
static bool IsCreatingFile(int flags) {
|
||||||
|
return (flags & O_CREAT) ||
|
||||||
|
(IsLinux() && (flags & O_TMPFILE_LINUX) == O_TMPFILE_LINUX);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *(DescribeOpenMode)(char buf[15], int flags, int mode) {
|
||||||
|
if (!IsCreatingFile(flags)) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
char *p = buf;
|
||||||
|
*p++ = ',';
|
||||||
|
*p++ = ' ';
|
||||||
|
FormatOctal32(p, mode, true);
|
||||||
|
return buf;
|
||||||
|
}
|
|
@ -34,6 +34,8 @@
|
||||||
#include "libc/sysv/consts/o.h"
|
#include "libc/sysv/consts/o.h"
|
||||||
#include "libc/thread/thread.h"
|
#include "libc/thread/thread.h"
|
||||||
|
|
||||||
|
#define OPEN_MAX 16
|
||||||
|
|
||||||
#ifdef __x86_64__
|
#ifdef __x86_64__
|
||||||
__static_yoink("_init_g_fds");
|
__static_yoink("_init_g_fds");
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -31,7 +31,6 @@
|
||||||
char *getenv(const char *s) {
|
char *getenv(const char *s) {
|
||||||
char **p;
|
char **p;
|
||||||
struct Env e;
|
struct Env e;
|
||||||
if (!s) return 0;
|
|
||||||
if (!(p = environ)) return 0;
|
if (!(p = environ)) return 0;
|
||||||
e = __getenv(p, s);
|
e = __getenv(p, s);
|
||||||
#if SYSDEBUG
|
#if SYSDEBUG
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
#include "libc/nt/struct/securityattributes.h"
|
#include "libc/nt/struct/securityattributes.h"
|
||||||
|
|
||||||
const struct NtSecurityAttributes kNtIsInheritable = {
|
const struct NtSecurityAttributes kNtIsInheritable = {
|
||||||
sizeof(struct NtSecurityAttributes),
|
.nLength = sizeof(struct NtSecurityAttributes),
|
||||||
NULL,
|
.lpSecurityDescriptor = NULL,
|
||||||
true,
|
.bInheritHandle = true,
|
||||||
};
|
};
|
||||||
|
|
|
@ -36,7 +36,8 @@ kOpenFlags:
|
||||||
.e O_TRUNC,"TRUNC" //
|
.e O_TRUNC,"TRUNC" //
|
||||||
.e O_CLOEXEC,"CLOEXEC" //
|
.e O_CLOEXEC,"CLOEXEC" //
|
||||||
.e O_NONBLOCK,"NONBLOCK" //
|
.e O_NONBLOCK,"NONBLOCK" //
|
||||||
.e O_TMPFILE,"TMPFILE" // linux, windows
|
.e O_TMPFILE,"TMPFILE" // linux
|
||||||
|
.e O_UNLINK,"UNLINK" // windows+unix
|
||||||
.e O_DIRECTORY,"DIRECTORY" // order matters
|
.e O_DIRECTORY,"DIRECTORY" // order matters
|
||||||
.e O_DIRECT,"DIRECT" // no-op on xnu/openbsd
|
.e O_DIRECT,"DIRECT" // no-op on xnu/openbsd
|
||||||
.e O_APPEND,"APPEND" // weird on nt
|
.e O_APPEND,"APPEND" // weird on nt
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
#ifndef __aarch64__
|
#ifndef __aarch64__
|
||||||
|
|
||||||
typedef char xmm_t __attribute__((__vector_size__(16), __aligned__(1)));
|
typedef char xmm_t __attribute__((__vector_size__(16), __aligned__(16)));
|
||||||
|
|
||||||
static inline const unsigned char *memchr_pure(const unsigned char *s,
|
static inline const unsigned char *memchr_pure(const unsigned char *s,
|
||||||
unsigned char c, size_t n) {
|
unsigned char c, size_t n) {
|
||||||
|
@ -68,14 +68,22 @@ dontasan static inline const unsigned char *memchr_sse(const unsigned char *s,
|
||||||
* @return is pointer to first instance of c or NULL if not found
|
* @return is pointer to first instance of c or NULL if not found
|
||||||
* @asyncsignalsafe
|
* @asyncsignalsafe
|
||||||
*/
|
*/
|
||||||
void *memchr(const void *s, int c, size_t n) {
|
dontasan void *memchr(const void *s, int c, size_t n) {
|
||||||
#if defined(__x86_64__) && !defined(__chibicc__)
|
#if defined(__x86_64__) && !defined(__chibicc__)
|
||||||
const void *r;
|
const void *r;
|
||||||
if (IsAsan()) __asan_verify(s, n);
|
if (IsAsan()) __asan_verify(s, n);
|
||||||
r = memchr_sse(s, c, n);
|
const unsigned char *p = (const unsigned char *)s;
|
||||||
|
while (n && ((intptr_t)p & 15)) {
|
||||||
|
if (*p == (unsigned char)c) {
|
||||||
|
return (void *)p;
|
||||||
|
}
|
||||||
|
++p;
|
||||||
|
--n;
|
||||||
|
}
|
||||||
|
r = memchr_sse(p, c, n);
|
||||||
return (void *)r;
|
return (void *)r;
|
||||||
#else
|
#else
|
||||||
return memchr_pure(s, c, n);
|
return (void *)memchr_pure(s, c, n);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,113 +22,34 @@
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
#ifndef __aarch64__
|
#ifndef __aarch64__
|
||||||
|
|
||||||
#define PMOVMSKB(x) __builtin_ia32_pmovmskb128(x)
|
|
||||||
|
|
||||||
typedef char xmm_t __attribute__((__vector_size__(16), __aligned__(1)));
|
typedef char xmm_t __attribute__((__vector_size__(16), __aligned__(1)));
|
||||||
|
|
||||||
#if defined(__x86_64__) && !defined(__chibicc__)
|
|
||||||
|
|
||||||
static dontinline antiquity int memcmp_sse(const unsigned char *p,
|
|
||||||
const unsigned char *q, size_t n) {
|
|
||||||
unsigned u;
|
|
||||||
if (n > 32) {
|
|
||||||
while (n > 16 + 16) {
|
|
||||||
if (!(u = PMOVMSKB(*(xmm_t *)p == *(xmm_t *)q) ^ 0xffff)) {
|
|
||||||
n -= 16;
|
|
||||||
p += 16;
|
|
||||||
q += 16;
|
|
||||||
} else {
|
|
||||||
u = __builtin_ctzl(u);
|
|
||||||
return p[u] - q[u];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!(u = PMOVMSKB(*(xmm_t *)p == *(xmm_t *)q) ^ 0xffff)) {
|
|
||||||
if (!(u = PMOVMSKB(*(xmm_t *)(p + n - 16) == *(xmm_t *)(q + n - 16)) ^
|
|
||||||
0xffff)) {
|
|
||||||
return 0;
|
|
||||||
} else {
|
|
||||||
u = __builtin_ctzl(u);
|
|
||||||
return p[n - 16 + u] - q[n - 16 + u];
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
u = __builtin_ctzl(u);
|
|
||||||
return p[u] - q[u];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_Microarchitecture("avx") static int memcmp_avx(const unsigned char *p,
|
|
||||||
const unsigned char *q,
|
|
||||||
size_t n) {
|
|
||||||
uint64_t w;
|
|
||||||
unsigned u;
|
|
||||||
if (n > 32) {
|
|
||||||
while (n >= 16 + 64) {
|
|
||||||
w = (uint64_t)PMOVMSKB(((xmm_t *)p)[0] == ((xmm_t *)q)[0]) << 000 |
|
|
||||||
(uint64_t)PMOVMSKB(((xmm_t *)p)[1] == ((xmm_t *)q)[1]) << 020 |
|
|
||||||
(uint64_t)PMOVMSKB(((xmm_t *)p)[2] == ((xmm_t *)q)[2]) << 040 |
|
|
||||||
(uint64_t)PMOVMSKB(((xmm_t *)p)[3] == ((xmm_t *)q)[3]) << 060;
|
|
||||||
if (w == -1) {
|
|
||||||
n -= 64;
|
|
||||||
p += 64;
|
|
||||||
q += 64;
|
|
||||||
} else {
|
|
||||||
w = __builtin_ctzll(w ^ -1);
|
|
||||||
return p[w] - q[w];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
while (n > 16 + 16) {
|
|
||||||
if (!(u = PMOVMSKB(*(xmm_t *)p == *(xmm_t *)q) ^ 0xffff)) {
|
|
||||||
n -= 16;
|
|
||||||
p += 16;
|
|
||||||
q += 16;
|
|
||||||
} else {
|
|
||||||
u = __builtin_ctzl(u);
|
|
||||||
return p[u] - q[u];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!(u = PMOVMSKB(*(xmm_t *)p == *(xmm_t *)q) ^ 0xffff)) {
|
|
||||||
if (!(u = PMOVMSKB(*(xmm_t *)(p + n - 16) == *(xmm_t *)(q + n - 16)) ^
|
|
||||||
0xffff)) {
|
|
||||||
return 0;
|
|
||||||
} else {
|
|
||||||
u = __builtin_ctzl(u);
|
|
||||||
return p[n - 16 + u] - q[n - 16 + u];
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
u = __builtin_ctzl(u);
|
|
||||||
return p[u] - q[u];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* __x86_64__ */
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compares memory byte by byte.
|
* Compares memory byte by byte.
|
||||||
*
|
*
|
||||||
* memcmp n=0 992 picoseconds
|
* memcmp n=0 2 nanoseconds
|
||||||
* memcmp n=1 1 ns/byte 738 mb/s
|
* memcmp n=1 2 ns/byte 357 mb/s
|
||||||
* memcmp n=2 661 ps/byte 1,476 mb/s
|
* memcmp n=2 1 ns/byte 530 mb/s
|
||||||
* memcmp n=3 551 ps/byte 1,771 mb/s
|
* memcmp n=3 1 ns/byte 631 mb/s
|
||||||
* memcmp n=4 248 ps/byte 3,936 mb/s
|
* 𝗺𝗲𝗺𝗰𝗺𝗽 n=4 1 ns/byte 849 mb/s
|
||||||
* memcmp n=5 198 ps/byte 4,920 mb/s
|
* memcmp n=5 816 ps/byte 1,195 mb/s
|
||||||
* memcmp n=6 165 ps/byte 5,904 mb/s
|
* memcmp n=6 888 ps/byte 1,098 mb/s
|
||||||
* memcmp n=7 141 ps/byte 6,889 mb/s
|
* memcmp n=7 829 ps/byte 1,176 mb/s
|
||||||
* memcmp n=8 124 ps/byte 7,873 mb/s
|
* 𝗺𝗲𝗺𝗰𝗺𝗽 n=8 773 ps/byte 1,261 mb/s
|
||||||
* memcmp n=9 110 ps/byte 8,857 mb/s
|
* memcmp n=9 629 ps/byte 1,551 mb/s
|
||||||
* memcmp n=15 44 ps/byte 22,143 mb/s
|
* memcmp n=15 540 ps/byte 1,805 mb/s
|
||||||
* memcmp n=16 41 ps/byte 23,619 mb/s
|
* 𝗺𝗲𝗺𝗰𝗺𝗽 n=16 211 ps/byte 4,623 mb/s
|
||||||
* memcmp n=17 77 ps/byte 12,547 mb/s
|
* memcmp n=17 268 ps/byte 3,633 mb/s
|
||||||
* memcmp n=31 42 ps/byte 22,881 mb/s
|
* memcmp n=31 277 ps/byte 3,524 mb/s
|
||||||
* memcmp n=32 41 ps/byte 23,619 mb/s
|
* memcmp n=32 153 ps/byte 6,351 mb/s
|
||||||
* memcmp n=33 60 ps/byte 16,238 mb/s
|
* memcmp n=33 179 ps/byte 5,431 mb/s
|
||||||
* memcmp n=80 53 ps/byte 18,169 mb/s
|
* memcmp n=79 148 ps/byte 6,576 mb/s
|
||||||
* memcmp n=128 38 ps/byte 25,194 mb/s
|
* 𝗺𝗲𝗺𝗰𝗺𝗽 n=80 81 ps/byte 11 GB/s
|
||||||
* memcmp n=256 32 ps/byte 30,233 mb/s
|
* memcmp n=128 76 ps/byte 12 GB/s
|
||||||
* memcmp n=16384 27 ps/byte 35,885 mb/s
|
* memcmp n=256 60 ps/byte 15 GB/s
|
||||||
* memcmp n=32768 29 ps/byte 32,851 mb/s
|
* memcmp n=16384 51 ps/byte 18 GB/s
|
||||||
* memcmp n=131072 33 ps/byte 28,983 mb/s
|
* memcmp n=32768 51 ps/byte 18 GB/s
|
||||||
|
* memcmp n=131072 52 ps/byte 18 GB/s
|
||||||
*
|
*
|
||||||
* @return an integer that's (1) equal to zero if `a` is equal to `b`,
|
* @return an integer that's (1) equal to zero if `a` is equal to `b`,
|
||||||
* (2) less than zero if `a` is less than `b`, or (3) greater than
|
* (2) less than zero if `a` is less than `b`, or (3) greater than
|
||||||
|
@ -137,62 +58,21 @@ _Microarchitecture("avx") static int memcmp_avx(const unsigned char *p,
|
||||||
*/
|
*/
|
||||||
int memcmp(const void *a, const void *b, size_t n) {
|
int memcmp(const void *a, const void *b, size_t n) {
|
||||||
int c;
|
int c;
|
||||||
unsigned u;
|
|
||||||
uint32_t k, i, j;
|
|
||||||
uint64_t w, x, y;
|
|
||||||
const unsigned char *p, *q;
|
const unsigned char *p, *q;
|
||||||
if ((p = a) == (q = b) || !n) return 0;
|
if ((p = a) == (q = b) || !n) return 0;
|
||||||
if ((c = *p - *q)) return c;
|
if ((c = *p - *q)) return c;
|
||||||
#if defined(__x86_64__) && !defined(__chibicc__)
|
#if defined(__x86_64__) && !defined(__chibicc__)
|
||||||
if (!IsTiny()) {
|
unsigned u;
|
||||||
if (n <= 16) {
|
while (n >= 16 && (((uintptr_t)p & 0xfff) <= 0x1000 - 16 &&
|
||||||
if (n >= 8) {
|
((uintptr_t)q & 0xfff) <= 0x1000 - 16)) {
|
||||||
if (!(w = (x = ((uint64_t)p[0] << 000 | (uint64_t)p[1] << 010 |
|
if (!(u = __builtin_ia32_pmovmskb128(*(xmm_t *)p == *(xmm_t *)q) ^
|
||||||
(uint64_t)p[2] << 020 | (uint64_t)p[3] << 030 |
|
0xffff)) {
|
||||||
(uint64_t)p[4] << 040 | (uint64_t)p[5] << 050 |
|
n -= 16;
|
||||||
(uint64_t)p[6] << 060 | (uint64_t)p[7] << 070)) ^
|
p += 16;
|
||||||
(y = ((uint64_t)q[0] << 000 | (uint64_t)q[1] << 010 |
|
q += 16;
|
||||||
(uint64_t)q[2] << 020 | (uint64_t)q[3] << 030 |
|
|
||||||
(uint64_t)q[4] << 040 | (uint64_t)q[5] << 050 |
|
|
||||||
(uint64_t)q[6] << 060 | (uint64_t)q[7] << 070)))) {
|
|
||||||
p += n - 8;
|
|
||||||
q += n - 8;
|
|
||||||
if (!(w = (x = ((uint64_t)p[0] << 000 | (uint64_t)p[1] << 010 |
|
|
||||||
(uint64_t)p[2] << 020 | (uint64_t)p[3] << 030 |
|
|
||||||
(uint64_t)p[4] << 040 | (uint64_t)p[5] << 050 |
|
|
||||||
(uint64_t)p[6] << 060 | (uint64_t)p[7] << 070)) ^
|
|
||||||
(y = ((uint64_t)q[0] << 000 | (uint64_t)q[1] << 010 |
|
|
||||||
(uint64_t)q[2] << 020 | (uint64_t)q[3] << 030 |
|
|
||||||
(uint64_t)q[4] << 040 | (uint64_t)q[5] << 050 |
|
|
||||||
(uint64_t)q[6] << 060 | (uint64_t)q[7] << 070)))) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
u = __builtin_ctzll(w);
|
|
||||||
u = u & -8;
|
|
||||||
return ((x >> u) & 255) - ((y >> u) & 255);
|
|
||||||
} else if (n >= 4) {
|
|
||||||
if (!(k = (i = ((uint32_t)p[0] << 000 | (uint32_t)p[1] << 010 |
|
|
||||||
(uint32_t)p[2] << 020 | (uint32_t)p[3] << 030)) ^
|
|
||||||
(j = ((uint32_t)q[0] << 000 | (uint32_t)q[1] << 010 |
|
|
||||||
(uint32_t)q[2] << 020 | (uint32_t)q[3] << 030)))) {
|
|
||||||
p += n - 4;
|
|
||||||
q += n - 4;
|
|
||||||
if (!(k = (i = ((uint32_t)p[0] << 000 | (uint32_t)p[1] << 010 |
|
|
||||||
(uint32_t)p[2] << 020 | (uint32_t)p[3] << 030)) ^
|
|
||||||
(j = ((uint32_t)q[0] << 000 | (uint32_t)q[1] << 010 |
|
|
||||||
(uint32_t)q[2] << 020 | (uint32_t)q[3] << 030)))) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
u = __builtin_ctzl(k);
|
|
||||||
u = u & -8;
|
|
||||||
return ((i >> u) & 255) - ((j >> u) & 255);
|
|
||||||
}
|
|
||||||
} else if (LIKELY(X86_HAVE(AVX))) {
|
|
||||||
return memcmp_avx(p, q, n);
|
|
||||||
} else {
|
} else {
|
||||||
return memcmp_sse(p, q, n);
|
u = __builtin_ctzl(u);
|
||||||
|
return p[u] - q[u];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif /* __x86_64__ */
|
#endif /* __x86_64__ */
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/dce.h"
|
#include "libc/dce.h"
|
||||||
#include "libc/intrin/asan.internal.h"
|
#include "libc/intrin/asan.internal.h"
|
||||||
|
#include "libc/limits.h"
|
||||||
#include "libc/nexgen32e/x86feature.h"
|
#include "libc/nexgen32e/x86feature.h"
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
#ifndef __aarch64__
|
#ifndef __aarch64__
|
||||||
|
@ -75,7 +76,7 @@ void *memrchr(const void *s, int c, size_t n) {
|
||||||
r = memrchr_sse(s, c, n);
|
r = memrchr_sse(s, c, n);
|
||||||
return (void *)r;
|
return (void *)r;
|
||||||
#else
|
#else
|
||||||
return memrchr_pure(s, c, n);
|
return (void *)memrchr_pure(s, c, n);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
#include "libc/macros.internal.h"
|
#include "libc/macros.internal.h"
|
||||||
|
|
||||||
.init.start 200,_init__mmi
|
.init.start 200,_init__mmi
|
||||||
movb $OPEN_MAX,_mmi+8
|
movb $16,_mmi+8
|
||||||
movl $_mmi+24,_mmi+16
|
movl $_mmi+24,_mmi+16
|
||||||
movb $PTHREAD_MUTEX_RECURSIVE,__mmi_lock_obj+4(%rip)
|
movb $PTHREAD_MUTEX_RECURSIVE,__mmi_lock_obj+4(%rip)
|
||||||
.init.end 200,_init__mmi
|
.init.end 200,_init__mmi
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/calls/struct/sigset.h"
|
#include "libc/calls/struct/sigset.h"
|
||||||
|
#include "libc/limits.h"
|
||||||
#include "libc/sysv/consts/limits.h"
|
#include "libc/sysv/consts/limits.h"
|
||||||
#include "libc/sysv/consts/sig.h"
|
#include "libc/sysv/consts/sig.h"
|
||||||
#include "libc/sysv/errfuns.h"
|
#include "libc/sysv/errfuns.h"
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/calls/struct/sigset.h"
|
#include "libc/calls/struct/sigset.h"
|
||||||
|
#include "libc/limits.h"
|
||||||
#include "libc/sysv/errfuns.h"
|
#include "libc/sysv/errfuns.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/calls/struct/sigset.h"
|
#include "libc/calls/struct/sigset.h"
|
||||||
|
#include "libc/limits.h"
|
||||||
#include "libc/sysv/consts/limits.h"
|
#include "libc/sysv/consts/limits.h"
|
||||||
#include "libc/sysv/errfuns.h"
|
#include "libc/sysv/errfuns.h"
|
||||||
|
|
||||||
|
|
|
@ -107,14 +107,14 @@ dontasan char *strchr(const char *s, int c) {
|
||||||
unassert(!r || *r || !(c & 255));
|
unassert(!r || *r || !(c & 255));
|
||||||
return (char *)r;
|
return (char *)r;
|
||||||
#else
|
#else
|
||||||
char *r;
|
const char *r;
|
||||||
for (c &= 255; (uintptr_t)s & 7; ++s) {
|
for (c &= 255; (uintptr_t)s & 7; ++s) {
|
||||||
if ((*s & 255) == c) return s;
|
if ((*s & 255) == c) return (char *)s;
|
||||||
if (!*s) return NULL;
|
if (!*s) return NULL;
|
||||||
}
|
}
|
||||||
r = strchr_x64(s, c);
|
r = strchr_x64(s, c);
|
||||||
unassert(!r || *r || !c);
|
unassert(!r || *r || !c);
|
||||||
return r;
|
return (char *)r;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,7 +36,7 @@
|
||||||
* @asyncsignalsafe
|
* @asyncsignalsafe
|
||||||
* @threadsafe
|
* @threadsafe
|
||||||
*/
|
*/
|
||||||
privileged dontdiscard char *strsignal_r(int sig, char buf[21]) {
|
privileged char *strsignal_r(int sig, char buf[21]) {
|
||||||
const char *s;
|
const char *s;
|
||||||
if (!sig) {
|
if (!sig) {
|
||||||
return "0";
|
return "0";
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#include "libc/intrin/pushpop.internal.h"
|
#include "libc/intrin/pushpop.internal.h"
|
||||||
#include "libc/intrin/strace.internal.h"
|
#include "libc/intrin/strace.internal.h"
|
||||||
#include "libc/intrin/weaken.h"
|
#include "libc/intrin/weaken.h"
|
||||||
|
#include "libc/limits.h"
|
||||||
#include "libc/log/color.internal.h"
|
#include "libc/log/color.internal.h"
|
||||||
#include "libc/log/internal.h"
|
#include "libc/log/internal.h"
|
||||||
#include "libc/log/libfatal.internal.h"
|
#include "libc/log/libfatal.internal.h"
|
||||||
|
@ -218,7 +219,7 @@ static char *__ubsan_stpcpy(char *d, const char *s) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dontdiscard static __ubsan_die_f *__ubsan_die(void) {
|
__wur static __ubsan_die_f *__ubsan_die(void) {
|
||||||
if (_weaken(__die)) {
|
if (_weaken(__die)) {
|
||||||
return _weaken(__die);
|
return _weaken(__die);
|
||||||
} else {
|
} else {
|
||||||
|
@ -232,8 +233,8 @@ static void __ubsan_warning(const struct UbsanSourceLocation *loc,
|
||||||
loc->line, SUBTLE, description, RESET);
|
loc->line, SUBTLE, description, RESET);
|
||||||
}
|
}
|
||||||
|
|
||||||
dontdiscard __ubsan_die_f *__ubsan_abort(const struct UbsanSourceLocation *loc,
|
__wur __ubsan_die_f *__ubsan_abort(const struct UbsanSourceLocation *loc,
|
||||||
const char *description) {
|
const char *description) {
|
||||||
kprintf("\n%s:%d: %subsan error%s: %s (tid %d)\n", loc->file, loc->line, RED2,
|
kprintf("\n%s:%d: %subsan error%s: %s (tid %d)\n", loc->file, loc->line, RED2,
|
||||||
RESET, description, gettid());
|
RESET, description, gettid());
|
||||||
return __ubsan_die();
|
return __ubsan_die();
|
||||||
|
|
|
@ -5,6 +5,6 @@
|
||||||
#include "libc/fmt/fmt.h"
|
#include "libc/fmt/fmt.h"
|
||||||
#include "libc/stdio/dprintf.h"
|
#include "libc/stdio/dprintf.h"
|
||||||
#include "libc/stdio/stdio.h"
|
#include "libc/stdio/stdio.h"
|
||||||
#include "libc/stdio/temp.h"
|
#include "libc/temp.h"
|
||||||
#include "third_party/musl/tempnam.h"
|
#include "third_party/musl/tempnam.h"
|
||||||
#endif /* _STDIO_H */
|
#endif /* _STDIO_H */
|
||||||
|
|
|
@ -10,9 +10,9 @@
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
#include "libc/stdio/dprintf.h"
|
#include "libc/stdio/dprintf.h"
|
||||||
#include "libc/stdio/rand.h"
|
#include "libc/stdio/rand.h"
|
||||||
#include "libc/stdio/temp.h"
|
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
#include "libc/sysv/consts/exit.h"
|
#include "libc/sysv/consts/exit.h"
|
||||||
|
#include "libc/temp.h"
|
||||||
#include "third_party/musl/crypt.h"
|
#include "third_party/musl/crypt.h"
|
||||||
#include "third_party/musl/rand48.h"
|
#include "third_party/musl/rand48.h"
|
||||||
#endif /* _STDLIB_H */
|
#endif /* _STDLIB_H */
|
||||||
|
|
|
@ -2,6 +2,11 @@
|
||||||
#define COSMOPOLITAN_LIBC_LIMITS_H_
|
#define COSMOPOLITAN_LIBC_LIMITS_H_
|
||||||
#define __STDC_LIMIT_MACROS
|
#define __STDC_LIMIT_MACROS
|
||||||
|
|
||||||
|
#define CHAR_BIT 8
|
||||||
|
#define PATH_MAX 1024
|
||||||
|
#define NAME_MAX 255 /* 511 on netbsd */
|
||||||
|
#define ARG_MAX 0xfffe /* for argv and envp; see CreateProcess (32767*2) */
|
||||||
|
|
||||||
#define UCHAR_MIN 0
|
#define UCHAR_MIN 0
|
||||||
#define UCHAR_MAX 255
|
#define UCHAR_MAX 255
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
|
#include "libc/limits.h"
|
||||||
#include "libc/log/log.h"
|
#include "libc/log/log.h"
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
#include "libc/intrin/safemacros.internal.h"
|
#include "libc/intrin/safemacros.internal.h"
|
||||||
|
#include "libc/limits.h"
|
||||||
#include "libc/log/log.h"
|
#include "libc/log/log.h"
|
||||||
#include "libc/mem/mem.h"
|
#include "libc/mem/mem.h"
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
|
|
|
@ -27,7 +27,7 @@ int mergesort(void *, size_t, size_t, int (*)(const void *, const void *));
|
||||||
int mergesort_r(void *, size_t, size_t,
|
int mergesort_r(void *, size_t, size_t,
|
||||||
int (*)(const void *, const void *, void *), void *);
|
int (*)(const void *, const void *, void *), void *);
|
||||||
|
|
||||||
#define __algalloc returnspointerwithnoaliases dontthrow nocallback dontdiscard
|
#define __algalloc returnspointerwithnoaliases dontthrow nocallback __wur
|
||||||
|
|
||||||
int radix_sort_int32(int32_t *, size_t);
|
int radix_sort_int32(int32_t *, size_t);
|
||||||
int radix_sort_int64(int64_t *, size_t);
|
int radix_sort_int64(int64_t *, size_t);
|
||||||
|
|
|
@ -30,7 +30,7 @@
|
||||||
* @return pointer that must be free()'d, or NULL w/ errno
|
* @return pointer that must be free()'d, or NULL w/ errno
|
||||||
* @threadsafe
|
* @threadsafe
|
||||||
*/
|
*/
|
||||||
dontdiscard char *get_current_dir_name(void) {
|
char *get_current_dir_name(void) {
|
||||||
const char *p;
|
const char *p;
|
||||||
if ((p = getenv("PWD")) && _isabspath(p)) {
|
if ((p = getenv("PWD")) && _isabspath(p)) {
|
||||||
return strdup(p);
|
return strdup(p);
|
||||||
|
|
|
@ -15,16 +15,16 @@ void free(void *) libcesque;
|
||||||
void *malloc(size_t) attributeallocsize((1)) mallocesque;
|
void *malloc(size_t) attributeallocsize((1)) mallocesque;
|
||||||
void *calloc(size_t, size_t) attributeallocsize((1, 2)) mallocesque;
|
void *calloc(size_t, size_t) attributeallocsize((1, 2)) mallocesque;
|
||||||
void *memalign(size_t, size_t) attributeallocalign((1))
|
void *memalign(size_t, size_t) attributeallocalign((1))
|
||||||
attributeallocsize((2)) returnspointerwithnoaliases libcesque dontdiscard;
|
attributeallocsize((2)) returnspointerwithnoaliases libcesque __wur;
|
||||||
void *realloc(void *, size_t) reallocesque;
|
void *realloc(void *, size_t) reallocesque;
|
||||||
void *realloc_in_place(void *, size_t) reallocesque;
|
void *realloc_in_place(void *, size_t) reallocesque;
|
||||||
void *reallocarray(void *, size_t, size_t) dontdiscard;
|
void *reallocarray(void *, size_t, size_t) __wur;
|
||||||
void *valloc(size_t) attributeallocsize((1)) vallocesque;
|
void *valloc(size_t) attributeallocsize((1)) vallocesque;
|
||||||
void *pvalloc(size_t) vallocesque;
|
void *pvalloc(size_t) vallocesque;
|
||||||
char *strdup(const char *) paramsnonnull() mallocesque;
|
char *strdup(const char *) paramsnonnull() mallocesque;
|
||||||
char *strndup(const char *, size_t) paramsnonnull() mallocesque;
|
char *strndup(const char *, size_t) paramsnonnull() mallocesque;
|
||||||
void *aligned_alloc(size_t, size_t) attributeallocalign((1))
|
void *aligned_alloc(size_t, size_t) attributeallocalign((1))
|
||||||
attributeallocsize((2)) returnspointerwithnoaliases libcesque dontdiscard;
|
attributeallocsize((2)) returnspointerwithnoaliases libcesque __wur;
|
||||||
int posix_memalign(void **, size_t, size_t);
|
int posix_memalign(void **, size_t, size_t);
|
||||||
|
|
||||||
int mallopt(int, int);
|
int mallopt(int, int);
|
||||||
|
@ -34,7 +34,7 @@ size_t malloc_usable_size(void *);
|
||||||
void **independent_calloc(size_t, size_t, void **);
|
void **independent_calloc(size_t, size_t, void **);
|
||||||
void **independent_comalloc(size_t, size_t *, void **);
|
void **independent_comalloc(size_t, size_t *, void **);
|
||||||
|
|
||||||
wchar_t *wcsdup(const wchar_t *) strlenesque dontdiscard;
|
wchar_t *wcsdup(const wchar_t *) strlenesque __wur;
|
||||||
|
|
||||||
struct mallinfo {
|
struct mallinfo {
|
||||||
size_t arena; /* non-mmapped space allocated from system */
|
size_t arena; /* non-mmapped space allocated from system */
|
||||||
|
|
|
@ -1,48 +0,0 @@
|
||||||
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
|
|
||||||
│vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi│
|
|
||||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
|
||||||
│ Copyright 2020 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/nexgen32e/x86feature.h"
|
|
||||||
#include "libc/macros.internal.h"
|
|
||||||
.text.startup
|
|
||||||
|
|
||||||
// Initializes jump table for memset() and memcpy().
|
|
||||||
//
|
|
||||||
// @param !ZF if required cpu vector extensions are available
|
|
||||||
// @param rdi is address of 64-bit jump table
|
|
||||||
// @param rsi is address of 8-bit jump initializers
|
|
||||||
// @param rdx is address of indirect branch
|
|
||||||
// @param ecx is size of jump table
|
|
||||||
memjmpinit:
|
|
||||||
.leafprologue
|
|
||||||
setnz %r8b
|
|
||||||
shl %r8b
|
|
||||||
0: xor %eax,%eax
|
|
||||||
lodsb
|
|
||||||
add %rdx,%rax
|
|
||||||
stosq
|
|
||||||
.loop 0b
|
|
||||||
xor %eax,%eax
|
|
||||||
testb X86_HAVE(ERMS)+kCpuids(%rip)
|
|
||||||
setnz %al
|
|
||||||
or %r8b,%al
|
|
||||||
mov (%rsi,%rax),%al
|
|
||||||
add %rdx,%rax
|
|
||||||
stosq
|
|
||||||
lodsq
|
|
||||||
.leafepilogue
|
|
||||||
.endfn memjmpinit,globl,hidden
|
|
|
@ -55,10 +55,10 @@ int64_t RegisterEventSource(const char16_t *lpUNCServerName,
|
||||||
const char16_t *lpSourceName);
|
const char16_t *lpSourceName);
|
||||||
int32_t DeregisterEventSource(uint64_t handle);
|
int32_t DeregisterEventSource(uint64_t handle);
|
||||||
|
|
||||||
int64_t CreateEvent(struct NtSecurityAttributes *opt_lpEventAttributes,
|
int64_t CreateEvent(const struct NtSecurityAttributes *opt_lpEventAttributes,
|
||||||
bool32 bManualReset, bool32 bInitialState,
|
bool32 bManualReset, bool32 bInitialState,
|
||||||
const char16_t *opt_lpName);
|
const char16_t *opt_lpName);
|
||||||
int64_t CreateEventEx(struct NtSecurityAttributes *lpEventAttributes,
|
int64_t CreateEventEx(const struct NtSecurityAttributes *lpEventAttributes,
|
||||||
const char16_t *lpName, uint32_t dwFlags,
|
const char16_t *lpName, uint32_t dwFlags,
|
||||||
uint32_t dwDesiredAccess);
|
uint32_t dwDesiredAccess);
|
||||||
|
|
||||||
|
|
|
@ -71,7 +71,7 @@ bool32 SetCurrentDirectory(const char16_t *lpPathName);
|
||||||
uint32_t GetCurrentDirectory(uint32_t nBufferLength, char16_t *out_lpBuffer);
|
uint32_t GetCurrentDirectory(uint32_t nBufferLength, char16_t *out_lpBuffer);
|
||||||
|
|
||||||
bool32 CreateDirectory(const char16_t *lpPathName,
|
bool32 CreateDirectory(const char16_t *lpPathName,
|
||||||
struct NtSecurityAttributes *lpSecurityAttributes);
|
const struct NtSecurityAttributes *lpSecurityAttributes);
|
||||||
bool32 RemoveDirectory(const char16_t *lpPathName);
|
bool32 RemoveDirectory(const char16_t *lpPathName);
|
||||||
|
|
||||||
bool32 DuplicateHandle(int64_t hSourceProcessHandle, int64_t hSourceHandle,
|
bool32 DuplicateHandle(int64_t hSourceProcessHandle, int64_t hSourceHandle,
|
||||||
|
@ -131,7 +131,7 @@ bool32 UnlockFileEx(int64_t hFile, uint32_t dwReserved,
|
||||||
|
|
||||||
bool32 CreateHardLink(const char16_t *lpFileName,
|
bool32 CreateHardLink(const char16_t *lpFileName,
|
||||||
const char16_t *lpExistingFileName,
|
const char16_t *lpExistingFileName,
|
||||||
struct NtSecurityAttributes *reserved)
|
const struct NtSecurityAttributes *reserved)
|
||||||
paramsnonnull((1, 2));
|
paramsnonnull((1, 2));
|
||||||
bool32 CreateSymbolicLink(const char16_t *lpSymlinkFileName,
|
bool32 CreateSymbolicLink(const char16_t *lpSymlinkFileName,
|
||||||
const char16_t *lpTargetPathName, uint32_t dwFlags)
|
const char16_t *lpTargetPathName, uint32_t dwFlags)
|
||||||
|
@ -156,7 +156,7 @@ bool32 OpenProcessToken(int64_t hProcessHandle, uint32_t dwDesiredAccess,
|
||||||
bool32 DuplicateToken(int64_t hExistingTokenHandle, int dwImpersonationLevel,
|
bool32 DuplicateToken(int64_t hExistingTokenHandle, int dwImpersonationLevel,
|
||||||
int64_t *out_hDuplicateTokenHandle);
|
int64_t *out_hDuplicateTokenHandle);
|
||||||
bool32 DuplicateTokenEx(int64_t hExistingToken, unsigned int dwDesiredAccess,
|
bool32 DuplicateTokenEx(int64_t hExistingToken, unsigned int dwDesiredAccess,
|
||||||
struct NtSecurityAttributes *lpTokenAttributes,
|
const struct NtSecurityAttributes *lpTokenAttributes,
|
||||||
int ImpersonationLevel, int TokenType,
|
int ImpersonationLevel, int TokenType,
|
||||||
int64_t *out_phNewToken);
|
int64_t *out_phNewToken);
|
||||||
|
|
||||||
|
|
|
@ -81,12 +81,12 @@ bool32 OfferVirtualMemory(void *inout_VirtualAddress, size_t Size,
|
||||||
int Priority);
|
int Priority);
|
||||||
|
|
||||||
int64_t GetProcessHeap(void);
|
int64_t GetProcessHeap(void);
|
||||||
void *HeapAlloc(int64_t hHeap, uint32_t dwFlags, size_t dwBytes) dontdiscard;
|
void *HeapAlloc(int64_t hHeap, uint32_t dwFlags, size_t dwBytes) __wur;
|
||||||
bool32 HeapFree(int64_t hHeap, uint32_t dwFlags, void *opt_lpMem);
|
bool32 HeapFree(int64_t hHeap, uint32_t dwFlags, void *opt_lpMem);
|
||||||
void *HeapReAlloc(int64_t hHeap, uint32_t dwFlags, void *lpMem,
|
void *HeapReAlloc(int64_t hHeap, uint32_t dwFlags, void *lpMem,
|
||||||
size_t dwBytes) dontdiscard;
|
size_t dwBytes) __wur;
|
||||||
|
|
||||||
void *GlobalAlloc(uint32_t uFlags, uint64_t dwBytes) dontdiscard;
|
void *GlobalAlloc(uint32_t uFlags, uint64_t dwBytes) __wur;
|
||||||
void *GlobalFree(void *hMem);
|
void *GlobalFree(void *hMem);
|
||||||
|
|
||||||
#if ShouldUseMsabiAttribute()
|
#if ShouldUseMsabiAttribute()
|
||||||
|
|
|
@ -36,8 +36,8 @@ COSMOPOLITAN_C_START_
|
||||||
|
|
||||||
bool32 CreateProcess(const char16_t *opt_lpApplicationName,
|
bool32 CreateProcess(const char16_t *opt_lpApplicationName,
|
||||||
char16_t *lpCommandLine,
|
char16_t *lpCommandLine,
|
||||||
struct NtSecurityAttributes *opt_lpProcessAttributes,
|
const struct NtSecurityAttributes *opt_lpProcessAttributes,
|
||||||
struct NtSecurityAttributes *opt_lpThreadAttributes,
|
const struct NtSecurityAttributes *opt_lpThreadAttributes,
|
||||||
bool32 bInheritHandles, uint32_t dwCreationFlags,
|
bool32 bInheritHandles, uint32_t dwCreationFlags,
|
||||||
void *opt_lpEnvironment,
|
void *opt_lpEnvironment,
|
||||||
const char16_t *opt_lpCurrentDirectory,
|
const char16_t *opt_lpCurrentDirectory,
|
||||||
|
|
|
@ -102,7 +102,7 @@ int RegConnectRegistryEx(const char16_t *lpMachineName, int64_t hKey,
|
||||||
int RegCreateKey(int64_t hKey, const char16_t *lpSubKey, int64_t *phkResult);
|
int RegCreateKey(int64_t hKey, const char16_t *lpSubKey, int64_t *phkResult);
|
||||||
int RegCreateKeyEx(int64_t hKey, const char16_t *lpSubKey, uint32_t Reserved,
|
int RegCreateKeyEx(int64_t hKey, const char16_t *lpSubKey, uint32_t Reserved,
|
||||||
int16_t *lpClass, uint32_t dwOptions, int samDesired,
|
int16_t *lpClass, uint32_t dwOptions, int samDesired,
|
||||||
struct NtSecurityAttributes *lpSecurityAttributes,
|
const struct NtSecurityAttributes *lpSecurityAttributes,
|
||||||
int64_t *phkResult, uint32_t *lpdwDisposition);
|
int64_t *phkResult, uint32_t *lpdwDisposition);
|
||||||
int RegDeleteKey(int64_t hKey, const char16_t *lpSubKey);
|
int RegDeleteKey(int64_t hKey, const char16_t *lpSubKey);
|
||||||
int RegDeleteKeyEx(int64_t hKey, const char16_t *lpSubKey, int samDesired,
|
int RegDeleteKeyEx(int64_t hKey, const char16_t *lpSubKey, int samDesired,
|
||||||
|
@ -127,7 +127,7 @@ int RegReplaceKey(int64_t hKey, const char16_t *lpSubKey,
|
||||||
const char16_t *lpNewFile, const char16_t *lpOldFile);
|
const char16_t *lpNewFile, const char16_t *lpOldFile);
|
||||||
int RegRestoreKey(int64_t hKey, const char16_t *lpFile, uint32_t dwFlags);
|
int RegRestoreKey(int64_t hKey, const char16_t *lpFile, uint32_t dwFlags);
|
||||||
int RegSaveKey(int64_t hKey, const char16_t *lpFile,
|
int RegSaveKey(int64_t hKey, const char16_t *lpFile,
|
||||||
struct NtSecurityAttributes *lpSecurityAttributes);
|
const struct NtSecurityAttributes *lpSecurityAttributes);
|
||||||
int RegSetKeySecurity(int64_t hKey, uint32_t SecurityInformation,
|
int RegSetKeySecurity(int64_t hKey, uint32_t SecurityInformation,
|
||||||
void *pSecurityDescriptor);
|
void *pSecurityDescriptor);
|
||||||
int RegUnLoadKey(int64_t hKey, const char16_t *lpSubKey);
|
int RegUnLoadKey(int64_t hKey, const char16_t *lpSubKey);
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
COSMOPOLITAN_C_START_
|
COSMOPOLITAN_C_START_
|
||||||
|
|
||||||
char16_t *GetCommandLine(void) nosideeffect;
|
char16_t *GetCommandLine(void) nosideeffect;
|
||||||
char16_t *GetEnvironmentStrings(void) dontdiscard;
|
char16_t *GetEnvironmentStrings(void) __wur;
|
||||||
bool32 FreeEnvironmentStrings(char16_t *) paramsnonnull();
|
bool32 FreeEnvironmentStrings(char16_t *) paramsnonnull();
|
||||||
bool32 ReadFile(int64_t hFile, void *lpBuffer, uint32_t nNumberOfBytesToRead,
|
bool32 ReadFile(int64_t hFile, void *lpBuffer, uint32_t nNumberOfBytesToRead,
|
||||||
uint32_t *lpNumberOfBytesRead,
|
uint32_t *lpNumberOfBytesRead,
|
||||||
|
|
|
@ -11,7 +11,7 @@ struct NtSecurityAttributes {
|
||||||
};
|
};
|
||||||
|
|
||||||
const char *DescribeNtSecurityAttributes(char[32],
|
const char *DescribeNtSecurityAttributes(char[32],
|
||||||
struct NtSecurityAttributes *);
|
const struct NtSecurityAttributes *);
|
||||||
#define DescribeNtSecurityAttributes(x) \
|
#define DescribeNtSecurityAttributes(x) \
|
||||||
DescribeNtSecurityAttributes(alloca(32), x)
|
DescribeNtSecurityAttributes(alloca(32), x)
|
||||||
|
|
||||||
|
|
|
@ -75,15 +75,16 @@ bool32 RegisterWaitForSingleObject(int64_t *phNewWaitObject, int64_t hObject,
|
||||||
void *Context, uint32_t dwMilliseconds,
|
void *Context, uint32_t dwMilliseconds,
|
||||||
uint32_t dwFlags);
|
uint32_t dwFlags);
|
||||||
|
|
||||||
int64_t CreateWaitableTimer(struct NtSecurityAttributes *lpTimerAttributes,
|
int64_t CreateWaitableTimer(
|
||||||
bool32 bManualReset, const char16_t *lpTimerName);
|
const struct NtSecurityAttributes *lpTimerAttributes, bool32 bManualReset,
|
||||||
|
const char16_t *lpTimerName);
|
||||||
bool32 SetWaitableTimer(int64_t hTimer, const int64_t *lpDueTimeAsFtOrNegRela,
|
bool32 SetWaitableTimer(int64_t hTimer, const int64_t *lpDueTimeAsFtOrNegRela,
|
||||||
int32_t opt_lPeriodMs, NtTimerapcroutine opt_callback,
|
int32_t opt_lPeriodMs, NtTimerapcroutine opt_callback,
|
||||||
void *lpArgToCallback, bool32 fUnsleepSystem);
|
void *lpArgToCallback, bool32 fUnsleepSystem);
|
||||||
|
|
||||||
int64_t CreateSemaphore(struct NtSecurityAttributes *opt_lpSemaphoreAttributes,
|
int64_t CreateSemaphore(
|
||||||
uint32_t lInitialCount, uint32_t lMaximumCount,
|
const struct NtSecurityAttributes *opt_lpSemaphoreAttributes,
|
||||||
const char16_t *opt_lpName);
|
uint32_t lInitialCount, uint32_t lMaximumCount, const char16_t *opt_lpName);
|
||||||
|
|
||||||
int32_t ReleaseMutex(int64_t hMutex);
|
int32_t ReleaseMutex(int64_t hMutex);
|
||||||
int32_t ReleaseSemaphore(int64_t hSemaphore, int32_t lReleaseCount,
|
int32_t ReleaseSemaphore(int64_t hSemaphore, int32_t lReleaseCount,
|
||||||
|
|
|
@ -30,7 +30,7 @@ COSMOPOLITAN_C_START_
|
||||||
│ cosmopolitan § new technology » threads ─╬─│┼
|
│ cosmopolitan § new technology » threads ─╬─│┼
|
||||||
╚────────────────────────────────────────────────────────────────────────────│*/
|
╚────────────────────────────────────────────────────────────────────────────│*/
|
||||||
|
|
||||||
int64_t CreateThread(struct NtSecurityAttributes *lpThreadAttributes,
|
int64_t CreateThread(const struct NtSecurityAttributes *lpThreadAttributes,
|
||||||
size_t dwStackSize, void *lpStartAddress,
|
size_t dwStackSize, void *lpStartAddress,
|
||||||
void *lpParameter, uint32_t dwCreationFlags,
|
void *lpParameter, uint32_t dwCreationFlags,
|
||||||
uint32_t *opt_lpThreadId);
|
uint32_t *opt_lpThreadId);
|
||||||
|
|
|
@ -291,7 +291,7 @@ struct NtInterfaceInfo {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int32_t WSAStartup(uint16_t wVersionRequested, struct NtWsaData *lpWSAData)
|
int32_t WSAStartup(uint16_t wVersionRequested, struct NtWsaData *lpWSAData)
|
||||||
paramsnonnull() dontdiscard;
|
paramsnonnull() __wur;
|
||||||
|
|
||||||
int WSACleanup(void);
|
int WSACleanup(void);
|
||||||
int WSAGetLastError(void) nosideeffect;
|
int WSAGetLastError(void) nosideeffect;
|
||||||
|
@ -311,7 +311,7 @@ int __sys_select_nt(int, struct NtFdSet *, struct NtFdSet *, struct NtFdSet *,
|
||||||
|
|
||||||
uint64_t WSASocket(int af, int type, int protocol,
|
uint64_t WSASocket(int af, int type, int protocol,
|
||||||
const struct NtWsaProtocolInfo *opt_lpProtocolInfo,
|
const struct NtWsaProtocolInfo *opt_lpProtocolInfo,
|
||||||
const uint32_t opt_group, uint32_t dwFlags) dontdiscard;
|
const uint32_t opt_group, uint32_t dwFlags) __wur;
|
||||||
|
|
||||||
int WSAConnect(uint64_t s, const struct sockaddr *name, const int namelen,
|
int WSAConnect(uint64_t s, const struct sockaddr *name, const int namelen,
|
||||||
const struct NtIovec *opt_lpCallerData,
|
const struct NtIovec *opt_lpCallerData,
|
||||||
|
@ -340,8 +340,7 @@ bool32 WSAConnectByList(uint64_t s,
|
||||||
int64_t WSAAccept(uint64_t s, struct sockaddr *out_addr,
|
int64_t WSAAccept(uint64_t s, struct sockaddr *out_addr,
|
||||||
int32_t *opt_inout_addrlen,
|
int32_t *opt_inout_addrlen,
|
||||||
const NtConditionProc opt_lpfnCondition,
|
const NtConditionProc opt_lpfnCondition,
|
||||||
const uint32_t *opt_dwCallbackData)
|
const uint32_t *opt_dwCallbackData) paramsnonnull((2)) __wur;
|
||||||
paramsnonnull((2)) dontdiscard;
|
|
||||||
|
|
||||||
bool32 AcceptEx(int64_t sListenSocket, int64_t sAcceptSocket,
|
bool32 AcceptEx(int64_t sListenSocket, int64_t sAcceptSocket,
|
||||||
void *out_lpOutputBuffer /*[recvlen+local+remoteaddrlen]*/,
|
void *out_lpOutputBuffer /*[recvlen+local+remoteaddrlen]*/,
|
||||||
|
@ -409,7 +408,7 @@ int WSANSPIoctl(int64_t hLookup, uint32_t dwControlCode,
|
||||||
const struct NtWsaCompletion *opt_lpCompletion)
|
const struct NtWsaCompletion *opt_lpCompletion)
|
||||||
paramsnonnull((3, 5, 7));
|
paramsnonnull((3, 5, 7));
|
||||||
|
|
||||||
int64_t WSACreateEvent(void) dontdiscard;
|
int64_t WSACreateEvent(void) __wur;
|
||||||
bool32 WSACloseEvent(const int64_t hEvent);
|
bool32 WSACloseEvent(const int64_t hEvent);
|
||||||
bool32 WSAResetEvent(const int64_t hEvent);
|
bool32 WSAResetEvent(const int64_t hEvent);
|
||||||
bool32 WSASetEvent(const int64_t hEvent);
|
bool32 WSASetEvent(const int64_t hEvent);
|
||||||
|
|
|
@ -28,10 +28,10 @@
|
||||||
#include "libc/intrin/bits.h"
|
#include "libc/intrin/bits.h"
|
||||||
#include "libc/intrin/getenv.internal.h"
|
#include "libc/intrin/getenv.internal.h"
|
||||||
#include "libc/intrin/weaken.h"
|
#include "libc/intrin/weaken.h"
|
||||||
|
#include "libc/limits.h"
|
||||||
#include "libc/macros.internal.h"
|
#include "libc/macros.internal.h"
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
#include "libc/stdio/stdio.h"
|
#include "libc/stdio/stdio.h"
|
||||||
#include "libc/stdio/temp.h"
|
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
#include "libc/sysv/consts/lock.h"
|
#include "libc/sysv/consts/lock.h"
|
||||||
#include "libc/sysv/consts/o.h"
|
#include "libc/sysv/consts/o.h"
|
||||||
|
@ -39,6 +39,7 @@
|
||||||
#include "libc/sysv/consts/s.h"
|
#include "libc/sysv/consts/s.h"
|
||||||
#include "libc/sysv/consts/sig.h"
|
#include "libc/sysv/consts/sig.h"
|
||||||
#include "libc/sysv/consts/timer.h"
|
#include "libc/sysv/consts/timer.h"
|
||||||
|
#include "libc/temp.h"
|
||||||
#include "third_party/awk/cmd.h"
|
#include "third_party/awk/cmd.h"
|
||||||
#include "third_party/getopt/getopt.internal.h"
|
#include "third_party/getopt/getopt.internal.h"
|
||||||
#include "third_party/musl/glob.h"
|
#include "third_party/musl/glob.h"
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue