diff --git a/Userland/Libraries/LibC/stdio.cpp b/Userland/Libraries/LibC/stdio.cpp index 1338b82f4e..6411df4d79 100644 --- a/Userland/Libraries/LibC/stdio.cpp +++ b/Userland/Libraries/LibC/stdio.cpp @@ -1205,16 +1205,11 @@ void funlockfile([[maybe_unused]] FILE* filehandle) FILE* tmpfile() { char tmp_path[] = "/tmp/XXXXXX"; - if (__generate_unique_filename(tmp_path) < 0) - return nullptr; - - int fd = open(tmp_path, O_CREAT | O_EXCL | O_RDWR, S_IWUSR | S_IRUSR); + int fd = mkstemp(tmp_path); if (fd < 0) return nullptr; - // FIXME: instead of using this hack, implement with O_TMPFILE or similar unlink(tmp_path); - return fdopen(fd, "rw"); } } diff --git a/Userland/Libraries/LibC/stdlib.cpp b/Userland/Libraries/LibC/stdlib.cpp index 47dd242bb0..8d2f0911b0 100644 --- a/Userland/Libraries/LibC/stdlib.cpp +++ b/Userland/Libraries/LibC/stdlib.cpp @@ -171,14 +171,13 @@ static bool is_either(char* str, int offset, char lower, char upper) return ch == lower || ch == upper; } -__attribute__((warn_unused_result)) int __generate_unique_filename(char* pattern) +template +inline int generate_unique_filename(char* pattern, Callback callback) { size_t length = strlen(pattern); - if (length < 6 || memcmp(pattern + length - 6, "XXXXXX", 6)) { - errno = EINVAL; - return -1; - } + if (length < 6 || memcmp(pattern + length - 6, "XXXXXX", 6)) + return EINVAL; size_t start = length - 6; @@ -187,13 +186,11 @@ __attribute__((warn_unused_result)) int __generate_unique_filename(char* pattern for (int attempt = 0; attempt < 100; ++attempt) { for (int i = 0; i < 6; ++i) pattern[start + i] = random_characters[(arc4random() % (sizeof(random_characters) - 1))]; - struct stat st; - int rc = lstat(pattern, &st); - if (rc < 0 && errno == ENOENT) + if (callback() == IterationDecision::Break) return 0; } - errno = EEXIST; - return -1; + + return EEXIST; } extern "C" { @@ -727,31 +724,47 @@ int system(const char* command) char* mktemp(char* pattern) { - if (__generate_unique_filename(pattern) < 0) + auto error = generate_unique_filename(pattern, [&] { + struct stat st; + int rc = lstat(pattern, &st); + if (rc < 0 && errno == ENOENT) + return IterationDecision::Break; + return IterationDecision::Continue; + }); + if (error) { pattern[0] = '\0'; - + errno = error; + } return pattern; } int mkstemp(char* pattern) { - char* path = mktemp(pattern); - - int fd = open(path, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR); // I'm using the flags I saw glibc using. - if (fd >= 0) - return fd; - - return -1; + int fd = -1; + auto error = generate_unique_filename(pattern, [&] { + fd = open(pattern, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR); // I'm using the flags I saw glibc using. + if (fd >= 0) + return IterationDecision::Break; + return IterationDecision::Continue; + }); + if (error) { + errno = error; + return -1; + } + return fd; } char* mkdtemp(char* pattern) { - if (__generate_unique_filename(pattern) < 0) + auto error = generate_unique_filename(pattern, [&] { + if (mkdir(pattern, 0700) == 0) + return IterationDecision::Break; + return IterationDecision::Continue; + }); + if (error) { + errno = error; return nullptr; - - if (mkdir(pattern, 0700) < 0) - return nullptr; - + } return pattern; }