Make improvements

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

View file

@ -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 2020 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,8 +16,9 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/stdio/temp.h"
#include "libc/stdio/internal.h"
#include "libc/stdio/stdio_ext.h"
int mkstemps(char *template, int suffixlen) {
return mkostempsm(template, suffixlen, 0, 0600);
size_t __freadahead(FILE *f) {
return f->beg <= f->end ? f->end - f->beg : 0;
}

View file

@ -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 2020 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,11 +16,11 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/stdio/temp.h"
#include "libc/stdio/internal.h"
#include "libc/stdio/stdio_ext.h"
/**
* Delegates to mkotempsm() w/ owner-only non-execute access.
*/
dontdiscard int mkostemps(char *template, int suffixlen, unsigned flags) {
return mkostempsm(template, suffixlen, flags, 0600);
const char *__freadptr(FILE *f, size_t *sizep) {
if (f->beg == f->end) return 0;
*sizep = f->end - f->beg;
return (const char *)f->buf + f->beg;
}

View file

@ -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 2020 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,8 +16,9 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/stdio/temp.h"
#include "libc/stdio/internal.h"
#include "libc/stdio/stdio_ext.h"
int mkostemp(char *template, unsigned flags) {
return mkostempsm(template, 0, flags, 0600);
void __freadptrinc(FILE *f, size_t inc) {
f->beg += inc;
}

View file

@ -21,6 +21,7 @@
#include "libc/calls/internal.h"
#include "libc/calls/struct/dirent.h"
#include "libc/calls/struct/stat.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/calls/syscall_support-nt.internal.h"
#include "libc/dce.h"
#include "libc/errno.h"
@ -42,6 +43,7 @@
#include "libc/runtime/zipos.internal.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/dt.h"
#include "libc/sysv/consts/f.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/s.h"
#include "libc/sysv/errfuns.h"
@ -262,6 +264,20 @@ GiveUpOnGettingInode:
*/
DIR *fdopendir(int fd) {
// sanity check file descriptor
struct stat st;
if (fstat(fd, &st) == -1) {
return 0;
}
if (!S_ISDIR(st.st_mode)) {
enotdir();
return 0;
}
if (IsLinux() && (__sys_fcntl(fd, F_GETFL) & O_PATH)) {
ebadf();
return 0;
}
// allocate directory iterator object
DIR *dir;
if (!(dir = calloc(1, sizeof(*dir)))) {

View file

@ -34,14 +34,23 @@ int __fflush_impl(FILE *f) {
}
f->getln = 0;
}
if (f->beg && !f->end && (f->iomode & O_ACCMODE) != O_RDONLY) {
for (i = 0; i < f->beg; i += rc) {
if ((rc = write(f->fd, f->buf + i, f->beg - i)) == -1) {
if (f->fd != -1) {
if (f->beg && !f->end && (f->iomode & O_ACCMODE) != O_RDONLY) {
for (i = 0; i < f->beg; i += rc) {
if ((rc = write(f->fd, f->buf + i, f->beg - i)) == -1) {
f->state = errno;
return -1;
}
}
f->beg = 0;
}
if (f->beg < f->end && (f->iomode & O_ACCMODE) != O_WRONLY) {
if (lseek(f->fd, -(int)(f->end - f->beg), SEEK_CUR) == -1) {
f->state = errno;
return -1;
}
f->end = f->beg;
}
f->beg = 0;
}
return 0;
}

View file

@ -53,7 +53,7 @@ size_t fwrite_unlocked(const void *data, size_t stride, size_t count, FILE *f) {
}
m = f->size - f->beg;
if (n <= m && f->bufmode != _IONBF) {
// this isn't a fully buffered stream, and
// this isn't an unbuffered stream, and
// there's enough room in the buffer for the request
memcpy(f->buf + f->beg, data, n);
f->beg += n;

View file

@ -10,7 +10,7 @@ COSMOPOLITAN_C_START_
struct FILE {
uint8_t bufmode; /* 0x00 _IOFBF, etc. (ignored if fd=-1) */
bool noclose; /* 0x01 for fake dup() todo delete! */
char noclose; /* 0x01 for fake dup() todo delete! */
uint32_t iomode; /* 0x04 O_RDONLY, etc. (ignored if fd=-1) */
int32_t state; /* 0x08 0=OK, -1=EOF, >0=errno */
int fd; /* 0x0c ≥0=fd, -1=closed|buffer */

View file

@ -1,85 +0,0 @@
/*-*- 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/assert.h"
#include "libc/calls/calls.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/intrin/strace.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/lcg.internal.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"
#define RESEED 1024
#define ATTEMPTS 10
#define WILDCARD "XXXXXX"
int mkostempsmi(char *tpl, int slen, unsigned flags, uint64_t *rando, int mode,
int openit(const char *file, int flags, ...)) {
size_t len = strlen(tpl);
size_t wildlen = strlen(WILDCARD);
if (len < wildlen || slen > len - wildlen) return einval();
char *ss = tpl + len - wildlen - slen;
npassert(memcmp(ss, WILDCARD, wildlen) == 0);
flags = (flags & ~(flags & O_ACCMODE)) | O_RDWR | O_CREAT | O_EXCL;
unsigned attempts = ATTEMPTS;
do {
char *p = ss;
uint32_t num = KnuthLinearCongruentialGenerator(rando) >> 32;
for (unsigned i = 0; i < wildlen; ++i) {
p[i] = "0123456789abcdefghijklmnopqrstuvwxyz"[num & 31];
num >>= 5;
}
int fd;
if ((fd = openit(tpl, flags, 0600)) != -1) return fd;
} while (--attempts && errno == EEXIST);
memcpy(ss, WILDCARD, wildlen);
return -1;
}
static uint64_t g_mkostemps_rand;
static uint64_t g_mkostemps_reseed;
/**
* Opens unique temporary file.
*
* The substring XXXXXX is replaced with a pseudorandom number that's
* seeded automatically and grants 30 bits of randomness to each value.
* Retries are made in the unlikely event of collisions.
*
* @param template is a pathname relative to current directory by default,
* that needs to have "XXXXXX" at the end of the string
* @param suffixlen may be nonzero to permit characters after the XXXXXX
* @param flags can have O_APPEND, O_CLOEXEC, etc.
* @param mode is conventionally 0600, for owner-only non-exec access
* @return exclusive open file descriptor for generated pathname,
* or -1 w/ errno
* @see kTmpPath
*/
int mkostempsm(char *template, int suffixlen, unsigned flags, int mode) {
int fd;
if (g_mkostemps_reseed++ % RESEED == 0) g_mkostemps_rand = _rand64();
fd = mkostempsmi(template, suffixlen, flags, &g_mkostemps_rand, mode, open);
STRACE("mkostempsm([%#s], %'d, %#x, %#o) → %d% m", template, suffixlen, flags,
mode, fd);
return fd;
}

View file

@ -17,12 +17,13 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/errno.h"
#include "libc/fmt/fmt.h"
#include "libc/intrin/safemacros.internal.h"
#include "libc/limits.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/o.h"
#include "libc/errno.h"
#include "libc/x/x.h"
/**

View file

@ -18,6 +18,7 @@
*/
#include "libc/calls/calls.h"
#include "libc/errno.h"
#include "libc/limits.h"
#include "libc/stdio/posix_spawn.h"
/**

View file

@ -1,10 +1,19 @@
#ifndef COSMOPOLITAN_LIBC_STDIO_H_
#define COSMOPOLITAN_LIBC_STDIO_H_
#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 L_tmpnam 20
#define L_ctermid 20
#define FILENAME_MAX PATH_MAX
#define P_tmpdir "/tmp"
#define FILENAME_MAX 1024
#define FOPEN_MAX 1000
#define TMP_MAX 10000
#define BUFSIZ 4096
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
@ -51,9 +60,9 @@ int putchar(int);
int puts(const char *);
ssize_t getline(char **, size_t *, FILE *) paramsnonnull();
ssize_t getdelim(char **, size_t *, int, FILE *) paramsnonnull();
FILE *fopen(const char *, const char *) paramsnonnull((2)) dontdiscard;
FILE *fdopen(int, const char *) paramsnonnull() dontdiscard;
FILE *fmemopen(void *, size_t, const char *) paramsnonnull((3)) dontdiscard;
FILE *fopen(const char *, const char *) paramsnonnull((2)) __wur;
FILE *fdopen(int, const char *) paramsnonnull() __wur;
FILE *fmemopen(void *, size_t, const char *) paramsnonnull((3)) __wur;
FILE *freopen(const char *, const char *, FILE *) paramsnonnull((2, 3));
size_t fread(void *, size_t, size_t, FILE *) paramsnonnull((4));
size_t fwrite(const void *, size_t, size_t, FILE *) paramsnonnull((4));
@ -77,6 +86,9 @@ char *gets(char *) paramsnonnull();
int fgetpos(FILE *, fpos_t *) paramsnonnull();
int fsetpos(FILE *, const fpos_t *) paramsnonnull();
FILE *tmpfile(void) __wur;
char *tmpnam(char *) __wur;
char *tmpnam_r(char *) __wur;
int system(const char *);
FILE *popen(const char *, const char *);

View file

@ -20,6 +20,9 @@ int __fsetlocking(FILE *, int);
void _flushlbf(void);
void __fpurge(FILE *);
void __fseterr(FILE *);
const char *__freadptr(FILE *, size_t *);
size_t __freadahead(FILE *);
void __freadptrinc(FILE *, size_t);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View file

@ -22,6 +22,7 @@
#include "libc/calls/struct/sigaction.h"
#include "libc/calls/struct/sigset.h"
#include "libc/errno.h"
#include "libc/limits.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/sysv/consts/sig.h"

View file

@ -1,22 +0,0 @@
#ifndef COSMOPOLITAN_LIBC_STDIO_TEMP_H_
#define COSMOPOLITAN_LIBC_STDIO_TEMP_H_
#include "libc/stdio/stdio.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
FILE *tmpfile(void);
char *mkdtemp(char *);
char *mktemp(char *);
char *tmpnam(char *);
int mkostemp(char *, unsigned);
int mkostemps(char *, int, unsigned);
int mkostempsm(char *, int, unsigned, int);
int mkstemp(char *);
int mkstemps(char *, int);
int mkostempsmi(char *, int, unsigned, uint64_t *, int,
int (*)(const char *, int, ...)) dontdiscard;
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_STDIO_TEMP_H_ */

View file

@ -18,7 +18,7 @@
*/
#include "libc/calls/calls.h"
#include "libc/stdio/stdio.h"
#include "libc/stdio/temp.h"
#include "libc/temp.h"
/**
* Opens stream backed by anonymous file, e.g.

View file

@ -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
@ -17,48 +17,36 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/errno.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/stdio/rand.h"
#include "libc/stdio/temp.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/errfuns.h"
static char g_tmpnam[L_tmpnam];
/**
* Creates temporary directory, e.g.
* Generates temporary file name.
*
* char path[PATH_MAX];
* snprintf(path, sizeof(path), "%s%s.XXXXXX",
* kTmpPath, program_invocation_short_name);
* printf("%s\n", mkdtemp(path));
* rmdir(path);
*
* @param template must end with XXXXXX which is replaced with
* nondeterministic base36 random data
* @return pointer to template on success, or NULL w/ errno
* @raise EINVAL if template didn't end with XXXXXX
* @param buf may be null to generate `/tmp/tmpnam_XXXXXX` to a static
* buffer (it works on Windows) that is not thread safe; otherwise
* the caller must supply a buffer with `L_tmpnam` bytes available
* @return unique generated filename, or null on failure; `buf` memory
* is only mutated on success
*/
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;
}
char *tmpnam(char *buf) {
if (IsAsan()) __asan_verify(buf, L_tmpnam);
char path[] = P_tmpdir "/tmpnam_XXXXXX";
for (int t = 0; t < 100; ++t) {
int w = _rand64();
for (int i = 0; i < 6; ++i) {
path[sizeof(path) - 1 - 6 + i] =
"0123456789abcdefghikmnpqrstvwxyz"[w & 31];
w >>= 5;
}
for (j = 0; j < 6; ++j) {
template[n - 6 + j] = 'X';
if (!fileexists(path)) {
return strcpy(buf ? buf : g_tmpnam, path);
}
} else {
einval();
}
return 0;
}

39
libc/stdio/tmpnam_r.c Normal file
View file

@ -0,0 +1,39 @@
/*-*- 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/stdio/stdio.h"
#include "libc/sysv/errfuns.h"
/**
* Generates temporary file name, reentrantly.
*
* This function is the same as tmpnam() except `buf` can't be NULL.
*
* @param buf must have `L_tmpnam` bytes available
* @return pointer to `buf` which is populated with a unique generated
* filename, or null w/ errno on failure; buffer content will only
* be mutated on success
*/
char *tmpnam_r(char *buf) {
if (buf) {
return tmpnam(buf);
} else {
einval();
return 0;
}
}

View file

@ -19,6 +19,7 @@
#include "libc/fmt/conv.h"
#include "libc/fmt/fmt.h"
#include "libc/intrin/weaken.h"
#include "libc/limits.h"
#include "libc/mem/mem.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"