windows: use OpenBSD implementation for uv_fs_mkdtemp
This commit is contained in:
parent
875814adc5
commit
a669f21bf8
@ -1916,6 +1916,12 @@ UV_EXTERN int uv_fs_write(uv_loop_t* loop, uv_fs_t* req, uv_file file,
|
||||
UV_EXTERN int uv_fs_mkdir(uv_loop_t* loop, uv_fs_t* req, const char* path,
|
||||
int mode, uv_fs_cb cb);
|
||||
|
||||
/*
|
||||
* Generates a uniquely named temporary directory from tpl. The last six
|
||||
* characters of tpl must be XXXXXX and these are replaced with a string that
|
||||
* makes the directory name unique. On success the name of created directory
|
||||
* will be stored in req->path.
|
||||
*/
|
||||
UV_EXTERN int uv_fs_mkdtemp(uv_loop_t* loop, uv_fs_t* req, const char* tpl,
|
||||
uv_fs_cb cb);
|
||||
|
||||
|
||||
96
src/win/fs.c
96
src/win/fs.c
@ -36,6 +36,8 @@
|
||||
#include "req-inl.h"
|
||||
#include "handle-inl.h"
|
||||
|
||||
#include <wincrypt.h>
|
||||
|
||||
|
||||
#define UV_FS_FREE_PATHS 0x0002
|
||||
#define UV_FS_FREE_PTR 0x0008
|
||||
@ -721,75 +723,61 @@ void fs__mkdir(uv_fs_t* req) {
|
||||
}
|
||||
|
||||
|
||||
/* Some parts of the implementation were borrowed from glibc. */
|
||||
/* OpenBSD original: lib/libc/stdio/mktemp.c */
|
||||
void fs__mkdtemp(uv_fs_t* req) {
|
||||
static const WCHAR letters[] =
|
||||
static const WCHAR *tempchars =
|
||||
L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
||||
static const size_t num_chars = 62;
|
||||
static const size_t num_x = 6;
|
||||
WCHAR *cp, *ep;
|
||||
unsigned int tries, i;
|
||||
size_t len;
|
||||
WCHAR* template_part;
|
||||
static uint64_t value;
|
||||
unsigned int count;
|
||||
int fd;
|
||||
|
||||
/* A lower bound on the number of temporary files to attempt to
|
||||
generate. The maximum total number of temporary file names that
|
||||
can exist for a given template is 62**6. It should never be
|
||||
necessary to try all these combinations. Instead if a reasonable
|
||||
number of names is tried (we define reasonable as 62**3) fail to
|
||||
give the system administrator the chance to remove the problems. */
|
||||
#define ATTEMPTS_MIN (62 * 62 * 62)
|
||||
|
||||
/* The number of times to attempt to generate a temporary file. To
|
||||
conform to POSIX, this must be no smaller than TMP_MAX. */
|
||||
#if ATTEMPTS_MIN < TMP_MAX
|
||||
unsigned int attempts = TMP_MAX;
|
||||
#else
|
||||
unsigned int attempts = ATTEMPTS_MIN;
|
||||
#endif
|
||||
HCRYPTPROV h_crypt_prov;
|
||||
uint64_t v;
|
||||
BOOL released;
|
||||
|
||||
len = wcslen(req->pathw);
|
||||
if (len < 6 || wcsncmp(&req->pathw[len - 6], L"XXXXXX", 6)) {
|
||||
ep = req->pathw + len;
|
||||
if (len < num_x || wcsncmp(ep - num_x, L"XXXXXX", num_x)) {
|
||||
SET_REQ_UV_ERROR(req, UV_EINVAL, ERROR_INVALID_PARAMETER);
|
||||
return;
|
||||
}
|
||||
|
||||
/* This is where the Xs start. */
|
||||
template_part = &req->pathw[len - 6];
|
||||
|
||||
/* Get some random data. */
|
||||
value += uv_hrtime() ^ _getpid();
|
||||
|
||||
for (count = 0; count < attempts; value += 7777, ++count) {
|
||||
uint64_t v = value;
|
||||
|
||||
/* Fill in the random bits. */
|
||||
template_part[0] = letters[v % 62];
|
||||
v /= 62;
|
||||
template_part[1] = letters[v % 62];
|
||||
v /= 62;
|
||||
template_part[2] = letters[v % 62];
|
||||
v /= 62;
|
||||
template_part[3] = letters[v % 62];
|
||||
v /= 62;
|
||||
template_part[4] = letters[v % 62];
|
||||
v /= 62;
|
||||
template_part[5] = letters[v % 62];
|
||||
|
||||
fd = _wmkdir(req->pathw);
|
||||
|
||||
if (fd >= 0) {
|
||||
len = strlen(req->path);
|
||||
wcstombs((char*) req->path + len - 6, template_part, 6);
|
||||
SET_REQ_RESULT(req, 0);
|
||||
if (!CryptAcquireContext(&h_crypt_prov, NULL, NULL, PROV_RSA_FULL,
|
||||
CRYPT_VERIFYCONTEXT)) {
|
||||
SET_REQ_WIN32_ERROR(req, GetLastError());
|
||||
return;
|
||||
}
|
||||
|
||||
tries = TMP_MAX;
|
||||
do {
|
||||
if (!CryptGenRandom(h_crypt_prov, sizeof(v), (BYTE*) &v)) {
|
||||
SET_REQ_WIN32_ERROR(req, GetLastError());
|
||||
break;
|
||||
}
|
||||
|
||||
cp = ep - num_x;
|
||||
for (i = 0; i < num_x; i++) {
|
||||
*cp++ = tempchars[v % num_chars];
|
||||
v /= num_chars;
|
||||
}
|
||||
|
||||
if (_wmkdir(req->pathw) == 0) {
|
||||
len = strlen(req->path);
|
||||
wcstombs((char*) req->path + len - num_x, ep - num_x, num_x);
|
||||
SET_REQ_RESULT(req, 0);
|
||||
break;
|
||||
} else if (errno != EEXIST) {
|
||||
SET_REQ_RESULT(req, -1);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
} while (--tries);
|
||||
|
||||
/* We got out of the loop because we ran out of combinations to try. */
|
||||
released = CryptReleaseContext(h_crypt_prov, 0);
|
||||
assert(released);
|
||||
if (tries == 0) {
|
||||
SET_REQ_RESULT(req, -1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user