diff options
Diffstat (limited to 'libc/bionic/tmpfile.cpp')
| -rw-r--r-- | libc/bionic/tmpfile.cpp | 109 |
1 files changed, 78 insertions, 31 deletions
diff --git a/libc/bionic/tmpfile.cpp b/libc/bionic/tmpfile.cpp index 4378e84ab..3d04610a4 100644 --- a/libc/bionic/tmpfile.cpp +++ b/libc/bionic/tmpfile.cpp @@ -31,56 +31,58 @@ */ #include <errno.h> +#include <fcntl.h> #include <signal.h> #include <stdio.h> #include <stdlib.h> +#include <string.h> #include <sys/stat.h> #include <sys/types.h> #include <unistd.h> #include "private/ErrnoRestorer.h" -#include "private/ScopedSignalBlocker.h" -static FILE* __tmpfile_dir(const char* tmp_dir) { +static FILE* __fd_to_fp(int fd) { + FILE* fp = fdopen(fd, "w+"); + if (fp != nullptr) return fp; + + ErrnoRestorer errno_restorer; + close(fd); + return nullptr; +} + +static FILE* __tmpfile_dir_legacy(const char* tmp_dir) { char* path = nullptr; if (asprintf(&path, "%s/tmp.XXXXXXXXXX", tmp_dir) == -1) { return nullptr; } - int fd; - { - ScopedSignalBlocker ssb; - fd = mkstemp(path); - if (fd == -1) { - free(path); - return nullptr; - } - - // Unlink the file now so that it's removed when closed. - unlink(path); + int fd = mkstemp(path); + if (fd == -1) { free(path); - - // Can we still use the file now it's unlinked? - // File systems without hard link support won't have the usual Unix semantics. - struct stat sb; - int rc = fstat(fd, &sb); - if (rc == -1) { - ErrnoRestorer errno_restorer; - close(fd); - return nullptr; - } + return nullptr; } - // Turn the file descriptor into a FILE*. - FILE* fp = fdopen(fd, "w+"); - if (fp != nullptr) { - return fp; + // Unlink the file now so that it's removed when closed. + unlink(path); + free(path); + + // Can we still use the file now it's unlinked? + // File systems without hard link support won't have the usual Unix semantics. + struct stat sb; + if (fstat(fd, &sb) == -1) { + ErrnoRestorer errno_restorer; + close(fd); + return nullptr; } - // Failure. Clean up. We already unlinked, so we just need to close. - ErrnoRestorer errno_restorer; - close(fd); - return nullptr; + return __fd_to_fp(fd); +} + +static FILE* __tmpfile_dir(const char* tmp_dir) { + int fd = open(tmp_dir, O_TMPFILE | O_RDWR, S_IRUSR | S_IWUSR); + if (fd == -1) return __tmpfile_dir_legacy(tmp_dir); + return __fd_to_fp(fd); } FILE* tmpfile() { @@ -98,3 +100,48 @@ FILE* tmpfile() { return fp; } __strong_alias(tmpfile64, tmpfile); + +char* tempnam(const char* dir, const char* prefix) { + // This function is a terrible idea, marked deprecated in our headers, + // and marked obsolescent by POSIX.1-2008, but we make some effort anyway + // since we can't easily remove it... + + // $TMPDIR overrides any directory passed in. + char* tmpdir = getenv("TMPDIR"); + if (tmpdir != nullptr) dir = tmpdir; + + // If we still have no directory, we'll give you a default. + // It's useless for apps, but good enough for the shell. + if (dir == nullptr) dir = "/data/local/tmp"; + + // Default prefix? + if (prefix == nullptr) prefix = "tempnam."; + + // Make up a mktemp(3) template and defer to it for the real work. + char* path = nullptr; + if (asprintf(&path, "%s/%sXXXXXXXXXX", dir, prefix) == -1) return nullptr; + if (mktemp(path) == nullptr) { + free(path); + return nullptr; + } + return path; +} + +char* tmpnam(char* s) { + // This function is a terrible idea, marked deprecated in our headers, + // and marked obsolescent by POSIX-1.2008, but we make some effort anyway + // since we can't easily remove it... + + // Default buffer? + static char buf[L_tmpnam]; + if (s == nullptr) s = buf; + + // Use $TMPDIR if set, or fall back to /data/local/tmp otherwise. + // Useless for apps, but good enough for the shell. + const char* dir = getenv("TMPDIR"); + if (dir == nullptr) dir = "/data/local/tmp"; + + // Make up a mktemp(3) template and defer to it for the real work. + snprintf(s, L_tmpnam, "%s/tmpnam.XXXXXXXXXX", dir); + return mktemp(s); +} |
