mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-02-07 06:53:33 +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)",
|
||||
"alignof(x)",
|
||||
"artificial=",
|
||||
"dontdiscard=",
|
||||
"__wur=",
|
||||
"mayalias=",
|
||||
"forceinline=",
|
||||
"forcealign(x)=",
|
||||
|
|
|
@ -181,10 +181,6 @@ fi
|
|||
|
||||
if [ "$1" = "--update" ]; then
|
||||
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
|
||||
make --silent -j toolchain MODE= || exit
|
||||
echo "building cosmo target (MODE=$MODE) toolchain..." >&2
|
||||
|
|
|
@ -150,10 +150,6 @@ fi
|
|||
|
||||
if [ "$1" = "--update" ]; then
|
||||
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
|
||||
make --silent -j toolchain MODE= || exit
|
||||
echo "building cosmo x86_64 target (MODE=$MODE) toolchain..." >&2
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "libc/errno.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/fmt/itoa.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/log/appendresourcereport.internal.h"
|
||||
#include "libc/log/internal.h"
|
||||
#include "libc/log/log.h"
|
||||
|
|
|
@ -7,15 +7,16 @@
|
|||
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/time/time.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/timespec.h"
|
||||
#include "libc/fmt/itoa.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/math.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/ex.h"
|
||||
#include "libc/time/time.h"
|
||||
#include "libc/x/xspawn.h"
|
||||
|
||||
/**
|
||||
|
|
|
@ -26,11 +26,6 @@
|
|||
#define _POSIX_MEMLOCK_RANGE _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_CUR 1 /* relative to current position */
|
||||
#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 execvp(const char *, char *const[]);
|
||||
int faccessat(int, const char *, int, int);
|
||||
int fadvise(int, uint64_t, uint64_t, int);
|
||||
int fchdir(int);
|
||||
int fchmod(int, unsigned) dontthrow;
|
||||
int fchmodat(int, const char *, unsigned, int);
|
||||
|
@ -136,7 +130,6 @@ int mkdirat(int, const char *, unsigned);
|
|||
int mkfifo(const char *, unsigned);
|
||||
int mkfifoat(int, const char *, unsigned);
|
||||
int mknod(const char *, unsigned, uint64_t);
|
||||
int mknodat(int, const char *, int, uint64_t);
|
||||
int nice(int);
|
||||
int open(const char *, int, ...);
|
||||
int openat(int, const char *, int, ...);
|
||||
|
@ -205,7 +198,7 @@ int setresgid(unsigned, unsigned, unsigned);
|
|||
int setresuid(unsigned, unsigned, unsigned);
|
||||
int getresgid(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);
|
||||
ssize_t splice(int, int64_t *, int, int64_t *, size_t, unsigned);
|
||||
int memfd_create(const char *, unsigned int);
|
||||
|
@ -245,6 +238,7 @@ int tmpfd(void);
|
|||
int touch(const char *, unsigned);
|
||||
int unveil(const char *, const char *);
|
||||
long ptrace(int, ...);
|
||||
int fadvise(int, uint64_t, uint64_t, int);
|
||||
ssize_t copyfd(int, int, size_t);
|
||||
ssize_t readansi(int, char *, size_t);
|
||||
ssize_t tinyprint(int, const char *, ...) nullterminated();
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
#define _O_EXCL 0x00000080 // kNtCreateNew
|
||||
#define _O_TRUNC 0x00000200 // kNtCreateAlways
|
||||
#define _O_DIRECTORY 0x00010000 // kNtFileFlagBackupSemantics
|
||||
#define _O_TMPFILE 0x00410000 // AttributeTemporary|FlagDeleteOnClose
|
||||
#define _O_UNLINK 0x04000100 // kNtFileAttributeTemporary|DeleteOnClose
|
||||
#define _O_DIRECT 0x00004000 // kNtFileFlagNoBuffering
|
||||
#define _O_NONBLOCK 0x00000800 // kNtFileFlagWriteThrough (not sent to win32)
|
||||
#define _O_RANDOM 0x80000000 // kNtFileFlagRandomAccess
|
||||
|
@ -51,11 +51,18 @@ textwindows int GetNtOpenFlags(int flags, int mode, uint32_t *out_perm,
|
|||
|
||||
if (flags &
|
||||
~(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)) {
|
||||
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) {
|
||||
case O_RDONLY:
|
||||
perm = kNtFileGenericRead;
|
||||
|
@ -80,7 +87,7 @@ textwindows int GetNtOpenFlags(int flags, int mode, uint32_t *out_perm,
|
|||
}
|
||||
|
||||
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
|
||||
// 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;
|
||||
}
|
||||
|
||||
// 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) {
|
||||
// The Windows content indexing service ravages performance similar to
|
||||
// Windows Defender. Please pass O_INDEXED to openat() to enable this.
|
||||
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) {
|
||||
// Windows' transparent filesystem compression is really cool, as such
|
||||
// we've introduced a nonstandard O_COMPRESSED flag to help you use it
|
||||
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.
|
||||
if (flags & _O_SEQUENTIAL) attr |= kNtFileFlagSequentialScan;
|
||||
if (flags & _O_RANDOM) attr |= kNtFileFlagRandomAccess;
|
||||
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_share) *out_share = share;
|
||||
if (out_disp) *out_disp = disp;
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/mem/alloca.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "libc/errno.h"
|
||||
#include "libc/intrin/bits.h"
|
||||
#include "libc/intrin/safemacros.internal.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/mem/alloca.h"
|
||||
#include "libc/paths.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "libc/calls/calls.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/mem/alloca.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/str/str.h"
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#include "libc/intrin/safemacros.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/f.h"
|
||||
#include "libc/sysv/consts/fd.h"
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
|
@ -25,6 +26,7 @@
|
|||
#include "libc/intrin/bsr.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/mem/alloca.h"
|
||||
#include "libc/nt/enum/fileflagandattributes.h"
|
||||
#include "libc/nt/enum/fileinfobyhandleclass.h"
|
||||
#include "libc/nt/enum/filetype.h"
|
||||
|
@ -39,102 +41,119 @@
|
|||
#include "libc/sysv/consts/s.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
static textwindows uint32_t GetSizeOfReparsePoint(int64_t fh) {
|
||||
wint_t x, y;
|
||||
const char16_t *p;
|
||||
uint32_t mem, i, n, z = 0;
|
||||
struct NtReparseDataBuffer *rdb;
|
||||
long buf[(sizeof(*rdb) + PATH_MAX * sizeof(char16_t)) / sizeof(long)];
|
||||
mem = sizeof(buf);
|
||||
rdb = (struct NtReparseDataBuffer *)buf;
|
||||
if (DeviceIoControl(fh, kNtFsctlGetReparsePoint, 0, 0, rdb, mem, &n, 0)) {
|
||||
i = 0;
|
||||
n = rdb->SymbolicLinkReparseBuffer.PrintNameLength / sizeof(char16_t);
|
||||
p = (char16_t *)((char *)rdb->SymbolicLinkReparseBuffer.PathBuffer +
|
||||
rdb->SymbolicLinkReparseBuffer.PrintNameOffset);
|
||||
while (i < n) {
|
||||
x = p[i++] & 0xffff;
|
||||
if (!IsUcs2(x)) {
|
||||
if (i < n) {
|
||||
y = p[i++] & 0xffff;
|
||||
x = MergeUtf16(x, y);
|
||||
} else {
|
||||
x = 0xfffd;
|
||||
}
|
||||
static textwindows long GetSizeOfReparsePoint(int64_t fh) {
|
||||
uint32_t mem =
|
||||
sizeof(struct NtReparseDataBuffer) + PATH_MAX * sizeof(char16_t);
|
||||
void *buf = alloca(mem);
|
||||
uint32_t dwBytesReturned;
|
||||
struct NtReparseDataBuffer *rdb = (struct NtReparseDataBuffer *)buf;
|
||||
if (!DeviceIoControl(fh, kNtFsctlGetReparsePoint, 0, 0, rdb, mem,
|
||||
&dwBytesReturned, 0)) {
|
||||
return -1;
|
||||
}
|
||||
const char16_t *p =
|
||||
(const char16_t *)((char *)rdb->SymbolicLinkReparseBuffer.PathBuffer +
|
||||
rdb->SymbolicLinkReparseBuffer.PrintNameOffset);
|
||||
uint32_t n =
|
||||
rdb->SymbolicLinkReparseBuffer.PrintNameLength / sizeof(char16_t);
|
||||
uint32_t i = 0;
|
||||
uint32_t z = 0;
|
||||
while (i < n) {
|
||||
wint_t x = p[i++] & 0xffff;
|
||||
if (!IsUcs2(x)) {
|
||||
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 {
|
||||
STRACE("%s failed %m", "GetSizeOfReparsePoint");
|
||||
if (x >= 0200) {
|
||||
z += _bsrl(tpenc(x)) >> 3;
|
||||
}
|
||||
++z;
|
||||
}
|
||||
return z;
|
||||
}
|
||||
|
||||
textwindows int sys_fstat_nt(int64_t handle, struct stat *st) {
|
||||
int filetype;
|
||||
uint32_t umask;
|
||||
uint64_t actualsize;
|
||||
struct NtFileCompressionInfo fci;
|
||||
struct NtByHandleFileInformation wst;
|
||||
if (!st) return efault();
|
||||
if ((filetype = GetFileType(handle))) {
|
||||
bzero(st, sizeof(*st));
|
||||
umask = atomic_load_explicit(&__umask, memory_order_acquire);
|
||||
switch (filetype) {
|
||||
case kNtFileTypeChar:
|
||||
st->st_mode = S_IFCHR | (0666 & ~umask);
|
||||
break;
|
||||
case kNtFileTypePipe:
|
||||
st->st_mode = S_IFIFO | (0666 & ~umask);
|
||||
break;
|
||||
case kNtFileTypeDisk:
|
||||
if (GetFileInformationByHandle(handle, &wst)) {
|
||||
st->st_mode = 0555 & ~umask;
|
||||
st->st_flags = wst.dwFileAttributes;
|
||||
if (!(wst.dwFileAttributes & kNtFileAttributeReadonly)) {
|
||||
st->st_mode |= 0222 & ~umask;
|
||||
}
|
||||
if (wst.dwFileAttributes & kNtFileAttributeDirectory) {
|
||||
st->st_mode |= S_IFDIR;
|
||||
} else if (wst.dwFileAttributes & kNtFileAttributeReparsePoint) {
|
||||
st->st_mode |= S_IFLNK;
|
||||
} else {
|
||||
st->st_mode |= S_IFREG;
|
||||
}
|
||||
st->st_atim = FileTimeToTimeSpec(wst.ftLastAccessFileTime);
|
||||
st->st_mtim = FileTimeToTimeSpec(wst.ftLastWriteFileTime);
|
||||
st->st_ctim = FileTimeToTimeSpec(wst.ftCreationFileTime);
|
||||
st->st_birthtim = st->st_ctim;
|
||||
st->st_gid = st->st_uid = __synthesize_uid();
|
||||
st->st_size = (uint64_t)wst.nFileSizeHigh << 32 | wst.nFileSizeLow;
|
||||
st->st_blksize = 4096;
|
||||
st->st_dev = wst.dwVolumeSerialNumber;
|
||||
st->st_rdev = 0;
|
||||
st->st_ino = (uint64_t)wst.nFileIndexHigh << 32 | wst.nFileIndexLow;
|
||||
st->st_nlink = wst.nNumberOfLinks;
|
||||
if (S_ISLNK(st->st_mode)) {
|
||||
if (!st->st_size) {
|
||||
st->st_size = GetSizeOfReparsePoint(handle);
|
||||
}
|
||||
} else {
|
||||
actualsize = st->st_size;
|
||||
if (S_ISREG(st->st_mode) &&
|
||||
GetFileInformationByHandleEx(handle, kNtFileCompressionInfo,
|
||||
&fci, sizeof(fci))) {
|
||||
actualsize = fci.CompressedFileSize;
|
||||
}
|
||||
st->st_blocks = ROUNDUP(actualsize, 4096) / 512;
|
||||
}
|
||||
} else {
|
||||
STRACE("%s failed %m", "GetFileInformationByHandle");
|
||||
textwindows int sys_fstat_nt(int64_t handle, struct stat *out_st) {
|
||||
struct stat st = {0};
|
||||
|
||||
// Always set st_blksize to avoid divide by zero issues.
|
||||
// The Linux kernel sets this for /dev/tty and similar too.
|
||||
// TODO(jart): GetVolumeInformationByHandle?
|
||||
st.st_blksize = 4096;
|
||||
|
||||
// We'll use the "umask" to fake out the mode bits.
|
||||
uint32_t umask = atomic_load_explicit(&__umask, memory_order_acquire);
|
||||
|
||||
switch (GetFileType(handle)) {
|
||||
case kNtFileTypeUnknown:
|
||||
break;
|
||||
case kNtFileTypeChar:
|
||||
st.st_mode = S_IFCHR | (0666 & ~umask);
|
||||
break;
|
||||
case kNtFileTypePipe:
|
||||
st.st_mode = S_IFIFO | (0666 & ~umask);
|
||||
break;
|
||||
case kNtFileTypeDisk: {
|
||||
struct NtByHandleFileInformation wst;
|
||||
if (!GetFileInformationByHandle(handle, &wst)) {
|
||||
return __winerr();
|
||||
}
|
||||
st.st_mode = 0555 & ~umask;
|
||||
st.st_flags = wst.dwFileAttributes;
|
||||
if (!(wst.dwFileAttributes & kNtFileAttributeReadonly)) {
|
||||
st.st_mode |= 0222 & ~umask;
|
||||
}
|
||||
if (wst.dwFileAttributes & kNtFileAttributeReparsePoint) {
|
||||
st.st_mode |= S_IFLNK;
|
||||
} else if (wst.dwFileAttributes & kNtFileAttributeDirectory) {
|
||||
st.st_mode |= S_IFDIR;
|
||||
} else {
|
||||
st.st_mode |= S_IFREG;
|
||||
}
|
||||
st.st_atim = FileTimeToTimeSpec(wst.ftLastAccessFileTime);
|
||||
st.st_mtim = FileTimeToTimeSpec(wst.ftLastWriteFileTime);
|
||||
st.st_birthtim = FileTimeToTimeSpec(wst.ftCreationFileTime);
|
||||
// compute time of last status change
|
||||
if (timespec_cmp(st.st_atim, st.st_mtim) > 0) {
|
||||
st.st_ctim = st.st_atim;
|
||||
} else {
|
||||
st.st_ctim = st.st_mtim;
|
||||
}
|
||||
st.st_gid = st.st_uid = __synthesize_uid();
|
||||
st.st_size = (wst.nFileSizeHigh + 0ull) << 32 | wst.nFileSizeLow;
|
||||
st.st_dev = wst.dwVolumeSerialNumber;
|
||||
st.st_ino = (wst.nFileIndexHigh + 0ull) << 32 | wst.nFileIndexLow;
|
||||
st.st_nlink = wst.nNumberOfLinks;
|
||||
if (S_ISLNK(st.st_mode)) {
|
||||
if (!st.st_size) {
|
||||
long size = GetSizeOfReparsePoint(handle);
|
||||
if (size == -1) return -1;
|
||||
st.st_size = size;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
} else {
|
||||
// st_size = uncompressed size
|
||||
// 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;
|
||||
} else {
|
||||
STRACE("%s failed %m", "GetFileType");
|
||||
return __winerr();
|
||||
default:
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
memcpy(out_st, &st, sizeof(st));
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -17,16 +17,9 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#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/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) {
|
||||
void *p;
|
||||
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];
|
||||
if (__mkntpathat(dirfd, path, 0, path16) == -1) return -1;
|
||||
if ((fh = CreateFile(
|
||||
path16, kNtFileReadAttributes, 0, 0, kNtOpenExisting,
|
||||
path16, kNtFileReadAttributes,
|
||||
kNtFileShareRead | kNtFileShareWrite | kNtFileShareDelete, 0,
|
||||
kNtOpenExisting,
|
||||
kNtFileAttributeNormal | kNtFileFlagBackupSemantics |
|
||||
((flags & AT_SYMLINK_NOFOLLOW) ? kNtFileFlagOpenReparsePoint
|
||||
: 0),
|
||||
|
|
|
@ -17,10 +17,8 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/struct/metastat.internal.h"
|
||||
#include "libc/calls/struct/stat.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.
|
||||
|
@ -30,7 +28,6 @@ int32_t sys_fstatat(int32_t dirfd, const char *path, struct stat *st,
|
|||
int32_t flags) {
|
||||
void *p;
|
||||
union metastat ms;
|
||||
if (IsAsan() && !__asan_is_valid_str(path)) return efault();
|
||||
if (st) {
|
||||
p = &ms;
|
||||
} else {
|
||||
|
|
|
@ -44,7 +44,11 @@
|
|||
*/
|
||||
int futimens(int fd, const struct timespec ts[2]) {
|
||||
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),
|
||||
DescribeTimespec(0, ts ? ts + 1 : 0), rc);
|
||||
return rc;
|
||||
|
|
|
@ -42,19 +42,16 @@
|
|||
int futimes(int fd, const struct timeval tv[2]) {
|
||||
int rc;
|
||||
struct timespec ts[2];
|
||||
|
||||
if (tv) {
|
||||
ts[0].tv_sec = tv[0].tv_sec;
|
||||
ts[0].tv_nsec = tv[0].tv_usec * 1000;
|
||||
ts[1].tv_sec = tv[1].tv_sec;
|
||||
ts[1].tv_nsec = tv[1].tv_usec * 1000;
|
||||
if (fd < 0) {
|
||||
rc = ebadf(); // so we don't confuse __utimens if caller passes AT_FDCWD
|
||||
} else if (tv) {
|
||||
ts[0] = timeval_totimespec(tv[0]);
|
||||
ts[1] = timeval_totimespec(tv[1]);
|
||||
rc = __utimens(fd, 0, ts, 0);
|
||||
} else {
|
||||
rc = __utimens(fd, 0, 0, 0);
|
||||
}
|
||||
|
||||
STRACE("futimes(%d, {%s, %s}) → %d% m", fd, DescribeTimeval(0, tv),
|
||||
DescribeTimeval(0, tv ? tv + 1 : 0), rc);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "libc/dce.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/log/backtrace.internal.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/str/str.h"
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "libc/cosmo.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
|
|
|
@ -16,21 +16,46 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/atomic.h"
|
||||
#include "libc/cosmo.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sysv/consts/pr.h"
|
||||
|
||||
bool __is_linux_2_6_23(void) {
|
||||
#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;
|
||||
if (!IsLinux()) return false;
|
||||
if (IsGenuineBlink()) return true;
|
||||
asm volatile("syscall"
|
||||
: "=a"(rc)
|
||||
: "0"(157), "D"(PR_GET_SECCOMP)
|
||||
: "rcx", "r11", "memory");
|
||||
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
|
||||
return true;
|
||||
#endif
|
||||
|
|
|
@ -37,7 +37,7 @@ int issetugid(void) {
|
|||
int rc;
|
||||
if (IsLinux()) {
|
||||
rc = !!__getauxval(AT_SECURE).value;
|
||||
} else if (IsMetal()) {
|
||||
} else if (IsMetal() || IsWindows()) {
|
||||
rc = 0;
|
||||
} else {
|
||||
rc = sys_issetugid();
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/nt/systeminfo.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
|
|
|
@ -27,10 +27,8 @@
|
|||
int lutimes(const char *filename, const struct timeval tv[2]) {
|
||||
struct timespec ts[2];
|
||||
if (tv) {
|
||||
ts[0].tv_sec = tv[0].tv_sec;
|
||||
ts[0].tv_nsec = tv[0].tv_usec * 1000;
|
||||
ts[1].tv_sec = tv[1].tv_sec;
|
||||
ts[1].tv_nsec = tv[1].tv_usec * 1000;
|
||||
ts[0] = timeval_totimespec(tv[0]);
|
||||
ts[1] = timeval_totimespec(tv[1]);
|
||||
return utimensat(AT_FDCWD, filename, ts, AT_SYMLINK_NOFOLLOW);
|
||||
} else {
|
||||
return utimensat(AT_FDCWD, filename, 0, AT_SYMLINK_NOFOLLOW);
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/str/path.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/s.h"
|
||||
|
|
|
@ -18,47 +18,45 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.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/errfuns.h"
|
||||
#include "libc/temp.h"
|
||||
|
||||
/**
|
||||
* Creates temporary directory, e.g.
|
||||
*
|
||||
* char path[PATH_MAX];
|
||||
* snprintf(path, sizeof(path), "%s%s.XXXXXX",
|
||||
* kTmpPath, program_invocation_short_name);
|
||||
* printf("%s\n", mkdtemp(path));
|
||||
* char path[] = "/tmp/foo.XXXXXX";
|
||||
* mkdtemp(path);
|
||||
* rmdir(path);
|
||||
*
|
||||
* @param template must end with XXXXXX which is replaced with
|
||||
* nondeterministic base36 random data
|
||||
* @param template must end with XXXXXX which will be replaced
|
||||
* with random text on success (and not modified on error)
|
||||
* @return pointer to template on success, or NULL w/ errno
|
||||
* @raise EINVAL if template didn't end with XXXXXX
|
||||
*/
|
||||
char *mkdtemp(char *template) {
|
||||
unsigned x;
|
||||
int i, j, n;
|
||||
if ((n = strlen(template)) >= 6 && !memcmp(template + n - 6, "XXXXXX", 6)) {
|
||||
for (i = 0; i < 10; ++i) {
|
||||
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 {
|
||||
int n;
|
||||
if ((n = strlen(template)) < 6 ||
|
||||
READ32LE(template + n - 6) != READ32LE("XXXX") ||
|
||||
READ16LE(template + n - 6 + 4) != READ16LE("XX")) {
|
||||
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 │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/dce.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;
|
||||
}
|
||||
}
|
||||
}
|
||||
#include "libc/temp.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
|
||||
/**
|
||||
* 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[PATH_MAX+1];
|
||||
* 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);
|
||||
* char path[] = "/tmp/foo.XXXXXX";
|
||||
* int fd = mkstemp(path);
|
||||
* 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 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
|
||||
*/
|
||||
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 │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/stdio/temp.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
#include "libc/temp.h"
|
||||
|
||||
/**
|
||||
* Generates temporary filename.
|
||||
|
@ -27,15 +29,20 @@
|
|||
*
|
||||
* @param template is mutated to replace last six X's with rng
|
||||
* @raise EINVAL if `template` didn't end with `XXXXXX`
|
||||
* @return pointer to mutated `template`, or 0 w/ errno
|
||||
* @see mkstemp()
|
||||
* @return always `template` which on success will have its XXXXXX bytes
|
||||
* 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) {
|
||||
int fd;
|
||||
if ((fd = mkstemp(template)) != -1) {
|
||||
close(fd);
|
||||
return template;
|
||||
if ((fd = openatemp(AT_FDCWD, template, 0, 0, 0)) != -1) {
|
||||
unassert(!close(fd));
|
||||
} else {
|
||||
return 0;
|
||||
*template = 0;
|
||||
}
|
||||
return template;
|
||||
}
|
||||
|
|
|
@ -66,9 +66,11 @@ struct SpawnBlock {
|
|||
*/
|
||||
textwindows int ntspawn(
|
||||
const char *prog, char *const argv[], char *const envp[],
|
||||
const char *extravar, struct NtSecurityAttributes *opt_lpProcessAttributes,
|
||||
struct NtSecurityAttributes *opt_lpThreadAttributes, bool32 bInheritHandles,
|
||||
uint32_t dwCreationFlags, const char16_t *opt_lpCurrentDirectory,
|
||||
const char *extravar,
|
||||
const struct NtSecurityAttributes *opt_lpProcessAttributes,
|
||||
const struct NtSecurityAttributes *opt_lpThreadAttributes,
|
||||
bool32 bInheritHandles, uint32_t dwCreationFlags,
|
||||
const char16_t *opt_lpCurrentDirectory,
|
||||
const struct NtStartupInfo *lpStartupInfo,
|
||||
struct NtProcessInformation *opt_out_lpProcessInformation) {
|
||||
int rc;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#ifndef 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/securityattributes.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 *,
|
||||
char[ARG_MAX]);
|
||||
int ntspawn(const char *, char *const[], char *const[], const char *,
|
||||
struct NtSecurityAttributes *, struct NtSecurityAttributes *,
|
||||
bool32, uint32_t, const char16_t *, const struct NtStartupInfo *,
|
||||
const struct NtSecurityAttributes *,
|
||||
const struct NtSecurityAttributes *, bool32, uint32_t,
|
||||
const char16_t *, const struct NtStartupInfo *,
|
||||
struct NtProcessInformation *);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
|
|
|
@ -23,14 +23,17 @@
|
|||
#include "libc/calls/syscall-nt.internal.h"
|
||||
#include "libc/calls/syscall_support-nt.internal.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/nt/createfile.h"
|
||||
#include "libc/nt/enum/accessmask.h"
|
||||
#include "libc/nt/enum/creationdisposition.h"
|
||||
#include "libc/nt/enum/fileflagandattributes.h"
|
||||
#include "libc/nt/enum/filesharemode.h"
|
||||
#include "libc/nt/enum/filetype.h"
|
||||
#include "libc/nt/files.h"
|
||||
#include "libc/nt/process.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/nt/synchronization.h"
|
||||
#include "libc/nt/thunk/msabi.h"
|
||||
#include "libc/str/str.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;
|
||||
}
|
||||
|
||||
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 :'(
|
||||
if (disp == kNtTruncateExisting) {
|
||||
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
|
||||
return __fix_enotdir(CreateFile(path16, perm, share, &kNtIsInheritable, disp,
|
||||
attr | extra_attr, 0),
|
||||
path16);
|
||||
int e = errno;
|
||||
int64_t hand = CreateFile(path16, perm | extra_perm, share, &kNtIsInheritable,
|
||||
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,
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/itoa.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/intrin/describeflags.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
|
@ -92,6 +93,7 @@
|
|||
* - `O_APPEND` open file for appending only
|
||||
* - `O_NOFOLLOW` fail with ELOOP if it's a symlink
|
||||
* - `O_NONBLOCK` asks read/write to fail with `EAGAIN` rather than block
|
||||
* - `O_UNLINK` delete file automatically on close
|
||||
* - `O_EXEC` open file for execution only; see fexecve()
|
||||
* - `O_NOCTTY` prevents `path` from becoming the controlling terminal
|
||||
* - `O_DIRECTORY` advisory feature for avoiding accidentally opening files
|
||||
|
@ -107,7 +109,7 @@
|
|||
* - `O_SEQUENTIAL` hint sequential access intent (zero on non-Windows)
|
||||
* - `O_COMPRESSED` ask fs to abstract compression (zero on non-Windows)
|
||||
* - `O_INDEXED` turns on that slow performance (zero on non-Windows)
|
||||
* - `O_TMPFILE` should not be used; use tmpfd() or tmpfile() instead
|
||||
* - `O_TMPFILE` EINVALs on non-Linux; please use tmpfd() / tmpfile()
|
||||
* There are three regular combinations for the above flags:
|
||||
* - `O_RDONLY`: Opens existing file for reading. If it doesn't
|
||||
* exist then nil is returned and errno will be `ENOENT` (or in
|
||||
|
@ -148,6 +150,7 @@
|
|||
* @raise EINTR if we needed to block and a signal was delivered instead
|
||||
* @raise EEXIST if `O_CREAT|O_EXCL` are used and `path` already existed
|
||||
* @raise EINVAL if ASCII control codes are used in `path` on Windows
|
||||
* @raise EINVAL if `O_UNLINK` is used without `O_CREAT|O_EXCL`
|
||||
* @raise EINVAL if `O_TRUNC` is specified in `O_RDONLY` mode
|
||||
* @raise EINVAL if `flags` contains unsupported bits
|
||||
* @raise ECANCELED if thread was cancelled in masked mode
|
||||
|
@ -180,6 +183,15 @@ int openat(int dirfd, const char *path, int flags, ...) {
|
|||
|
||||
if (!path || (IsAsan() && !__asan_is_valid_str(path))) {
|
||||
rc = efault();
|
||||
} else if ((flags & O_UNLINK) &&
|
||||
(flags & (O_CREAT | O_EXCL)) != (O_CREAT | O_EXCL)) {
|
||||
// O_UNLINK is a non-standard cosmo extension; we've chosen bits for
|
||||
// this magic number which we believe are unlikely to interfere with
|
||||
// the bits chosen by operating systems both today and in the future
|
||||
// however, due to the risks here and the irregularity of using this
|
||||
// feature for anything but temporary files, we are going to prevent
|
||||
// the clever use cases for now; please file an issue if you want it
|
||||
rc = einval();
|
||||
} else if (__isfdkind(dirfd, kFdZip)) {
|
||||
rc = enotsup(); // TODO
|
||||
} else if (_weaken(__zipos_open) &&
|
||||
|
@ -190,20 +202,29 @@ int openat(int dirfd, const char *path, int flags, ...) {
|
|||
rc = enotsup(); // TODO
|
||||
}
|
||||
} else if ((flags & O_ACCMODE) == O_RDONLY && (flags & O_TRUNC)) {
|
||||
rc = einval(); // Every OS except OpenBSD actually does this D:
|
||||
// Every operating system we've tested (with the notable exception
|
||||
// of OpenBSD) will gladly truncate files opened in read-only mode
|
||||
rc = einval();
|
||||
} else if (IsLinux() || IsXnu() || IsFreebsd() || IsOpenbsd() || IsNetbsd()) {
|
||||
rc = sys_openat(dirfd, path, flags, mode);
|
||||
if (IsFreebsd()) {
|
||||
// Address FreeBSD divergence from IEEE Std 1003.1-2008 (POSIX.1)
|
||||
// in the case when O_NOFOLLOW is used, but fails due to symlink.
|
||||
if (rc == -1 && errno == EMLINK) {
|
||||
// openat unix userspace
|
||||
rc = sys_openat(dirfd, path, flags & ~O_UNLINK, mode);
|
||||
if (rc != -1) {
|
||||
// openat succeeded
|
||||
if (flags & O_UNLINK) {
|
||||
// Implement Cosmopolitan O_UNLINK extension for UNIX
|
||||
// This cannot fail since we require O_CREAT / O_EXCL
|
||||
unassert(!sys_unlinkat(dirfd, path, 0));
|
||||
}
|
||||
} else {
|
||||
// openat failed
|
||||
if (IsFreebsd() && errno == EMLINK) {
|
||||
// Address FreeBSD divergence from IEEE Std 1003.1-2008 (POSIX.1)
|
||||
// in the case when O_NOFOLLOW is used, but fails due to symlink.
|
||||
errno = ELOOP;
|
||||
}
|
||||
}
|
||||
if (IsNetbsd()) {
|
||||
// Address NetBSD divergence from IEEE Std 1003.1-2008 (POSIX.1)
|
||||
// in the case when O_NOFOLLOW is used but fails due to symlink.
|
||||
if (rc == -1 && errno == EFTYPE) {
|
||||
if (IsNetbsd() && errno == EFTYPE) {
|
||||
// Address NetBSD divergence from IEEE Std 1003.1-2008 (POSIX.1)
|
||||
// in the case when O_NOFOLLOW is used but fails due to symlink.
|
||||
errno = ELOOP;
|
||||
}
|
||||
}
|
||||
|
@ -216,9 +237,8 @@ int openat(int dirfd, const char *path, int flags, ...) {
|
|||
}
|
||||
|
||||
END_CANCELLATION_POINT;
|
||||
STRACE("openat(%s, %#s, %s, %#o) → %d% m", DescribeDirfd(dirfd), path,
|
||||
DescribeOpenFlags(flags), (flags & (O_CREAT | O_TMPFILE)) ? mode : 0,
|
||||
rc);
|
||||
STRACE("openat(%s, %#s, %s%s) → %d% m", DescribeDirfd(dirfd), path,
|
||||
DescribeOpenFlags(flags), DescribeOpenMode(flags, mode), rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
|
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 -*-│
|
||||
│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 │
|
||||
│ 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 │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/struct/termios.h"
|
||||
#include "libc/calls/termios.h"
|
||||
#include "libc/sysv/consts/termios.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
struct termios t;
|
||||
if (tcgetattr(0, &t) == -1) return 1;
|
||||
t.c_lflag ^= ECHOCTL;
|
||||
if (tcsetattr(0, TCSANOW, &t) == -1) return 2;
|
||||
/**
|
||||
* Returns environment variable, securely.
|
||||
*
|
||||
* This is the same as getenv() except it'll return null if current
|
||||
* 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;
|
||||
typedef struct dirstream DIR;
|
||||
|
||||
DIR *fdopendir(int) dontdiscard;
|
||||
DIR *opendir(const char *) dontdiscard;
|
||||
DIR *fdopendir(int) __wur;
|
||||
DIR *opendir(const char *) __wur;
|
||||
int closedir(DIR *);
|
||||
int dirfd(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_utimensat(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 *);
|
||||
#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_mkdirat_nt(int, const char *, uint32_t);
|
||||
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_renameat_nt(int, const char *, int, const char *);
|
||||
int sys_sched_yield_nt(void);
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#ifndef 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)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
|
|
|
@ -15,13 +15,13 @@ int tcsetattr(int, int, const struct termios *);
|
|||
int openpty(int *, int *, char *, const struct termios *,
|
||||
const struct winsize *) paramsnonnull((1, 2));
|
||||
int forkpty(int *, char *, const struct termios *, const struct winsize *)
|
||||
paramsnonnull((1, 2)) dontdiscard;
|
||||
paramsnonnull((1, 2)) __wur;
|
||||
char *ptsname(int);
|
||||
errno_t ptsname_r(int, char *, size_t);
|
||||
|
||||
int grantpt(int);
|
||||
int unlockpt(int);
|
||||
int posix_openpt(int) dontdiscard;
|
||||
int posix_openpt(int) __wur;
|
||||
|
||||
int tcdrain(int);
|
||||
int tcgetsid(int);
|
||||
|
|
|
@ -20,12 +20,14 @@
|
|||
#include "libc/calls/calls.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/temp.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/temp.h"
|
||||
|
||||
#define _O_TMPFILE 000020200000
|
||||
#define O_TMPFILE_LINUX 0x00410000
|
||||
|
||||
int _mkstemp(char *, int);
|
||||
|
||||
|
@ -79,7 +81,7 @@ int tmpfd(void) {
|
|||
char path[PATH_MAX + 1];
|
||||
if (IsLinux()) {
|
||||
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;
|
||||
} else {
|
||||
errno = e;
|
||||
|
@ -90,7 +92,6 @@ int tmpfd(void) {
|
|||
if (!(prog = program_invocation_short_name)) prog = "tmp";
|
||||
strlcat(path, prog, sizeof(path));
|
||||
strlcat(path, ".XXXXXX", sizeof(path));
|
||||
if ((fd = _mkstemp(path, IsWindows() ? 0x00410000 : 0)) == -1) return -1;
|
||||
if (!IsWindows()) unassert(!unlink(path));
|
||||
if ((fd = openatemp(AT_FDCWD, path, 0, O_UNLINK, 0)) == -1) return -1;
|
||||
return fd;
|
||||
}
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include "libc/fmt/conv.h"
|
||||
#include "libc/fmt/libgen.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/nexgen32e/vendor.internal.h"
|
||||
#include "libc/runtime/internal.h"
|
||||
|
@ -175,7 +176,7 @@ static int unveil_init(void) {
|
|||
.handled_access_fs = State.fs_mask,
|
||||
};
|
||||
// [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;
|
||||
// grant file descriptor a higher number that's less likely to interfere
|
||||
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) &&
|
||||
_weaken(__zipos_parseuri)(path, &zipname) != -1))) {
|
||||
rc = erofs();
|
||||
} else if (IsLinux() && !__is_linux_2_6_23() && fd == AT_FDCWD && !flags) {
|
||||
rc = sys_utimes(path, (void *)ts); // rhel5 truncates to seconds
|
||||
} else if (!IsWindows()) {
|
||||
} else if (IsXnu() || (IsLinux() && !__is_linux_2_6_23())) {
|
||||
rc = sys_utimensat_old(fd, path, ts, flags);
|
||||
} else if (IsLinux() || IsFreebsd() || IsOpenbsd() || IsNetbsd()) {
|
||||
rc = sys_utimensat(fd, path, ts, flags);
|
||||
} else {
|
||||
} else if (IsWindows()) {
|
||||
rc = sys_utimensat_nt(fd, path, ts, flags);
|
||||
} else if (IsMetal()) {
|
||||
rc = enosys();
|
||||
} else {
|
||||
rc = enosys();
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -41,8 +41,14 @@ textwindows int sys_utimensat_nt(int dirfd, const char *path,
|
|||
|
||||
if (path) {
|
||||
if (__mkntpathat(dirfd, path, 0, path16) == -1) return -1;
|
||||
if ((fh = CreateFile(path16, kNtFileWriteAttributes, kNtFileShareRead, NULL,
|
||||
kNtOpenExisting, kNtFileAttributeNormal, 0)) != -1) {
|
||||
if ((fh = CreateFile(
|
||||
path16, kNtFileWriteAttributes,
|
||||
kNtFileShareRead | kNtFileShareWrite | kNtFileShareDelete, NULL,
|
||||
kNtOpenExisting,
|
||||
kNtFileAttributeNormal | kNtFileFlagBackupSemantics |
|
||||
((flags & AT_SYMLINK_NOFOLLOW) ? kNtFileFlagOpenReparsePoint
|
||||
: 0),
|
||||
0)) != -1) {
|
||||
closeme = fh;
|
||||
} else {
|
||||
return __winerr();
|
||||
|
|
|
@ -16,27 +16,78 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/calls/calls.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.internal.h"
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/nexgen32e/nexgen32e.h"
|
||||
#include "libc/dce.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/utime.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) {
|
||||
struct stat st;
|
||||
struct timeval now, tv[2];
|
||||
if (flags) return einval();
|
||||
char buf[PATH_MAX + 1];
|
||||
|
||||
// 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) {
|
||||
gettimeofday(&now, NULL);
|
||||
unassert(!gettimeofday(&now, 0));
|
||||
}
|
||||
if (ts && (ts[0].tv_nsec == UTIME_NOW || ts[1].tv_nsec == UTIME_NOW)) {
|
||||
if (fstatat(dirfd, path, &st, flags) == -1) return -1;
|
||||
struct stat st;
|
||||
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[0].tv_nsec == UTIME_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[1] = now;
|
||||
}
|
||||
|
||||
// apply the new timestamps
|
||||
if (path) {
|
||||
if (dirfd == AT_FDCWD) {
|
||||
return sys_utimes(path, tv);
|
||||
} else {
|
||||
return enosys();
|
||||
}
|
||||
return sys_utimes(path, tv);
|
||||
} else {
|
||||
if (dirfd != AT_FDCWD) {
|
||||
return sys_futimes(dirfd, tv);
|
||||
} else {
|
||||
return einval();
|
||||
}
|
||||
return sys_futimes(dirfd, tv);
|
||||
}
|
||||
}
|
|
@ -16,39 +16,37 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/calls/struct/timespec.internal.h"
|
||||
#include "libc/calls/struct/timeval.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/runtime/zipos.internal.h"
|
||||
#include "libc/sysv/consts/at.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 flags) {
|
||||
int rc, olderr;
|
||||
struct timeval tv[2];
|
||||
if (!IsXnu()) {
|
||||
if (!path && (IsFreebsd() || IsNetbsd() || IsOpenbsd())) {
|
||||
rc = sys_futimens(dirfd, ts);
|
||||
} else {
|
||||
olderr = errno;
|
||||
rc = __sys_utimensat(dirfd, path, ts, flags);
|
||||
// TODO(jart): How does RHEL5 do futimes()?
|
||||
if (rc == -1 && errno == ENOSYS && path) {
|
||||
errno = olderr;
|
||||
if (ts) {
|
||||
tv[0] = timespec_totimeval(ts[0]);
|
||||
tv[1] = timespec_totimeval(ts[1]);
|
||||
rc = sys_utimes(path, tv);
|
||||
} else {
|
||||
rc = sys_utimes(path, NULL);
|
||||
}
|
||||
unassert(!IsWindows() && !IsXnu());
|
||||
if (!path && (IsFreebsd() || IsNetbsd() || IsOpenbsd())) {
|
||||
rc = sys_futimens(dirfd, ts);
|
||||
} else {
|
||||
olderr = errno;
|
||||
rc = __sys_utimensat(dirfd, path, ts, flags);
|
||||
// TODO(jart): How does RHEL5 do futimes()?
|
||||
if (rc == -1 && errno == ENOSYS && path) {
|
||||
errno = olderr;
|
||||
if (ts) {
|
||||
tv[0] = timespec_totimeval(ts[0]);
|
||||
tv[1] = timespec_totimeval(ts[1]);
|
||||
rc = sys_utimes(path, tv);
|
||||
} else {
|
||||
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 │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/asan.internal.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/struct/timespec.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/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"
|
||||
|
||||
/**
|
||||
|
@ -43,9 +36,10 @@
|
|||
* @param dirfd can be `AT_FDCWD` or an open directory
|
||||
* @param path is filename whose timestamps should be modified
|
||||
* @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
|
||||
* @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 EACCES if unveil() is in play and `path` isn't unveiled
|
||||
* @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 EFAULT if `path` or `ts` memory was invalid
|
||||
* @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
|
||||
* @threadsafe
|
||||
*/
|
||||
int utimensat(int dirfd, const char *path, const struct timespec ts[2],
|
||||
int flags) {
|
||||
int rc;
|
||||
|
||||
if (!path) {
|
||||
rc = efault(); // linux kernel abi behavior isn't supported
|
||||
} else {
|
||||
rc = __utimens(dirfd, path, ts, flags);
|
||||
}
|
||||
|
||||
STRACE("utimensat(%s, %#s, {%s, %s}, %#o) → %d% m", DescribeDirfd(dirfd),
|
||||
path, DescribeTimespec(0, ts), DescribeTimespec(0, ts ? ts + 1 : 0),
|
||||
flags, rc);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "libc/calls/struct/timeval.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
* Changes last accessed/modified timestamps on file.
|
||||
|
@ -36,7 +37,9 @@
|
|||
int utimes(const char *path, const struct timeval tv[2]) {
|
||||
int rc;
|
||||
struct timespec ts[2];
|
||||
if (tv) {
|
||||
if (!path) {
|
||||
rc = efault();
|
||||
} else if (tv) {
|
||||
ts[0] = timeval_totimespec(tv[0]);
|
||||
ts[1] = timeval_totimespec(tv[1]);
|
||||
rc = __utimens(AT_FDCWD, path, ts, 0);
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_FMT_STRTOL_H_
|
||||
#define COSMOPOLITAN_LIBC_FMT_STRTOL_H_
|
||||
#include "libc/errno.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
#define CONSUME_SPACES(t, s, c) \
|
||||
if (endptr) *endptr = (t *)(s); \
|
||||
|
@ -10,33 +11,34 @@
|
|||
d = c == '-' ? -1 : 1; \
|
||||
if (c == '-' || c == '+') c = *++s
|
||||
|
||||
#define GET_RADIX(s, c, r) \
|
||||
if (!r) { \
|
||||
if (c == '0') { \
|
||||
t |= 1; \
|
||||
c = *++s; \
|
||||
if (c == 'x' || c == 'X') { \
|
||||
c = *++s; \
|
||||
r = 16; \
|
||||
} else if (c == 'b' || c == 'B') { \
|
||||
c = *++s; \
|
||||
r = 2; \
|
||||
} else { \
|
||||
r = 8; \
|
||||
} \
|
||||
} else { \
|
||||
r = 10; \
|
||||
} \
|
||||
} else if (!(2 <= r && r <= 36)) { \
|
||||
errno = EINVAL; \
|
||||
return 0; \
|
||||
} else if (c == '0') { \
|
||||
t |= 1; \
|
||||
c = *++s; \
|
||||
if ((r == 2 && (c == 'b' || c == 'B')) || \
|
||||
(r == 16 && (c == 'x' || c == 'X'))) { \
|
||||
c = *++s; \
|
||||
} \
|
||||
#define GET_RADIX(s, c, r) \
|
||||
if (!r) { \
|
||||
if (c == '0') { \
|
||||
t |= 1; \
|
||||
c = *++s; \
|
||||
if ((c == 'x' || c == 'X') && isxdigit(s[1])) { \
|
||||
c = *++s; \
|
||||
r = 16; \
|
||||
} else if ((c == 'b' || c == 'B') && (s[1] == '0' || s[1] == '1')) { \
|
||||
c = *++s; \
|
||||
r = 2; \
|
||||
} else { \
|
||||
r = 8; \
|
||||
} \
|
||||
} else { \
|
||||
r = 10; \
|
||||
} \
|
||||
} else if (!(2 <= r && r <= 36)) { \
|
||||
errno = EINVAL; \
|
||||
return 0; \
|
||||
} else if (c == '0') { \
|
||||
t |= 1; \
|
||||
c = *++s; \
|
||||
if ((r == 2 && \
|
||||
((c == 'b' || c == 'B') && (s[1] == '0' || s[1] == '1'))) || \
|
||||
(r == 16 && ((c == 'x' || c == 'X') && isxdigit(s[1])))) { \
|
||||
c = *++s; \
|
||||
} \
|
||||
}
|
||||
|
||||
#endif /* COSMOPOLITAN_LIBC_FMT_STRTOL_H_ */
|
||||
|
|
|
@ -156,7 +156,7 @@ typedef struct {
|
|||
#define memcpyesque libcesque
|
||||
#define strlenesque libcesque nosideeffect paramsnonnull()
|
||||
#define vallocesque \
|
||||
libcesque dontdiscard returnsaligned((65536)) returnspointerwithnoaliases
|
||||
libcesque __wur returnsaligned((65536)) returnspointerwithnoaliases
|
||||
#define reallocesque libcesque returnsaligned((16))
|
||||
#define mallocesque reallocesque returnspointerwithnoaliases
|
||||
#define interruptfn nocallersavedregisters forcealignargpointer
|
||||
|
@ -268,13 +268,13 @@ typedef struct {
|
|||
#endif /* __cplusplus */
|
||||
#endif /* forceinline */
|
||||
|
||||
#ifndef dontdiscard
|
||||
#ifndef __wur
|
||||
#if !defined(__STRICT_ANSI__) && \
|
||||
((__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 304 || \
|
||||
__has_attribute(__warn_unused_result__))
|
||||
#define dontdiscard __attribute__((__warn_unused_result__))
|
||||
#define __wur __attribute__((__warn_unused_result__))
|
||||
#else
|
||||
#define dontdiscard
|
||||
#define __wur
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
|
|
@ -79,15 +79,7 @@
|
|||
#define _PAGESIZE 4096
|
||||
#endif
|
||||
|
||||
#define BUFSIZ 0x1000 /* best stdio default */
|
||||
#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 */
|
||||
#define NSIG 128 /* b/c freebsd */
|
||||
|
||||
#if defined(__LP64__) && !defined(__INT64_TYPE__)
|
||||
#include "libc/integral/lp64.inc"
|
||||
|
|
|
@ -347,7 +347,7 @@ static void __asan_exit(void) {
|
|||
_Exit(99);
|
||||
}
|
||||
|
||||
dontdiscard static __asan_die_f *__asan_die(void) {
|
||||
static __wur __asan_die_f *__asan_die(void) {
|
||||
if (_weaken(__die)) {
|
||||
return _weaken(__die);
|
||||
} else {
|
||||
|
@ -707,8 +707,7 @@ static const char *__asan_describe_access_poison(signed char kind) {
|
|||
}
|
||||
}
|
||||
|
||||
static dontdiscard __asan_die_f *__asan_report_invalid_pointer(
|
||||
const void *addr) {
|
||||
static __wur __asan_die_f *__asan_report_invalid_pointer(const void *addr) {
|
||||
kprintf("\n\e[J\e[1;31masan error\e[0m: this corruption at %p shadow %p\n",
|
||||
addr, SHADOW(addr));
|
||||
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,
|
||||
const char *message,
|
||||
signed char kind) {
|
||||
static __wur __asan_die_f *__asan_report(const void *addr, int size,
|
||||
const char *message,
|
||||
signed char kind) {
|
||||
int i;
|
||||
wint_t c;
|
||||
signed char t;
|
||||
|
@ -940,8 +939,8 @@ void __asan_verify_str(const char *p) {
|
|||
__asan_verify_failed(UNSHADOW(f.shadow), 8, f);
|
||||
}
|
||||
|
||||
static dontdiscard __asan_die_f *__asan_report_memory_fault(
|
||||
void *addr, int size, const char *message) {
|
||||
static __wur __asan_die_f *__asan_report_memory_fault(void *addr, int size,
|
||||
const char *message) {
|
||||
return __asan_report(addr, size, message,
|
||||
__asan_fault(SHADOW(addr), -128).kind);
|
||||
}
|
||||
|
|
|
@ -8,9 +8,9 @@ int _bsrl(long) pureconst;
|
|||
int _bsrll(long long) pureconst;
|
||||
|
||||
#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
|
||||
#define _bsr(x) (__builtin_clz(x) ^ (sizeof(int) * CHAR_BIT - 1))
|
||||
#define _bsrl(x) (__builtin_clzl(x) ^ (sizeof(long) * CHAR_BIT - 1))
|
||||
#define _bsrll(x) (__builtin_clzll(x) ^ (sizeof(long long) * CHAR_BIT - 1))
|
||||
#define _bsr(x) (__builtin_clz(x) ^ (sizeof(int) * 8 - 1))
|
||||
#define _bsrl(x) (__builtin_clzl(x) ^ (sizeof(long) * 8 - 1))
|
||||
#define _bsrll(x) (__builtin_clzll(x) ^ (sizeof(long long) * 8 - 1))
|
||||
#endif
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
|
|
|
@ -139,6 +139,10 @@ void bzero(void *p, size_t n) {
|
|||
#ifdef __x86_64__
|
||||
asm("xorl\t%k0,%k0" : "=r"(x));
|
||||
#else
|
||||
if (1) {
|
||||
memset(p, 0, n);
|
||||
return;
|
||||
}
|
||||
x = 0;
|
||||
#endif
|
||||
if (n <= 16) {
|
||||
|
|
|
@ -31,11 +31,11 @@ __msabi extern typeof(CreateDirectory) *const __imp_CreateDirectoryW;
|
|||
* @note this wrapper takes care of ABI, STRACE(), and __winerr()
|
||||
*/
|
||||
textwindows bool32 CreateDirectory(const char16_t *lpPathName,
|
||||
struct NtSecurityAttributes *lpSecurity) {
|
||||
const struct NtSecurityAttributes *lpSec) {
|
||||
bool32 ok;
|
||||
ok = __imp_CreateDirectoryW(lpPathName, lpSecurity);
|
||||
ok = __imp_CreateDirectoryW(lpPathName, lpSec);
|
||||
if (!ok) __winerr();
|
||||
NTTRACE("CreateDirectory(%#hs, %s) → %hhhd% m", lpPathName,
|
||||
DescribeNtSecurityAttributes(lpSecurity), ok);
|
||||
DescribeNtSecurityAttributes(lpSec), ok);
|
||||
return ok;
|
||||
}
|
||||
|
|
|
@ -32,8 +32,8 @@ __msabi extern typeof(CreateProcess) *const __imp_CreateProcessW;
|
|||
*/
|
||||
textwindows bool32
|
||||
CreateProcess(const char16_t *opt_lpApplicationName, char16_t *lpCommandLine,
|
||||
struct NtSecurityAttributes *opt_lpProcessAttributes,
|
||||
struct NtSecurityAttributes *opt_lpThreadAttributes,
|
||||
const struct NtSecurityAttributes *opt_lpProcessAttributes,
|
||||
const struct NtSecurityAttributes *opt_lpThreadAttributes,
|
||||
bool32 bInheritHandles, uint32_t dwCreationFlags,
|
||||
void *opt_lpEnvironment, const char16_t *opt_lpCurrentDirectory,
|
||||
const struct NtStartupInfo *lpStartupInfo,
|
||||
|
|
|
@ -32,7 +32,7 @@ __msabi extern typeof(CreateThread) *const __imp_CreateThread;
|
|||
* @note this wrapper takes care of ABI, STRACE()
|
||||
*/
|
||||
textwindows int64_t
|
||||
CreateThread(struct NtSecurityAttributes *lpThreadAttributes,
|
||||
CreateThread(const struct NtSecurityAttributes *lpThreadAttributes,
|
||||
size_t dwStackSize, void *lpStartAddress, void *lpParameter,
|
||||
uint32_t dwCreationFlags, uint32_t *opt_lpThreadId) {
|
||||
int64_t hHandle;
|
||||
|
|
|
@ -46,7 +46,6 @@ dontasan int __cxa_atexit(void *fp, void *arg, void *pred) {
|
|||
/* asan runtime depends on this function */
|
||||
unsigned i;
|
||||
struct CxaAtexitBlock *b, *b2;
|
||||
_Static_assert(ATEXIT_MAX == CHAR_BIT * sizeof(b->mask), "");
|
||||
__cxa_lock();
|
||||
b = __cxa_blocks.p;
|
||||
if (!b) b = __cxa_blocks.p = &__cxa_blocks.root;
|
||||
|
|
|
@ -14,7 +14,7 @@ struct CxaAtexitBlocks {
|
|||
void *fp;
|
||||
void *arg;
|
||||
void *pred;
|
||||
} p[ATEXIT_MAX];
|
||||
} p[32];
|
||||
} * p, root;
|
||||
};
|
||||
|
||||
|
|
|
@ -44,6 +44,7 @@ const char *DescribeNtProcAccessFlags(char[256], uint32_t);
|
|||
const char *DescribeNtStartFlags(char[128], uint32_t);
|
||||
const char *DescribeNtSymlinkFlags(char[64], uint32_t);
|
||||
const char *DescribeOpenFlags(char[128], int);
|
||||
const char *DescribeOpenMode(char[15], int, int);
|
||||
const char *DescribePersonalityFlags(char[128], int);
|
||||
const char *DescribePollFlags(char[64], int);
|
||||
const char *DescribePrctlOperation(int);
|
||||
|
@ -97,6 +98,7 @@ const char *DescribeWhichPrio(char[12], int);
|
|||
#define DescribeNtStartFlags(x) DescribeNtStartFlags(alloca(128), x)
|
||||
#define DescribeNtSymlinkFlags(x) DescribeNtSymlinkFlags(alloca(64), 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 DescribePollFlags(p) DescribePollFlags(alloca(64), p)
|
||||
#define DescribeProtFlags(x) DescribeProtFlags(alloca(48), x)
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
#include "libc/intrin/kprintf.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;
|
||||
bool gotsome = false;
|
||||
if (!o) return "NULL";
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
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)
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
|
|
|
@ -21,8 +21,9 @@
|
|||
#include "libc/intrin/describeflags.internal.h"
|
||||
#include "libc/nt/struct/securityattributes.h"
|
||||
|
||||
const char *(DescribeNtSecurityAttributes)(char buf[32],
|
||||
struct NtSecurityAttributes *p) {
|
||||
const char *(
|
||||
DescribeNtSecurityAttributes)(char buf[32],
|
||||
const struct NtSecurityAttributes *p) {
|
||||
if (p == &kNtIsInheritable) return "&kNtIsInheritable";
|
||||
FormatInt64(buf, (uintptr_t)p);
|
||||
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/thread/thread.h"
|
||||
|
||||
#define OPEN_MAX 16
|
||||
|
||||
#ifdef __x86_64__
|
||||
__static_yoink("_init_g_fds");
|
||||
#endif
|
||||
|
|
|
@ -31,7 +31,6 @@
|
|||
char *getenv(const char *s) {
|
||||
char **p;
|
||||
struct Env e;
|
||||
if (!s) return 0;
|
||||
if (!(p = environ)) return 0;
|
||||
e = __getenv(p, s);
|
||||
#if SYSDEBUG
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
#include "libc/nt/struct/securityattributes.h"
|
||||
|
||||
const struct NtSecurityAttributes kNtIsInheritable = {
|
||||
sizeof(struct NtSecurityAttributes),
|
||||
NULL,
|
||||
true,
|
||||
.nLength = sizeof(struct NtSecurityAttributes),
|
||||
.lpSecurityDescriptor = NULL,
|
||||
.bInheritHandle = true,
|
||||
};
|
||||
|
|
|
@ -36,7 +36,8 @@ kOpenFlags:
|
|||
.e O_TRUNC,"TRUNC" //
|
||||
.e O_CLOEXEC,"CLOEXEC" //
|
||||
.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_DIRECT,"DIRECT" // no-op on xnu/openbsd
|
||||
.e O_APPEND,"APPEND" // weird on nt
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
#include "libc/str/str.h"
|
||||
#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,
|
||||
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
|
||||
* @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__)
|
||||
const void *r;
|
||||
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;
|
||||
#else
|
||||
return memchr_pure(s, c, n);
|
||||
return (void *)memchr_pure(s, c, n);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -22,113 +22,34 @@
|
|||
#include "libc/str/str.h"
|
||||
#ifndef __aarch64__
|
||||
|
||||
#define PMOVMSKB(x) __builtin_ia32_pmovmskb128(x)
|
||||
|
||||
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.
|
||||
*
|
||||
* memcmp n=0 992 picoseconds
|
||||
* memcmp n=1 1 ns/byte 738 mb/s
|
||||
* memcmp n=2 661 ps/byte 1,476 mb/s
|
||||
* memcmp n=3 551 ps/byte 1,771 mb/s
|
||||
* memcmp n=4 248 ps/byte 3,936 mb/s
|
||||
* memcmp n=5 198 ps/byte 4,920 mb/s
|
||||
* memcmp n=6 165 ps/byte 5,904 mb/s
|
||||
* memcmp n=7 141 ps/byte 6,889 mb/s
|
||||
* memcmp n=8 124 ps/byte 7,873 mb/s
|
||||
* memcmp n=9 110 ps/byte 8,857 mb/s
|
||||
* memcmp n=15 44 ps/byte 22,143 mb/s
|
||||
* memcmp n=16 41 ps/byte 23,619 mb/s
|
||||
* memcmp n=17 77 ps/byte 12,547 mb/s
|
||||
* memcmp n=31 42 ps/byte 22,881 mb/s
|
||||
* memcmp n=32 41 ps/byte 23,619 mb/s
|
||||
* memcmp n=33 60 ps/byte 16,238 mb/s
|
||||
* memcmp n=80 53 ps/byte 18,169 mb/s
|
||||
* memcmp n=128 38 ps/byte 25,194 mb/s
|
||||
* memcmp n=256 32 ps/byte 30,233 mb/s
|
||||
* memcmp n=16384 27 ps/byte 35,885 mb/s
|
||||
* memcmp n=32768 29 ps/byte 32,851 mb/s
|
||||
* memcmp n=131072 33 ps/byte 28,983 mb/s
|
||||
* memcmp n=0 2 nanoseconds
|
||||
* memcmp n=1 2 ns/byte 357 mb/s
|
||||
* memcmp n=2 1 ns/byte 530 mb/s
|
||||
* memcmp n=3 1 ns/byte 631 mb/s
|
||||
* 𝗺𝗲𝗺𝗰𝗺𝗽 n=4 1 ns/byte 849 mb/s
|
||||
* memcmp n=5 816 ps/byte 1,195 mb/s
|
||||
* memcmp n=6 888 ps/byte 1,098 mb/s
|
||||
* memcmp n=7 829 ps/byte 1,176 mb/s
|
||||
* 𝗺𝗲𝗺𝗰𝗺𝗽 n=8 773 ps/byte 1,261 mb/s
|
||||
* memcmp n=9 629 ps/byte 1,551 mb/s
|
||||
* memcmp n=15 540 ps/byte 1,805 mb/s
|
||||
* 𝗺𝗲𝗺𝗰𝗺𝗽 n=16 211 ps/byte 4,623 mb/s
|
||||
* memcmp n=17 268 ps/byte 3,633 mb/s
|
||||
* memcmp n=31 277 ps/byte 3,524 mb/s
|
||||
* memcmp n=32 153 ps/byte 6,351 mb/s
|
||||
* memcmp n=33 179 ps/byte 5,431 mb/s
|
||||
* memcmp n=79 148 ps/byte 6,576 mb/s
|
||||
* 𝗺𝗲𝗺𝗰𝗺𝗽 n=80 81 ps/byte 11 GB/s
|
||||
* memcmp n=128 76 ps/byte 12 GB/s
|
||||
* memcmp n=256 60 ps/byte 15 GB/s
|
||||
* memcmp n=16384 51 ps/byte 18 GB/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`,
|
||||
* (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 c;
|
||||
unsigned u;
|
||||
uint32_t k, i, j;
|
||||
uint64_t w, x, y;
|
||||
const unsigned char *p, *q;
|
||||
if ((p = a) == (q = b) || !n) return 0;
|
||||
if ((c = *p - *q)) return c;
|
||||
#if defined(__x86_64__) && !defined(__chibicc__)
|
||||
if (!IsTiny()) {
|
||||
if (n <= 16) {
|
||||
if (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)))) {
|
||||
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);
|
||||
unsigned u;
|
||||
while (n >= 16 && (((uintptr_t)p & 0xfff) <= 0x1000 - 16 &&
|
||||
((uintptr_t)q & 0xfff) <= 0x1000 - 16)) {
|
||||
if (!(u = __builtin_ia32_pmovmskb128(*(xmm_t *)p == *(xmm_t *)q) ^
|
||||
0xffff)) {
|
||||
n -= 16;
|
||||
p += 16;
|
||||
q += 16;
|
||||
} else {
|
||||
return memcmp_sse(p, q, n);
|
||||
u = __builtin_ctzl(u);
|
||||
return p[u] - q[u];
|
||||
}
|
||||
}
|
||||
#endif /* __x86_64__ */
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/nexgen32e/x86feature.h"
|
||||
#include "libc/str/str.h"
|
||||
#ifndef __aarch64__
|
||||
|
@ -75,7 +76,7 @@ void *memrchr(const void *s, int c, size_t n) {
|
|||
r = memrchr_sse(s, c, n);
|
||||
return (void *)r;
|
||||
#else
|
||||
return memrchr_pure(s, c, n);
|
||||
return (void *)memrchr_pure(s, c, n);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
#include "libc/macros.internal.h"
|
||||
|
||||
.init.start 200,_init__mmi
|
||||
movb $OPEN_MAX,_mmi+8
|
||||
movb $16,_mmi+8
|
||||
movl $_mmi+24,_mmi+16
|
||||
movb $PTHREAD_MUTEX_RECURSIVE,__mmi_lock_obj+4(%rip)
|
||||
.init.end 200,_init__mmi
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/sysv/consts/limits.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/sysv/consts/limits.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
|
|
|
@ -107,14 +107,14 @@ dontasan char *strchr(const char *s, int c) {
|
|||
unassert(!r || *r || !(c & 255));
|
||||
return (char *)r;
|
||||
#else
|
||||
char *r;
|
||||
const char *r;
|
||||
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;
|
||||
}
|
||||
r = strchr_x64(s, c);
|
||||
unassert(!r || *r || !c);
|
||||
return r;
|
||||
return (char *)r;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -36,7 +36,7 @@
|
|||
* @asyncsignalsafe
|
||||
* @threadsafe
|
||||
*/
|
||||
privileged dontdiscard char *strsignal_r(int sig, char buf[21]) {
|
||||
privileged char *strsignal_r(int sig, char buf[21]) {
|
||||
const char *s;
|
||||
if (!sig) {
|
||||
return "0";
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "libc/intrin/pushpop.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/log/color.internal.h"
|
||||
#include "libc/log/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)) {
|
||||
return _weaken(__die);
|
||||
} else {
|
||||
|
@ -232,8 +233,8 @@ static void __ubsan_warning(const struct UbsanSourceLocation *loc,
|
|||
loc->line, SUBTLE, description, RESET);
|
||||
}
|
||||
|
||||
dontdiscard __ubsan_die_f *__ubsan_abort(const struct UbsanSourceLocation *loc,
|
||||
const char *description) {
|
||||
__wur __ubsan_die_f *__ubsan_abort(const struct UbsanSourceLocation *loc,
|
||||
const char *description) {
|
||||
kprintf("\n%s:%d: %subsan error%s: %s (tid %d)\n", loc->file, loc->line, RED2,
|
||||
RESET, description, gettid());
|
||||
return __ubsan_die();
|
||||
|
|
|
@ -5,6 +5,6 @@
|
|||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/stdio/dprintf.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/stdio/temp.h"
|
||||
#include "libc/temp.h"
|
||||
#include "third_party/musl/tempnam.h"
|
||||
#endif /* _STDIO_H */
|
||||
|
|
|
@ -10,9 +10,9 @@
|
|||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/dprintf.h"
|
||||
#include "libc/stdio/rand.h"
|
||||
#include "libc/stdio/temp.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/exit.h"
|
||||
#include "libc/temp.h"
|
||||
#include "third_party/musl/crypt.h"
|
||||
#include "third_party/musl/rand48.h"
|
||||
#endif /* _STDLIB_H */
|
||||
|
|
|
@ -2,6 +2,11 @@
|
|||
#define COSMOPOLITAN_LIBC_LIMITS_H_
|
||||
#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_MAX 255
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/intrin/safemacros.internal.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/mem/mem.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 (*)(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_int64(int64_t *, size_t);
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
* @return pointer that must be free()'d, or NULL w/ errno
|
||||
* @threadsafe
|
||||
*/
|
||||
dontdiscard char *get_current_dir_name(void) {
|
||||
char *get_current_dir_name(void) {
|
||||
const char *p;
|
||||
if ((p = getenv("PWD")) && _isabspath(p)) {
|
||||
return strdup(p);
|
||||
|
|
|
@ -15,16 +15,16 @@ void free(void *) libcesque;
|
|||
void *malloc(size_t) attributeallocsize((1)) mallocesque;
|
||||
void *calloc(size_t, size_t) attributeallocsize((1, 2)) mallocesque;
|
||||
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_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 *pvalloc(size_t) vallocesque;
|
||||
char *strdup(const char *) paramsnonnull() mallocesque;
|
||||
char *strndup(const char *, size_t) paramsnonnull() mallocesque;
|
||||
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 mallopt(int, int);
|
||||
|
@ -34,7 +34,7 @@ size_t malloc_usable_size(void *);
|
|||
void **independent_calloc(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 {
|
||||
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);
|
||||
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,
|
||||
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,
|
||||
uint32_t dwDesiredAccess);
|
||||
|
||||
|
|
|
@ -71,7 +71,7 @@ bool32 SetCurrentDirectory(const char16_t *lpPathName);
|
|||
uint32_t GetCurrentDirectory(uint32_t nBufferLength, char16_t *out_lpBuffer);
|
||||
|
||||
bool32 CreateDirectory(const char16_t *lpPathName,
|
||||
struct NtSecurityAttributes *lpSecurityAttributes);
|
||||
const struct NtSecurityAttributes *lpSecurityAttributes);
|
||||
bool32 RemoveDirectory(const char16_t *lpPathName);
|
||||
|
||||
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,
|
||||
const char16_t *lpExistingFileName,
|
||||
struct NtSecurityAttributes *reserved)
|
||||
const struct NtSecurityAttributes *reserved)
|
||||
paramsnonnull((1, 2));
|
||||
bool32 CreateSymbolicLink(const char16_t *lpSymlinkFileName,
|
||||
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,
|
||||
int64_t *out_hDuplicateTokenHandle);
|
||||
bool32 DuplicateTokenEx(int64_t hExistingToken, unsigned int dwDesiredAccess,
|
||||
struct NtSecurityAttributes *lpTokenAttributes,
|
||||
const struct NtSecurityAttributes *lpTokenAttributes,
|
||||
int ImpersonationLevel, int TokenType,
|
||||
int64_t *out_phNewToken);
|
||||
|
||||
|
|
|
@ -81,12 +81,12 @@ bool32 OfferVirtualMemory(void *inout_VirtualAddress, size_t Size,
|
|||
int Priority);
|
||||
|
||||
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);
|
||||
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);
|
||||
|
||||
#if ShouldUseMsabiAttribute()
|
||||
|
|
|
@ -36,8 +36,8 @@ COSMOPOLITAN_C_START_
|
|||
|
||||
bool32 CreateProcess(const char16_t *opt_lpApplicationName,
|
||||
char16_t *lpCommandLine,
|
||||
struct NtSecurityAttributes *opt_lpProcessAttributes,
|
||||
struct NtSecurityAttributes *opt_lpThreadAttributes,
|
||||
const struct NtSecurityAttributes *opt_lpProcessAttributes,
|
||||
const struct NtSecurityAttributes *opt_lpThreadAttributes,
|
||||
bool32 bInheritHandles, uint32_t dwCreationFlags,
|
||||
void *opt_lpEnvironment,
|
||||
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 RegCreateKeyEx(int64_t hKey, const char16_t *lpSubKey, uint32_t Reserved,
|
||||
int16_t *lpClass, uint32_t dwOptions, int samDesired,
|
||||
struct NtSecurityAttributes *lpSecurityAttributes,
|
||||
const struct NtSecurityAttributes *lpSecurityAttributes,
|
||||
int64_t *phkResult, uint32_t *lpdwDisposition);
|
||||
int RegDeleteKey(int64_t hKey, const char16_t *lpSubKey);
|
||||
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);
|
||||
int RegRestoreKey(int64_t hKey, const char16_t *lpFile, uint32_t dwFlags);
|
||||
int RegSaveKey(int64_t hKey, const char16_t *lpFile,
|
||||
struct NtSecurityAttributes *lpSecurityAttributes);
|
||||
const struct NtSecurityAttributes *lpSecurityAttributes);
|
||||
int RegSetKeySecurity(int64_t hKey, uint32_t SecurityInformation,
|
||||
void *pSecurityDescriptor);
|
||||
int RegUnLoadKey(int64_t hKey, const char16_t *lpSubKey);
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
COSMOPOLITAN_C_START_
|
||||
|
||||
char16_t *GetCommandLine(void) nosideeffect;
|
||||
char16_t *GetEnvironmentStrings(void) dontdiscard;
|
||||
char16_t *GetEnvironmentStrings(void) __wur;
|
||||
bool32 FreeEnvironmentStrings(char16_t *) paramsnonnull();
|
||||
bool32 ReadFile(int64_t hFile, void *lpBuffer, uint32_t nNumberOfBytesToRead,
|
||||
uint32_t *lpNumberOfBytesRead,
|
||||
|
|
|
@ -11,7 +11,7 @@ struct NtSecurityAttributes {
|
|||
};
|
||||
|
||||
const char *DescribeNtSecurityAttributes(char[32],
|
||||
struct NtSecurityAttributes *);
|
||||
const struct NtSecurityAttributes *);
|
||||
#define DescribeNtSecurityAttributes(x) \
|
||||
DescribeNtSecurityAttributes(alloca(32), x)
|
||||
|
||||
|
|
|
@ -75,15 +75,16 @@ bool32 RegisterWaitForSingleObject(int64_t *phNewWaitObject, int64_t hObject,
|
|||
void *Context, uint32_t dwMilliseconds,
|
||||
uint32_t dwFlags);
|
||||
|
||||
int64_t CreateWaitableTimer(struct NtSecurityAttributes *lpTimerAttributes,
|
||||
bool32 bManualReset, const char16_t *lpTimerName);
|
||||
int64_t CreateWaitableTimer(
|
||||
const struct NtSecurityAttributes *lpTimerAttributes, bool32 bManualReset,
|
||||
const char16_t *lpTimerName);
|
||||
bool32 SetWaitableTimer(int64_t hTimer, const int64_t *lpDueTimeAsFtOrNegRela,
|
||||
int32_t opt_lPeriodMs, NtTimerapcroutine opt_callback,
|
||||
void *lpArgToCallback, bool32 fUnsleepSystem);
|
||||
|
||||
int64_t CreateSemaphore(struct NtSecurityAttributes *opt_lpSemaphoreAttributes,
|
||||
uint32_t lInitialCount, uint32_t lMaximumCount,
|
||||
const char16_t *opt_lpName);
|
||||
int64_t CreateSemaphore(
|
||||
const struct NtSecurityAttributes *opt_lpSemaphoreAttributes,
|
||||
uint32_t lInitialCount, uint32_t lMaximumCount, const char16_t *opt_lpName);
|
||||
|
||||
int32_t ReleaseMutex(int64_t hMutex);
|
||||
int32_t ReleaseSemaphore(int64_t hSemaphore, int32_t lReleaseCount,
|
||||
|
|
|
@ -30,7 +30,7 @@ COSMOPOLITAN_C_START_
|
|||
│ cosmopolitan § new technology » threads ─╬─│┼
|
||||
╚────────────────────────────────────────────────────────────────────────────│*/
|
||||
|
||||
int64_t CreateThread(struct NtSecurityAttributes *lpThreadAttributes,
|
||||
int64_t CreateThread(const struct NtSecurityAttributes *lpThreadAttributes,
|
||||
size_t dwStackSize, void *lpStartAddress,
|
||||
void *lpParameter, uint32_t dwCreationFlags,
|
||||
uint32_t *opt_lpThreadId);
|
||||
|
|
|
@ -291,7 +291,7 @@ struct NtInterfaceInfo {
|
|||
*/
|
||||
|
||||
int32_t WSAStartup(uint16_t wVersionRequested, struct NtWsaData *lpWSAData)
|
||||
paramsnonnull() dontdiscard;
|
||||
paramsnonnull() __wur;
|
||||
|
||||
int WSACleanup(void);
|
||||
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,
|
||||
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,
|
||||
const struct NtIovec *opt_lpCallerData,
|
||||
|
@ -340,8 +340,7 @@ bool32 WSAConnectByList(uint64_t s,
|
|||
int64_t WSAAccept(uint64_t s, struct sockaddr *out_addr,
|
||||
int32_t *opt_inout_addrlen,
|
||||
const NtConditionProc opt_lpfnCondition,
|
||||
const uint32_t *opt_dwCallbackData)
|
||||
paramsnonnull((2)) dontdiscard;
|
||||
const uint32_t *opt_dwCallbackData) paramsnonnull((2)) __wur;
|
||||
|
||||
bool32 AcceptEx(int64_t sListenSocket, int64_t sAcceptSocket,
|
||||
void *out_lpOutputBuffer /*[recvlen+local+remoteaddrlen]*/,
|
||||
|
@ -409,7 +408,7 @@ int WSANSPIoctl(int64_t hLookup, uint32_t dwControlCode,
|
|||
const struct NtWsaCompletion *opt_lpCompletion)
|
||||
paramsnonnull((3, 5, 7));
|
||||
|
||||
int64_t WSACreateEvent(void) dontdiscard;
|
||||
int64_t WSACreateEvent(void) __wur;
|
||||
bool32 WSACloseEvent(const int64_t hEvent);
|
||||
bool32 WSAResetEvent(const int64_t hEvent);
|
||||
bool32 WSASetEvent(const int64_t hEvent);
|
||||
|
|
|
@ -28,10 +28,10 @@
|
|||
#include "libc/intrin/bits.h"
|
||||
#include "libc/intrin/getenv.internal.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/stdio/temp.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/lock.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
|
@ -39,6 +39,7 @@
|
|||
#include "libc/sysv/consts/s.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/sysv/consts/timer.h"
|
||||
#include "libc/temp.h"
|
||||
#include "third_party/awk/cmd.h"
|
||||
#include "third_party/getopt/getopt.internal.h"
|
||||
#include "third_party/musl/glob.h"
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue