summaryrefslogtreecommitdiff
path: root/deps/uv/src/win/util.c
diff options
context:
space:
mode:
Diffstat (limited to 'deps/uv/src/win/util.c')
-rw-r--r--deps/uv/src/win/util.c91
1 files changed, 65 insertions, 26 deletions
diff --git a/deps/uv/src/win/util.c b/deps/uv/src/win/util.c
index 87a999ff5..be43d50d2 100644
--- a/deps/uv/src/win/util.c
+++ b/deps/uv/src/win/util.c
@@ -154,7 +154,7 @@ int uv_exepath(char* buffer, size_t* size_ptr) {
uv_err_t uv_cwd(char* buffer, size_t size) {
DWORD utf16_len;
- WCHAR utf16_buffer[MAX_PATH + 1];
+ WCHAR utf16_buffer[MAX_PATH];
int r;
if (buffer == NULL || size == 0) {
@@ -164,6 +164,10 @@ uv_err_t uv_cwd(char* buffer, size_t size) {
utf16_len = GetCurrentDirectoryW(MAX_PATH, utf16_buffer);
if (utf16_len == 0) {
return uv__new_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__new_artificial_error(UV_EIO);
}
/* utf16_len contains the length, *not* including the terminating null. */
@@ -195,45 +199,80 @@ uv_err_t uv_cwd(char* buffer, size_t size) {
uv_err_t uv_chdir(const char* dir) {
- uv_err_t err;
- wchar_t* utf16Buffer = NULL;
- size_t utf16Size;
+ WCHAR utf16_buffer[MAX_PATH];
+ size_t utf16_len;
+ WCHAR drive_letter, env_var[4];
- if (!dir) {
- err.code = UV_EINVAL;
- goto done;
+ if (dir == NULL) {
+ return uv__new_artificial_error(UV_EINVAL);
}
- utf16Size = uv_utf8_to_utf16(dir, NULL, 0);
- if (!utf16Size) {
- err = uv__new_sys_error(GetLastError());
- goto done;
+ 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__new_artificial_error(UV_ENAMETOOLONG);
+ } else {
+ return uv__new_sys_error(error);
+ }
}
- utf16Buffer = (wchar_t*)malloc(sizeof(wchar_t) * utf16Size);
- if (!utf16Buffer) {
- err.code = UV_ENOMEM;
- goto done;
+ if (!SetCurrentDirectoryW(utf16_buffer)) {
+ return uv__new_sys_error(GetLastError());
}
- if (!uv_utf8_to_utf16(dir, utf16Buffer, utf16Size)) {
- err = uv__new_sys_error(GetLastError());
- goto done;
+ /* 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);
+ if (utf16_len == 0) {
+ return uv__new_sys_error(GetLastError());
+ } else if (utf16_len > MAX_PATH) {
+ return uv__new_artificial_error(UV_EIO);
}
- if (_wchdir(utf16Buffer) == -1) {
- err = uv__new_sys_error(_doserrno);
- goto done;
+ /* The returned directory should not have a trailing slash, unless it */
+ /* points at a drive root, like c:\. Remove it if needed. */
+ if (utf16_buffer[utf16_len - 1] == L'\\' &&
+ !(utf16_len == 3 && utf16_buffer[1] == L':')) {
+ utf16_len--;
+ utf16_buffer[utf16_len] = L'\0';
}
- err = uv_ok_;
+ if (utf16_len < 2 || utf16_buffer[1] != L':') {
+ /* Doesn't look like a drive letter could be there - probably an UNC */
+ /* path. TODO: Need to handle win32 namespaces like \\?\C:\ ? */
+ drive_letter = 0;
+ } else if (utf16_buffer[0] >= L'A' && utf16_buffer[0] <= L'Z') {
+ drive_letter = utf16_buffer[0];
+ } else if (utf16_buffer[0] >= L'a' && utf16_buffer[0] <= L'z') {
+ /* Convert to uppercase. */
+ drive_letter = utf16_buffer[0] - L'a' + L'A';
+ } else {
+ /* Not valid. */
+ drive_letter = 0;
+ }
-done:
- if (utf16Buffer) {
- free(utf16Buffer);
+ if (drive_letter != 0) {
+ /* Construct the environment variable name and set it. */
+ env_var[0] = L'=';
+ env_var[1] = drive_letter;
+ env_var[2] = L':';
+ env_var[3] = L'\0';
+
+ if (!SetEnvironmentVariableW(env_var, utf16_buffer)) {
+ return uv__new_sys_error(GetLastError());
+ }
}
- return err;
+ return uv_ok_;
}