environment_internal.cc 4.1 KB

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