libc: Add mktemp() and mkdtemp(), along with a test for mktemp

This commit is contained in:
apio 2022-11-05 18:07:45 +01:00
parent b2fb740d99
commit da182f1c2f
5 changed files with 81 additions and 4 deletions

View File

@ -120,7 +120,10 @@ extern "C"
size_t mbstowcs(wchar_t* dest, const char* src, size_t mbstowcs(wchar_t* dest, const char* src,
size_t n); // Not implemented. size_t n); // Not implemented.
char* mktemp(char* base); // Not implemented. /* Generate a unique filename from the template string str. The last 6 bytes of str must be 'XXXXXX', and they will
* be replaced with random characters. This function is deprecated due to race conditions; between the name being
* generated and creating a file with that name, that filename could have already been used. */
__lc_is_deprecated char* mktemp(char* str);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -2,6 +2,8 @@
#include <luna.h> #include <luna.h>
#include <luna/syscall.h> #include <luna/syscall.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/syscall.h> #include <sys/syscall.h>
#include <sys/wait.h> #include <sys/wait.h>
#include <unistd.h> #include <unistd.h>
@ -188,8 +190,52 @@ extern "C"
NOT_IMPLEMENTED("mbstowcs"); NOT_IMPLEMENTED("mbstowcs");
} }
char* mktemp(char*) static void gentemp(char* startptr)
{ {
NOT_IMPLEMENTED("mktemp"); for (int i = 0; i < 6; i++)
{
startptr[i] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890"[rand() % 63];
}
}
char* mktemp(char* str)
{
size_t len = strlen(str);
if (len < 6)
{
errno = EINVAL;
return NULL;
}
char* startptr = str + (len - 6);
if (strncmp(startptr, "XXXXXX", 6))
{
errno = EINVAL;
return NULL;
}
do {
gentemp(startptr);
} while (access(str, F_OK) == 0);
return str;
}
char* mkdtemp(char* str)
{
size_t len = strlen(str);
if (len < 6)
{
errno = EINVAL;
return NULL;
}
char* startptr = str + (len - 6);
if (strncmp(startptr, "XXXXXX", 6))
{
errno = EINVAL;
return NULL;
}
do {
gentemp(startptr);
} while (mkdir(str, 0700) < 0 && errno == EEXIST);
if (errno) return NULL;
return str;
} }
} }

View File

@ -4,7 +4,7 @@ DESTDIR := $(LUNA_ROOT)/initrd/bin
build: build:
@mkdir -p $(TESTDIR)/bin @mkdir -p $(TESTDIR)/bin
$(LUNA_ROOT)/tools/sync-libc.sh $(LUNA_ROOT)/tools/sync-libc.sh
$(CC) $(TESTDIR)/string.c $(TESTDIR)/stdlib.c $(TESTDIR)/Test.c -I$(LUNA_ROOT)/tests -o $(TESTDIR)/bin/test-libc -Wall -Wextra -Wno-stringop-overread -Werror $(CC) $(TESTDIR)/string.c $(TESTDIR)/stdlib.c $(TESTDIR)/Test.c -I$(LUNA_ROOT)/tests -o $(TESTDIR)/bin/test-libc -Wall -Wextra -Wno-deprecated-declarations -Wno-stringop-overread -Werror
install: install:
$(LUNA_ROOT)/tools/clean.sh $(LUNA_ROOT)/tools/clean.sh

View File

@ -24,6 +24,7 @@ DEFINE_TEST(atoll);
DEFINE_TEST(srand); DEFINE_TEST(srand);
DEFINE_TEST(malloc); DEFINE_TEST(malloc);
DEFINE_TEST(calloc); DEFINE_TEST(calloc);
DEFINE_TEST(mktemp);
int main() int main()
{ {
@ -51,4 +52,5 @@ int main()
RUN_TEST(srand); RUN_TEST(srand);
RUN_TEST(malloc); RUN_TEST(malloc);
RUN_TEST(calloc); RUN_TEST(calloc);
RUN_TEST(mktemp);
} }

View File

@ -1,5 +1,7 @@
#include "Test.h" #include "Test.h"
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#include <unistd.h>
DEFINE_TEST(atoi) DEFINE_TEST(atoi)
{ {
@ -138,3 +140,27 @@ DEFINE_TEST(calloc)
TEST_SUCCESS(); TEST_SUCCESS();
} }
DEFINE_TEST(mktemp)
{
START_TEST(mktemp);
char template[] = "/tmp/file.XXXXXX";
const char* template2 = "/tmp/file.XXXXXX";
char* ptr = mktemp(template);
EXPECT_NOT_EQ(ptr, NULL); // mktemp only fails if we give it an invalid template.
int rc = access(ptr, F_OK);
EXPECT_NOT_EQ(rc, 0); // FIXME: This could actually happen, since that's why mktemp is deprecated.
// Another process could create the file between generating the name and actually using it.
rc = strcmp(ptr, template2);
EXPECT_NOT_EQ(rc, 0);
TEST_SUCCESS();
}