diff --git a/src/node.cc b/src/node.cc index f6ae19da928973..d429a9c7f2899b 100644 --- a/src/node.cc +++ b/src/node.cc @@ -1296,7 +1296,8 @@ static Handle CwdForDrive(const Arguments& args) { env_key[1] = (WCHAR) drive; DWORD len = GetEnvironmentVariableW(env_key, NULL, 0); - if (len == 0 && GetLastError() == ERROR_ENVVAR_NOT_FOUND) { + if (len == 0 && (GetLastError() == ERROR_ENVVAR_NOT_FOUND || + GetLastError() == ERROR_SUCCESS)) { // There is no current directory for that drive. Default to drive + ":\". Local cwd = String::Concat(String::New(&drive, 1), String::New(":\\")); @@ -1317,7 +1318,7 @@ static Handle CwdForDrive(const Arguments& args) { } DWORD len2 = GetEnvironmentVariableW(env_key, buffer, len); - if (len2 == 0 || len2 >= len) { + if ((len2 == 0 && GetLastError() != ERROR_SUCCESS) || len2 >= len) { // Error delete[] buffer; Local exception = Exception::Error( @@ -1869,12 +1870,28 @@ static void ProcessTitleSetter(Local property, static Handle EnvGetter(Local property, const AccessorInfo& info) { + HandleScope scope; +#ifdef __POSIX__ String::Utf8Value key(property); const char* val = getenv(*key); if (val) { - HandleScope scope; return scope.Close(String::New(val)); } +#else // _WIN32 + String::Value key(property); + WCHAR buffer[32767]; // The maximum size allowed for environment variables. + DWORD result = GetEnvironmentVariableW(reinterpret_cast(*key), + buffer, + ARRAY_SIZE(buffer)); + // If result >= sizeof buffer the buffer was too small. That should never + // happen. If result == 0 and result != ERROR_SUCCESS the variable was not + // not found. + if ((result > 0 || GetLastError() == ERROR_SUCCESS) && + result < ARRAY_SIZE(buffer)) { + return scope.Close(String::New(reinterpret_cast(buffer), result)); + } +#endif + // Not found return Undefined(); } @@ -1883,66 +1900,82 @@ static Handle EnvSetter(Local property, Local value, const AccessorInfo& info) { HandleScope scope; +#ifdef __POSIX__ String::Utf8Value key(property); String::Utf8Value val(value); - -#ifdef __POSIX__ setenv(*key, *val, 1); -#else // __WIN32__ - int n = key.length() + val.length() + 2; - char* pair = new char[n]; - snprintf(pair, n, "%s=%s", *key, *val); - int r = _putenv(pair); - if (r) { - fprintf(stderr, "error putenv: '%s'\n", pair); +#else // _WIN32 + String::Value key(property); + String::Value val(value); + WCHAR* key_ptr = reinterpret_cast(*key); + // Environment variables that start with '=' are read-only. + if (key_ptr[0] != L'=') { + SetEnvironmentVariableW(key_ptr, reinterpret_cast(*val)); } - delete [] pair; #endif - - return value; + // Whether it worked or not, always return rval. + return scope.Close(value); } static Handle EnvQuery(Local property, const AccessorInfo& info) { + HandleScope scope; +#ifdef __POSIX__ String::Utf8Value key(property); if (getenv(*key)) { - HandleScope scope; return scope.Close(Integer::New(None)); } - return Handle(); +#else // _WIN32 + String::Value key(property); + WCHAR* key_ptr = reinterpret_cast(*key); + if (GetEnvironmentVariableW(key_ptr, NULL, 0) > 0 || + GetLastError() == ERROR_SUCCESS) { + if (key_ptr[0] == L'=') { + // Environment variables that start with '=' are hidden and read-only. + return scope.Close(Integer::New(v8::ReadOnly || + v8::DontDelete || + v8::DontEnum)); + } else { + return scope.Close(Integer::New(None)); + } + } +#endif + // Not found + return scope.Close(Handle()); } static Handle EnvDeleter(Local property, const AccessorInfo& info) { HandleScope scope; - - String::Utf8Value key(property); - - if (getenv(*key)) { #ifdef __POSIX__ - unsetenv(*key); // prototyped as `void unsetenv(const char*)` on some platforms + String::Utf8Value key(property); + // prototyped as `void unsetenv(const char*)` on some platforms + if (unsetenv(*key) < 0) { + // Deletion failed. Return true if the key wasn't there in the first place, + // false if it is still there. + return scope.Close(Boolean::New(getenv(*key) == NULL)); + }; #else - int n = key.length() + 2; - char* pair = new char[n]; - snprintf(pair, n, "%s=", *key); - int r = _putenv(pair); - if (r) { - fprintf(stderr, "error unsetenv: '%s'\n", pair); - } - delete [] pair; -#endif - return True(); + String::Value key(property); + WCHAR* key_ptr = reinterpret_cast(*key); + if (key_ptr[0] == L'=' || !SetEnvironmentVariableW(key_ptr, NULL)) { + // Deletion failed. Return true if the key wasn't there in the first place, + // false if it is still there. + bool rv = GetEnvironmentVariableW(key_ptr, NULL, NULL) == 0 && + GetLastError() != ERROR_SUCCESS; + return scope.Close(Boolean::New(rv)); } - - return False(); +#endif + // It worked + return v8::True(); } static Handle EnvEnumerator(const AccessorInfo& info) { HandleScope scope; - +#ifdef __POSIX__ int size = 0; while (environ[size]) size++; @@ -1954,7 +1987,32 @@ static Handle EnvEnumerator(const AccessorInfo& info) { const int length = s ? s - var : strlen(var); env->Set(i, String::New(var, length)); } - +#else // _WIN32 + WCHAR* environment = GetEnvironmentStringsW(); + if (environment == NULL) { + // This should not happen. + return scope.Close(Handle()); + } + Local env = Array::New(); + WCHAR* p = environment; + int i = 0; + while (*p != NULL) { + WCHAR *s; + if (*p == L'=') { + // If the key starts with '=' it is a hidden environment variable. + p += wcslen(p) + 1; + continue; + } else { + s = wcschr(p, L'='); + } + if (!s) { + s = p + wcslen(p); + } + env->Set(i++, String::New(reinterpret_cast(p), s - p)); + p = s + wcslen(s) + 1; + } + FreeEnvironmentStringsW(environment); +#endif return scope.Close(env); }