//////////////////////////////////////////////////////////////////////////////// /// DISCLAIMER /// /// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany /// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. /// You may obtain a copy of the License at /// /// http://www.apache.org/licenses/LICENSE-2.0 /// /// Unless required by applicable law or agreed to in writing, software /// distributed under the License is distributed on an "AS IS" BASIS, /// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. /// See the License for the specific language governing permissions and /// limitations under the License. /// /// Copyright holder is ArangoDB GmbH, Cologne, Germany /// //////////////////////////////////////////////////////////////////////////////// #include "Basics/Common.h" #include "v8-utils.h" #ifdef _WIN32 #include "Basics/win-utils.h" #else #ifdef __APPLE__ #include #define environ (*_NSGetEnviron()) #elif !defined(_MSC_VER) extern char** environ; #endif #endif static void EnvGetter(v8::Local property, const v8::PropertyCallbackInfo& args) { v8::Isolate* isolate = args.GetIsolate(); v8::HandleScope scope(isolate); #ifndef _WIN32 v8::String::Utf8Value const key(property); char const* val = getenv(*key); if (val) { TRI_V8_RETURN_STRING(val); } #else // _WIN32 v8::String::Value key(property); WCHAR buffer[32767]; // The maximum size allowed for environment variables. DWORD result = GetEnvironmentVariableW(reinterpret_cast(*key), buffer, sizeof(buffer)); // ERROR_ENVVAR_NOT_FOUND is possibly returned. // 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 < sizeof(buffer)) { uint16_t const* two_byte_buffer = reinterpret_cast(buffer); TRI_V8_RETURN(TRI_V8_STRING_UTF16(isolate, two_byte_buffer, result)); } #endif // Not found. Fetch from prototype. TRI_V8_RETURN(args.Data().As()->Get(property)); } static void EnvSetter(v8::Local property, v8::Local value, const v8::PropertyCallbackInfo& args) { v8::Isolate* isolate = args.GetIsolate(); v8::HandleScope scope(isolate); #ifndef _WIN32 v8::String::Utf8Value key(property); v8::String::Utf8Value val(value); setenv(*key, *val, 1); #else // _WIN32 v8::String::Value key(property); v8::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)); } #endif // Whether it worked or not, always return rval. TRI_V8_RETURN(value); } static void EnvQuery(v8::Local property, const v8::PropertyCallbackInfo& args) { v8::Isolate* isolate = args.GetIsolate(); v8::HandleScope scope(isolate); int32_t rc = -1; // Not found unless proven otherwise. #ifndef _WIN32 v8::String::Utf8Value key(property); if (getenv(*key)) { rc = 0; } #else // _WIN32 v8::String::Value key(property); WCHAR* key_ptr = reinterpret_cast(*key); SetLastError(ERROR_SUCCESS); if (GetEnvironmentVariableW(key_ptr, nullptr, 0) > 0 || GetLastError() == ERROR_SUCCESS) { rc = 0; if (key_ptr[0] == L'=') { // Environment variables that start with '=' are hidden and read-only. rc = static_cast(v8::ReadOnly) | static_cast(v8::DontDelete) | static_cast(v8::DontEnum); } } #endif if (rc != -1) { TRI_V8_RETURN(rc); } } static void EnvDeleter(v8::Local property, const v8::PropertyCallbackInfo& args) { v8::Isolate* isolate = args.GetIsolate(); v8::HandleScope scope(isolate); #ifndef _WIN32 v8::String::Utf8Value key(property); bool rc = getenv(*key) != nullptr; if (rc) { unsetenv(*key); } #else bool rc = true; v8::String::Value key(property); WCHAR* key_ptr = reinterpret_cast(*key); if (key_ptr[0] == L'=' || !SetEnvironmentVariableW(key_ptr, nullptr)) { // Deletion failed. Return true if the key wasn't there in the first place, // false if it is still there. rc = GetEnvironmentVariableW(key_ptr, nullptr, 0) == 0 && GetLastError() != ERROR_SUCCESS; } #endif if (rc) { TRI_V8_RETURN_TRUE(); } TRI_V8_RETURN_FALSE(); } static void EnvEnumerator(const v8::PropertyCallbackInfo& args) { v8::Isolate* isolate = args.GetIsolate(); v8::HandleScope scope(isolate); #ifndef _WIN32 int size = 0; while (environ[size]) { size++; } v8::Local envarr = v8::Array::New(isolate, size); for (int i = 0; i < size; ++i) { char const* var = environ[i]; char const* s = strchr(var, '='); size_t const length = s ? s - var : strlen(var); v8::Local name = TRI_V8_PAIR_STRING(isolate, var, length); envarr->Set(i, name); } #else // _WIN32 WCHAR* environment = GetEnvironmentStringsW(); if (environment == nullptr) return; // This should not happen. v8::Local envarr = v8::Array::New(isolate); WCHAR* p = environment; int i = 0; while (*p != 0) { 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); } uint16_t const* two_byte_buffer = reinterpret_cast(p); size_t const two_byte_buffer_len = s - p; auto value = TRI_V8_STRING_UTF16(isolate, two_byte_buffer, (int)two_byte_buffer_len); envarr->Set(i, value); p = s + wcslen(s) + 1; i++; } FreeEnvironmentStringsW(environment); #endif TRI_V8_RETURN(envarr); } //////////////////////////////////////////////////////////////////////////////// /// @brief stores the V8 utils functions inside the global variable //////////////////////////////////////////////////////////////////////////////// void TRI_InitV8Env(v8::Isolate* isolate, v8::Handle context) { TRI_v8_global_t* v8g = TRI_GetV8Globals(isolate); v8::Handle rt; v8::Handle ft; ft = v8::FunctionTemplate::New(isolate); ft->SetClassName(TRI_V8_ASCII_STRING(isolate, "ENV")); rt = ft->InstanceTemplate(); // rt->SetInternalFieldCount(3); rt->SetNamedPropertyHandler(EnvGetter, EnvSetter, EnvQuery, EnvDeleter, EnvEnumerator, v8::Object::New(isolate)); v8g->EnvTempl.Reset(isolate, rt); TRI_AddGlobalFunctionVocbase(isolate, TRI_V8_ASCII_STRING(isolate, "ENV"), ft->GetFunction()); }