mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 05:07:34 +00:00
LibC: Templatize unique filename enumeration for mkstemp() et al
This allows us to implement mkstemp() with open() directly, instead of first lstat()'ing, and then open()'ing the filename. Also implement tmpfile() in terms of mkstemp() instead of mktemp().
This commit is contained in:
parent
2cd07c6212
commit
b0f19c2af4
2 changed files with 38 additions and 30 deletions
|
@ -1205,16 +1205,11 @@ void funlockfile([[maybe_unused]] FILE* filehandle)
|
||||||
FILE* tmpfile()
|
FILE* tmpfile()
|
||||||
{
|
{
|
||||||
char tmp_path[] = "/tmp/XXXXXX";
|
char tmp_path[] = "/tmp/XXXXXX";
|
||||||
if (__generate_unique_filename(tmp_path) < 0)
|
int fd = mkstemp(tmp_path);
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
int fd = open(tmp_path, O_CREAT | O_EXCL | O_RDWR, S_IWUSR | S_IRUSR);
|
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
// FIXME: instead of using this hack, implement with O_TMPFILE or similar
|
// FIXME: instead of using this hack, implement with O_TMPFILE or similar
|
||||||
unlink(tmp_path);
|
unlink(tmp_path);
|
||||||
|
|
||||||
return fdopen(fd, "rw");
|
return fdopen(fd, "rw");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -171,14 +171,13 @@ static bool is_either(char* str, int offset, char lower, char upper)
|
||||||
return ch == lower || ch == upper;
|
return ch == lower || ch == upper;
|
||||||
}
|
}
|
||||||
|
|
||||||
__attribute__((warn_unused_result)) int __generate_unique_filename(char* pattern)
|
template<typename Callback>
|
||||||
|
inline int generate_unique_filename(char* pattern, Callback callback)
|
||||||
{
|
{
|
||||||
size_t length = strlen(pattern);
|
size_t length = strlen(pattern);
|
||||||
|
|
||||||
if (length < 6 || memcmp(pattern + length - 6, "XXXXXX", 6)) {
|
if (length < 6 || memcmp(pattern + length - 6, "XXXXXX", 6))
|
||||||
errno = EINVAL;
|
return EINVAL;
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t start = length - 6;
|
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 attempt = 0; attempt < 100; ++attempt) {
|
||||||
for (int i = 0; i < 6; ++i)
|
for (int i = 0; i < 6; ++i)
|
||||||
pattern[start + i] = random_characters[(arc4random() % (sizeof(random_characters) - 1))];
|
pattern[start + i] = random_characters[(arc4random() % (sizeof(random_characters) - 1))];
|
||||||
struct stat st;
|
if (callback() == IterationDecision::Break)
|
||||||
int rc = lstat(pattern, &st);
|
|
||||||
if (rc < 0 && errno == ENOENT)
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
errno = EEXIST;
|
|
||||||
return -1;
|
return EEXIST;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
@ -727,31 +724,47 @@ int system(const char* command)
|
||||||
|
|
||||||
char* mktemp(char* pattern)
|
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';
|
pattern[0] = '\0';
|
||||||
|
errno = error;
|
||||||
|
}
|
||||||
return pattern;
|
return pattern;
|
||||||
}
|
}
|
||||||
|
|
||||||
int mkstemp(char* pattern)
|
int mkstemp(char* pattern)
|
||||||
{
|
{
|
||||||
char* path = mktemp(pattern);
|
int fd = -1;
|
||||||
|
auto error = generate_unique_filename(pattern, [&] {
|
||||||
int fd = open(path, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR); // I'm using the flags I saw glibc using.
|
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)
|
if (fd >= 0)
|
||||||
return fd;
|
return IterationDecision::Break;
|
||||||
|
return IterationDecision::Continue;
|
||||||
return -1;
|
});
|
||||||
|
if (error) {
|
||||||
|
errno = error;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
char* mkdtemp(char* pattern)
|
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;
|
return nullptr;
|
||||||
|
}
|
||||||
if (mkdir(pattern, 0700) < 0)
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
return pattern;
|
return pattern;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue