environment_internal.cc (4141B)
1 // Copyright 2019 The Chromium Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "base/process/environment_internal.h" 6 7 #include <stddef.h> 8 9 #include "build/build_config.h" 10 11 #if BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA) 12 #include <string.h> 13 #endif 14 15 #include <vector> 16 17 namespace base { 18 namespace internal { 19 20 namespace { 21 22 #if BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA) || BUILDFLAG(IS_WIN) 23 // Parses a null-terminated input string of an environment block. The key is 24 // placed into the given string, and the total length of the line, including 25 // the terminating null, is returned. 26 size_t ParseEnvLine(const NativeEnvironmentString::value_type* input, 27 NativeEnvironmentString* key) { 28 // Skip to the equals or end of the string, this is the key. 29 size_t cur = 0; 30 while (input[cur] && input[cur] != '=') 31 cur++; 32 *key = NativeEnvironmentString(&input[0], cur); 33 34 // Now just skip to the end of the string. 35 while (input[cur]) 36 cur++; 37 return cur + 1; 38 } 39 #endif 40 41 } // namespace 42 43 #if BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA) 44 45 std::unique_ptr<char* []> AlterEnvironment(const char* const* const env, 46 const EnvironmentMap& changes) { 47 std::string value_storage; // Holds concatenated null-terminated strings. 48 std::vector<size_t> result_indices; // Line indices into value_storage. 49 50 // First build up all of the unchanged environment strings. These are 51 // null-terminated of the form "key=value". 52 std::string key; 53 for (size_t i = 0; env[i]; i++) { 54 size_t line_length = ParseEnvLine(env[i], &key); 55 56 // Keep only values not specified in the change vector. 57 auto found_change = changes.find(key); 58 if (found_change == changes.end()) { 59 result_indices.push_back(value_storage.size()); 60 value_storage.append(env[i], line_length); 61 } 62 } 63 64 // Now append all modified and new values. 65 for (const auto& i : changes) { 66 if (!i.second.empty()) { 67 result_indices.push_back(value_storage.size()); 68 value_storage.append(i.first); 69 value_storage.push_back('='); 70 value_storage.append(i.second); 71 value_storage.push_back(0); 72 } 73 } 74 75 size_t pointer_count_required = 76 result_indices.size() + 1 + // Null-terminated array of pointers. 77 (value_storage.size() + sizeof(char*) - 1) / sizeof(char*); // Buffer. 78 std::unique_ptr<char*[]> result(new char*[pointer_count_required]); 79 80 // The string storage goes after the array of pointers. 81 char* storage_data = 82 reinterpret_cast<char*>(&result.get()[result_indices.size() + 1]); 83 if (!value_storage.empty()) 84 memcpy(storage_data, value_storage.data(), value_storage.size()); 85 86 // Fill array of pointers at the beginning of the result. 87 for (size_t i = 0; i < result_indices.size(); i++) 88 result[i] = &storage_data[result_indices[i]]; 89 result[result_indices.size()] = 0; // Null terminator. 90 91 return result; 92 } 93 94 #elif BUILDFLAG(IS_WIN) 95 96 NativeEnvironmentString AlterEnvironment(const wchar_t* env, 97 const EnvironmentMap& changes) { 98 NativeEnvironmentString result; 99 100 // First build up all of the unchanged environment strings. 101 const wchar_t* ptr = env; 102 while (*ptr) { 103 std::wstring key; 104 size_t line_length = ParseEnvLine(ptr, &key); 105 106 // Keep only values not specified in the change vector. 107 if (changes.find(key) == changes.end()) { 108 result.append(ptr, line_length); 109 } 110 ptr += line_length; 111 } 112 113 // Now append all modified and new values. 114 for (const auto& i : changes) { 115 // Windows environment blocks cannot handle keys or values with NULs. 116 CHECK_EQ(std::wstring::npos, i.first.find(L'\0')); 117 CHECK_EQ(std::wstring::npos, i.second.find(L'\0')); 118 if (!i.second.empty()) { 119 result += i.first; 120 result.push_back('='); 121 result += i.second; 122 result.push_back('\0'); 123 } 124 } 125 126 // Add the terminating NUL. 127 result.push_back('\0'); 128 return result; 129 } 130 131 #endif // BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA) 132 133 } // namespace internal 134 } // namespace base