diff --git a/libc/include/stdlib.h b/libc/include/stdlib.h index df6cf274..02fde3b7 100644 --- a/libc/include/stdlib.h +++ b/libc/include/stdlib.h @@ -131,6 +131,12 @@ extern "C" /* Convert a wide character string to a multibyte character string. */ size_t wcstombs(char* buf, const wchar_t* src, size_t max); + /* Create a unique directory from a template string whose last 6 bytes must be XXXXXX. */ + char* mkdtemp(char* _template); + + /* Create a unique file from a template string whose last 6 bytes must be XXXXXX. */ + int mkstemp(char* _template); + #ifdef __cplusplus } #endif diff --git a/libc/src/stdlib.cpp b/libc/src/stdlib.cpp index 4271aeeb..290f66da 100644 --- a/libc/src/stdlib.cpp +++ b/libc/src/stdlib.cpp @@ -1,10 +1,13 @@ #include +#include #include #include #include #include #include #include +#include +#include #include #include #include @@ -218,4 +221,66 @@ extern "C" { next = seed; } + + static void generate_random_character(char* ptr) + { + constexpr const char chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_"; + *ptr = chars[rand() % sizeof(chars)]; + } + + static int check_template(char* _template, size_t* len) + { + *len = strlen(_template); + if (*len < 6) + { + errno = EINVAL; + return -1; + } + + if (strncmp(_template + (*len - 6), "XXXXXX", 6)) + { + errno = EINVAL; + return -1; + } + + return 0; + } + + static void generate_random_name(char* _template, const size_t* len) + { + size_t index = *len - 6; + while (index < *len) generate_random_character(&_template[index++]); + } + + char* mkdtemp(char* _template) + { + size_t len; + if (check_template(_template, &len) < 0) return nullptr; + + while (true) + { + generate_random_name(_template, &len); + + if (mkdir(_template, 0700) == 0) return _template; + + if (errno != EEXIST) return nullptr; + } + } + + int mkstemp(char* _template) + { + size_t len; + if (check_template(_template, &len) < 0) return -1; + + while (true) + { + generate_random_name(_template, &len); + + int fd; + + if ((fd = open(_template, O_RDWR | O_CREAT | O_EXCL, 0600)) >= 0) return fd; + + if (errno != EEXIST) return -1; + } + } }