summaryrefslogtreecommitdiffstats
path: root/Utilities/cmlibuv/src/win/util.c
diff options
context:
space:
mode:
Diffstat (limited to 'Utilities/cmlibuv/src/win/util.c')
-rw-r--r--Utilities/cmlibuv/src/win/util.c194
1 files changed, 143 insertions, 51 deletions
diff --git a/Utilities/cmlibuv/src/win/util.c b/Utilities/cmlibuv/src/win/util.c
index 34a898b..9e1e7f7 100644
--- a/Utilities/cmlibuv/src/win/util.c
+++ b/Utilities/cmlibuv/src/win/util.c
@@ -60,9 +60,6 @@
#endif
-/* Maximum environment variable size, including the terminating null */
-#define MAX_ENV_VAR_LENGTH 32767
-
/* A RtlGenRandom() by any other name... */
extern BOOLEAN NTAPI SystemFunction036(PVOID Buffer, ULONG BufferLength);
@@ -154,20 +151,26 @@ int uv_exepath(char* buffer, size_t* size_ptr) {
int uv_cwd(char* buffer, size_t* size) {
DWORD utf16_len;
- WCHAR utf16_buffer[MAX_PATH];
+ WCHAR *utf16_buffer;
int r;
if (buffer == NULL || size == NULL) {
return UV_EINVAL;
}
- utf16_len = GetCurrentDirectoryW(MAX_PATH, utf16_buffer);
+ utf16_len = GetCurrentDirectoryW(0, NULL);
if (utf16_len == 0) {
return uv_translate_sys_error(GetLastError());
- } else if (utf16_len > MAX_PATH) {
- /* This should be impossible; however the CRT has a code path to deal with
- * this scenario, so I added a check anyway. */
- return UV_EIO;
+ }
+ utf16_buffer = uv__malloc(utf16_len * sizeof(WCHAR));
+ if (utf16_buffer == NULL) {
+ return UV_ENOMEM;
+ }
+
+ utf16_len = GetCurrentDirectoryW(utf16_len, utf16_buffer);
+ if (utf16_len == 0) {
+ uv__free(utf16_buffer);
+ return uv_translate_sys_error(GetLastError());
}
/* utf16_len contains the length, *not* including the terminating null. */
@@ -191,8 +194,10 @@ int uv_cwd(char* buffer, size_t* size) {
NULL,
NULL);
if (r == 0) {
+ uv__free(utf16_buffer);
return uv_translate_sys_error(GetLastError());
} else if (r > (int) *size) {
+ uv__free(utf16_buffer);
*size = r;
return UV_ENOBUFS;
}
@@ -206,6 +211,8 @@ int uv_cwd(char* buffer, size_t* size) {
*size > INT_MAX ? INT_MAX : (int) *size,
NULL,
NULL);
+ uv__free(utf16_buffer);
+
if (r == 0) {
return uv_translate_sys_error(GetLastError());
}
@@ -216,43 +223,61 @@ int uv_cwd(char* buffer, size_t* size) {
int uv_chdir(const char* dir) {
- WCHAR utf16_buffer[MAX_PATH];
- size_t utf16_len;
+ WCHAR *utf16_buffer;
+ size_t utf16_len, new_utf16_len;
WCHAR drive_letter, env_var[4];
if (dir == NULL) {
return UV_EINVAL;
}
+ utf16_len = MultiByteToWideChar(CP_UTF8,
+ 0,
+ dir,
+ -1,
+ NULL,
+ 0);
+ if (utf16_len == 0) {
+ return uv_translate_sys_error(GetLastError());
+ }
+ utf16_buffer = uv__malloc(utf16_len * sizeof(WCHAR));
+ if (utf16_buffer == NULL) {
+ return UV_ENOMEM;
+ }
+
if (MultiByteToWideChar(CP_UTF8,
0,
dir,
-1,
utf16_buffer,
- MAX_PATH) == 0) {
- DWORD error = GetLastError();
- /* The maximum length of the current working directory is 260 chars,
- * including terminating null. If it doesn't fit, the path name must be too
- * long. */
- if (error == ERROR_INSUFFICIENT_BUFFER) {
- return UV_ENAMETOOLONG;
- } else {
- return uv_translate_sys_error(error);
- }
+ utf16_len) == 0) {
+ uv__free(utf16_buffer);
+ return uv_translate_sys_error(GetLastError());
}
if (!SetCurrentDirectoryW(utf16_buffer)) {
+ uv__free(utf16_buffer);
return uv_translate_sys_error(GetLastError());
}
/* Windows stores the drive-local path in an "hidden" environment variable,
* which has the form "=C:=C:\Windows". SetCurrentDirectory does not update
* this, so we'll have to do it. */
- utf16_len = GetCurrentDirectoryW(MAX_PATH, utf16_buffer);
+ new_utf16_len = GetCurrentDirectoryW(utf16_len, utf16_buffer);
+ if (new_utf16_len > utf16_len ) {
+ uv__free(utf16_buffer);
+ utf16_buffer = uv__malloc(new_utf16_len * sizeof(WCHAR));
+ if (utf16_buffer == NULL) {
+ /* When updating the environment variable fails, return UV_OK anyway.
+ * We did successfully change current working directory, only updating
+ * hidden env variable failed. */
+ return 0;
+ }
+ new_utf16_len = GetCurrentDirectoryW(new_utf16_len, utf16_buffer);
+ }
if (utf16_len == 0) {
- return uv_translate_sys_error(GetLastError());
- } else if (utf16_len > MAX_PATH) {
- return UV_EIO;
+ uv__free(utf16_buffer);
+ return 0;
}
/* The returned directory should not have a trailing slash, unless it points
@@ -284,11 +309,10 @@ int uv_chdir(const char* dir) {
env_var[2] = L':';
env_var[3] = L'\0';
- if (!SetEnvironmentVariableW(env_var, utf16_buffer)) {
- return uv_translate_sys_error(GetLastError());
- }
+ SetEnvironmentVariableW(env_var, utf16_buffer);
}
+ uv__free(utf16_buffer);
return 0;
}
@@ -361,6 +385,10 @@ char** uv_setup_args(int argc, char** argv) {
}
+void uv__process_title_cleanup(void) {
+}
+
+
int uv_set_process_title(const char* title) {
int err;
int length;
@@ -1163,20 +1191,29 @@ int uv_os_homedir(char* buffer, size_t* size) {
int uv_os_tmpdir(char* buffer, size_t* size) {
- wchar_t path[MAX_PATH + 2];
+ wchar_t *path;
DWORD bufsize;
size_t len;
if (buffer == NULL || size == NULL || *size == 0)
return UV_EINVAL;
- len = GetTempPathW(ARRAY_SIZE(path), path);
+ len = 0;
+ len = GetTempPathW(0, NULL);
+ if (len == 0) {
+ return uv_translate_sys_error(GetLastError());
+ }
+ /* Include space for terminating null char. */
+ len += 1;
+ path = uv__malloc(len * sizeof(wchar_t));
+ if (path == NULL) {
+ return UV_ENOMEM;
+ }
+ len = GetTempPathW(len, path);
if (len == 0) {
+ uv__free(path);
return uv_translate_sys_error(GetLastError());
- } else if (len > ARRAY_SIZE(path)) {
- /* This should not be possible */
- return UV_EIO;
}
/* The returned directory should not have a trailing slash, unless it points
@@ -1191,8 +1228,10 @@ int uv_os_tmpdir(char* buffer, size_t* size) {
bufsize = WideCharToMultiByte(CP_UTF8, 0, path, -1, NULL, 0, NULL, NULL);
if (bufsize == 0) {
+ uv__free(path);
return uv_translate_sys_error(GetLastError());
} else if (bufsize > *size) {
+ uv__free(path);
*size = bufsize;
return UV_ENOBUFS;
}
@@ -1206,6 +1245,7 @@ int uv_os_tmpdir(char* buffer, size_t* size) {
*size,
NULL,
NULL);
+ uv__free(path);
if (bufsize == 0)
return uv_translate_sys_error(GetLastError());
@@ -1325,7 +1365,7 @@ int uv__convert_utf8_to_utf16(const char* utf8, int utf8len, WCHAR** utf16) {
int uv__getpwuid_r(uv_passwd_t* pwd) {
HANDLE token;
wchar_t username[UNLEN + 1];
- wchar_t path[MAX_PATH];
+ wchar_t *path;
DWORD bufsize;
int r;
@@ -1336,15 +1376,24 @@ int uv__getpwuid_r(uv_passwd_t* pwd) {
if (OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &token) == 0)
return uv_translate_sys_error(GetLastError());
- bufsize = ARRAY_SIZE(path);
- if (!GetUserProfileDirectoryW(token, path, &bufsize)) {
+ bufsize = 0;
+ GetUserProfileDirectoryW(token, NULL, &bufsize);
+ if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
r = GetLastError();
CloseHandle(token);
+ return uv_translate_sys_error(r);
+ }
- /* This should not be possible */
- if (r == ERROR_INSUFFICIENT_BUFFER)
- return UV_ENOMEM;
+ path = uv__malloc(bufsize * sizeof(wchar_t));
+ if (path == NULL) {
+ CloseHandle(token);
+ return UV_ENOMEM;
+ }
+ if (!GetUserProfileDirectoryW(token, path, &bufsize)) {
+ r = GetLastError();
+ CloseHandle(token);
+ uv__free(path);
return uv_translate_sys_error(r);
}
@@ -1354,6 +1403,7 @@ int uv__getpwuid_r(uv_passwd_t* pwd) {
bufsize = ARRAY_SIZE(username);
if (!GetUserNameW(username, &bufsize)) {
r = GetLastError();
+ uv__free(path);
/* This should not be possible */
if (r == ERROR_INSUFFICIENT_BUFFER)
@@ -1364,6 +1414,7 @@ int uv__getpwuid_r(uv_passwd_t* pwd) {
pwd->homedir = NULL;
r = uv__convert_utf16_to_utf8(path, -1, &pwd->homedir);
+ uv__free(path);
if (r != 0)
return r;
@@ -1405,7 +1456,7 @@ int uv_os_environ(uv_env_item_t** envitems, int* count) {
for (penv = env, i = 0; *penv != L'\0'; penv += wcslen(penv) + 1, i++);
*envitems = uv__calloc(i, sizeof(**envitems));
- if (envitems == NULL) {
+ if (*envitems == NULL) {
FreeEnvironmentStringsW(env);
return UV_ENOMEM;
}
@@ -1461,7 +1512,9 @@ fail:
int uv_os_getenv(const char* name, char* buffer, size_t* size) {
- wchar_t var[MAX_ENV_VAR_LENGTH];
+ wchar_t fastvar[512];
+ wchar_t* var;
+ DWORD varlen;
wchar_t* name_w;
DWORD bufsize;
size_t len;
@@ -1475,25 +1528,52 @@ int uv_os_getenv(const char* name, char* buffer, size_t* size) {
if (r != 0)
return r;
- SetLastError(ERROR_SUCCESS);
- len = GetEnvironmentVariableW(name_w, var, MAX_ENV_VAR_LENGTH);
+ var = fastvar;
+ varlen = ARRAY_SIZE(fastvar);
+
+ for (;;) {
+ SetLastError(ERROR_SUCCESS);
+ len = GetEnvironmentVariableW(name_w, var, varlen);
+
+ if (len < varlen)
+ break;
+
+ /* Try repeatedly because we might have been preempted by another thread
+ * modifying the environment variable just as we're trying to read it.
+ */
+ if (var != fastvar)
+ uv__free(var);
+
+ varlen = 1 + len;
+ var = uv__malloc(varlen * sizeof(*var));
+
+ if (var == NULL) {
+ r = UV_ENOMEM;
+ goto fail;
+ }
+ }
+
uv__free(name_w);
- assert(len < MAX_ENV_VAR_LENGTH); /* len does not include the null */
+ name_w = NULL;
if (len == 0) {
r = GetLastError();
- if (r != ERROR_SUCCESS)
- return uv_translate_sys_error(r);
+ if (r != ERROR_SUCCESS) {
+ r = uv_translate_sys_error(r);
+ goto fail;
+ }
}
/* Check how much space we need */
bufsize = WideCharToMultiByte(CP_UTF8, 0, var, -1, NULL, 0, NULL, NULL);
if (bufsize == 0) {
- return uv_translate_sys_error(GetLastError());
+ r = uv_translate_sys_error(GetLastError());
+ goto fail;
} else if (bufsize > *size) {
*size = bufsize;
- return UV_ENOBUFS;
+ r = UV_ENOBUFS;
+ goto fail;
}
/* Convert to UTF-8 */
@@ -1506,11 +1586,23 @@ int uv_os_getenv(const char* name, char* buffer, size_t* size) {
NULL,
NULL);
- if (bufsize == 0)
- return uv_translate_sys_error(GetLastError());
+ if (bufsize == 0) {
+ r = uv_translate_sys_error(GetLastError());
+ goto fail;
+ }
*size = bufsize - 1;
- return 0;
+ r = 0;
+
+fail:
+
+ if (name_w != NULL)
+ uv__free(name_w);
+
+ if (var != fastvar)
+ uv__free(var);
+
+ return r;
}