libc: Add mkdtemp() and mkstemp()
All checks were successful
continuous-integration/drone/push Build is passing

No mktemp() though, as it has race conditions and was removed in POSIX.1-2008.
This commit is contained in:
apio 2023-05-03 16:43:30 +02:00
parent a0b45a51de
commit 1215c38d75
Signed by: apio
GPG Key ID: B8A7D06E42258954
2 changed files with 71 additions and 0 deletions

View File

@ -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

View File

@ -1,10 +1,13 @@
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <luna/Heap.h>
#include <luna/NumberParsing.h>
#include <luna/Sort.h>
#include <luna/Utf8.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/wait.h>
#include <unistd.h>
@ -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;
}
}
}