From 13ff49f8a0a4b0fe40b0aff06971dd8abeb43eaa Mon Sep 17 00:00:00 2001 From: Andrew Brown Date: Thu, 21 Nov 2024 15:38:08 -0800 Subject: [PATCH] test: add `tmpfile.c` Though `wasi-libc` may not want to expose `tmpfile` and other related, Unix-specific, "create a /tmp thing" functions, these functions are quite useful during testing. By pulling in slightly-altered versions of these functions, this change also enables two new tests, `fdopen.c` and `ungetc.c`. --- test/Makefile | 6 ++ test/common/tmpfile.c | 86 ++++++++++++++++++++++++++ test/common/tmpfile.h | 7 +++ test/src/libc-test/functional/fdopen.c | 3 + test/src/libc-test/functional/ungetc.c | 3 + 5 files changed, 105 insertions(+) create mode 100644 test/common/tmpfile.c create mode 100644 test/common/tmpfile.h create mode 100644 test/src/libc-test/functional/fdopen.c create mode 100644 test/src/libc-test/functional/ungetc.c diff --git a/test/Makefile b/test/Makefile index 43046fdc..644af298 100644 --- a/test/Makefile +++ b/test/Makefile @@ -98,6 +98,12 @@ INFRA_WASM_OBJS := $(patsubst $(LIBC_TEST)/src/common/%.c,$(OBJDIR)/common/%.was $(OBJDIR)/common/%.wasm.o: $(LIBC_TEST)/src/common/%.c | $(INFRA_OBJDIR) $(CC) $(CFLAGS) -c $< -o $@ +# In some cases, we need extra test infrastructure to provide some unimplemented +# functions (see the `common` directory). +INFRA_WASM_OBJS += $(OBJDIR)/common/tmpfile.wasm.o +$(OBJDIR)/common/tmpfile.wasm.o: common/tmpfile.c | $(INFRA_OBJDIR) + $(CC) $(CFLAGS) -c $< -o $@ + # Also, include the `libc-test` infrastructure headers. INFRA_HEADERS_DIR := $(LIBC_TEST)/src/common INFRA_HEADERS := $(shell find $(INFRA_HEADERS_DIR) -name '*.h') diff --git a/test/common/tmpfile.c b/test/common/tmpfile.c new file mode 100644 index 00000000..79d6dffc --- /dev/null +++ b/test/common/tmpfile.c @@ -0,0 +1,86 @@ +/* + * For tests that need to create temporary files, it is quite convenient to + * implement the following functions. Note that these are to be used as testing + * infrastructure (i.e., creating files to test against), not for testing the + * implementation of these functions themselves which may be altered slightly. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Copied from `libc-top-half/musl/src/temp/__randname.c`. This assumes that a + check for the template size has already been made + */ +char *__randname(char *template) +{ + int i; + struct timespec ts; + unsigned long r; + + clock_gettime(CLOCK_REALTIME, &ts); + r = ts.tv_nsec*65537 ^ (uintptr_t)&ts / 16 + (uintptr_t)template; + for (i=0; i<6; i++, r>>=5) + template[i] = 'A'+(r&15)+(r&16)*2; + + return template; +} + +/* + * Adapted from `libc-top-half/musl/src/stdio/tmpfile.c`; this implementation + * does not retry opening the file. + */ +#define MAXTRIES 1 +FILE *tmpfile(void) +{ + char s[] = "/tmp/tmpfile_XXXXXX"; + int fd; + FILE *f; + int try; + for (try=0; try= 0) { + unlink(s); + f = fdopen(fd, "w+"); + if (!f) close(fd); + return f; + } + } + return 0; +} + +/* + * Adapted from `libc-top-half/musl/src/stdio/mkostemps.c` and + * `libc-top-half/musl/src/temp/mkstemp.c`; this implementation does not + * actually retry creating the file. + */ +int __mkostemps(char *template, int len, int flags) +{ + size_t l = strlen(template); + if (l<6 || len>l-6 || memcmp(template+l-len-6, "XXXXXX", 6)) { + errno = EINVAL; + return -1; + } + + flags -= flags & O_ACCMODE; + int fd, retries = 1; + do { + __randname(template+l-len-6); + if ((fd = open(template, flags | O_RDWR | O_CREAT | O_EXCL, 0600))>=0) + return fd; + } while (--retries && errno == EEXIST); + + memcpy(template+l-len-6, "XXXXXX", 6); + return -1; +} +int mkstemp(char *template) +{ + return __mkostemps(template, 0, 0); +} diff --git a/test/common/tmpfile.h b/test/common/tmpfile.h new file mode 100644 index 00000000..cae653df --- /dev/null +++ b/test/common/tmpfile.h @@ -0,0 +1,7 @@ +/* + * For tests that need to create temporary files, it is quite convenient to + * implement the following functions; see `tmpfile.c` for details. + */ +#include +FILE *tmpfile(void); +int mkstemp(char *); diff --git a/test/src/libc-test/functional/fdopen.c b/test/src/libc-test/functional/fdopen.c new file mode 100644 index 00000000..594eb4d0 --- /dev/null +++ b/test/src/libc-test/functional/fdopen.c @@ -0,0 +1,3 @@ +// add-flags.py(CFLAGS): -I. -include common/tmpfile.h +// add-flags.py(RUN): --dir fs::/tmp +#include "build/download/libc-test/src/functional/fdopen.c" diff --git a/test/src/libc-test/functional/ungetc.c b/test/src/libc-test/functional/ungetc.c new file mode 100644 index 00000000..44071a7c --- /dev/null +++ b/test/src/libc-test/functional/ungetc.c @@ -0,0 +1,3 @@ +// add-flags.py(CFLAGS): -I. -include common/tmpfile.h +// add-flags.py(RUN): --dir fs::/tmp +#include "build/download/libc-test/src/functional/ungetc.c"