Reactos
at master 332 lines 11 kB view raw
1// 2// getenv.cpp 3// 4// Copyright (c) Microsoft Corporation. All rights reserved. 5// 6// Defines the getenv family of functions, which search the environment for a 7// variable and return its value. 8// 9#include <corecrt_internal_traits.h> 10#include <stdlib.h> 11#include <string.h> 12 13 14 15//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 16// 17// getenv() and _wgetenv() 18// 19//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 20// These functions search the environment for a variable with the given name. 21// If such a variable is found, a pointer to its value is returned. Otherwise, 22// nullptr is returned. Note that if the environment is access and manipulated 23// from multiple threads, this function cannot be safely used: the returned 24// pointer may not be valid when the function returns. 25template <typename Character> 26static Character* __cdecl common_getenv_nolock(Character const* const name) throw() 27{ 28 typedef __crt_char_traits<Character> traits; 29 30 Character** const environment = traits::get_or_create_environment_nolock(); 31 if (environment == nullptr || name == nullptr) 32 return nullptr; 33 34 size_t const name_length = traits::tcslen(name); 35 36 for (Character** current = environment; *current; ++current) 37 { 38 if (traits::tcslen(*current) <= name_length) 39 continue; 40 41 if (*(*current + name_length) != '=') 42 continue; 43 44 if (traits::tcsnicoll(*current, name, name_length) != 0) 45 continue; 46 47 // Internal consistency check: The environment string should never use 48 // a bigger buffer than _MAX_ENV. See also the SetEnvironmentVariable 49 // SDK function. 50 _ASSERTE(traits::tcsnlen(*current + name_length + 1, _MAX_ENV) < _MAX_ENV); 51 52 return *current + name_length + 1; 53 } 54 55 return nullptr; 56} 57 58 59 60template <typename Character> 61static Character* __cdecl common_getenv(Character const* const name) throw() 62{ 63 typedef __crt_char_traits<Character> traits; 64 65 _VALIDATE_RETURN(name != nullptr, EINVAL, nullptr); 66 _VALIDATE_RETURN(traits::tcsnlen(name, _MAX_ENV) < _MAX_ENV, EINVAL, nullptr); 67 68 Character* result = 0; 69 70 __acrt_lock(__acrt_environment_lock); 71 __try 72 { 73 result = common_getenv_nolock(name); 74 } 75 __finally 76 { 77 __acrt_unlock(__acrt_environment_lock); 78 } 79 __endtry 80 81 return result; 82} 83 84extern "C" char* __cdecl getenv(char const* const name) 85{ 86 return common_getenv(name); 87} 88 89extern "C" wchar_t* __cdecl _wgetenv(wchar_t const* const name) 90{ 91 return common_getenv(name); 92} 93 94 95 96//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 97// 98// getenv_s() and _wgetenv_s() 99// 100//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 101// These functions search the environment for a variable with the given name. 102// If such a variable is found, its value is copied into the provided buffer. 103// The number of characters in the value (including the null terminator) is 104// stored in '*required_count'. Returns 0 on success; returns ERANGE if the 105// provided buffer is too small; otherwise returns an error code on failure. 106template <typename Character> 107_Success_(return == 0) 108static errno_t __cdecl common_getenv_s_nolock( 109 size_t* const required_count, 110 _Out_writes_z_(buffer_count) Character* const buffer, 111 size_t const buffer_count, 112 Character const* const name 113 ) throw() 114{ 115 typedef __crt_char_traits<Character> traits; 116 117 _VALIDATE_RETURN_ERRCODE(required_count != nullptr, EINVAL); 118 *required_count = 0; 119 120 _VALIDATE_RETURN_ERRCODE( 121 (buffer != nullptr && buffer_count > 0) || 122 (buffer == nullptr && buffer_count == 0), EINVAL); 123 124 if (buffer) 125 buffer[0] = '\0'; 126 127 Character const* const value = common_getenv_nolock(name); 128 if (!value) 129 return 0; 130 131 *required_count = traits::tcslen(value) + 1; 132 if (buffer_count == 0) 133 return 0; 134 135 // The buffer is too small; we return an error code and the caller can have 136 // the opportunity to try again with a larger buffer: 137 if (*required_count > buffer_count) 138 return ERANGE; 139 140 _ERRCHECK(traits::tcscpy_s(buffer, buffer_count, value)); 141 return 0; 142} 143 144template <typename Character> 145_Success_(return == 0) 146static errno_t __cdecl common_getenv_s( 147 size_t* const required_count, 148 _Out_writes_z_(buffer_count) Character* const buffer, 149 size_t const buffer_count, 150 Character const* const name 151 ) throw() 152{ 153 errno_t status = 0; 154 155 __acrt_lock(__acrt_environment_lock); 156 __try 157 { 158 status = common_getenv_s_nolock(required_count, buffer, buffer_count, name); 159 } 160 __finally 161 { 162 __acrt_unlock(__acrt_environment_lock); 163 } 164 __endtry 165 166 return status; 167} 168 169extern "C" errno_t __cdecl getenv_s( 170 size_t* const required_count, 171 char* const buffer, 172 size_t const buffer_count, 173 char const* const name 174 ) 175{ 176 return common_getenv_s(required_count, buffer, buffer_count, name); 177} 178 179extern "C" errno_t __cdecl _wgetenv_s( 180 size_t* const required_count, 181 wchar_t* const buffer, 182 size_t const buffer_count, 183 wchar_t const* const name 184 ) 185{ 186 return common_getenv_s(required_count, buffer, buffer_count, name); 187} 188 189 190 191//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 192// 193// _dupenv_s() and _wdupenv_s() 194// 195//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 196// These functions search the environment for a variable with the given name. 197// If a variable is found, a buffer is allocated using the public malloc to hold 198// the value of the variable. The value is copied into the buffer and the buffer 199// is returned to the caller via 'buffer_pointer' and 'buffer_count'. The caller 200// is responsible for freeing the buffer. 201// 202// Returns zero on success; returns an error code on failure. Note that if a 203// variable with the specified name is not found, that is still considered a 204// success; in this case, the 'value' is an empty string ('*buffer_count' will 205// be zero and '*buffer_pointer' will be nullptr). 206template <typename Character> 207static errno_t __cdecl common_dupenv_s_nolock( 208 _Outptr_result_buffer_maybenull_(*buffer_count) _Outptr_result_maybenull_z_ Character** const buffer_pointer, 209 _Out_opt_ size_t* const buffer_count, 210 Character const* const name, 211 int const block_use, 212 char const* const file_name, 213 int const line_number 214 ) throw() 215{ 216 // These are referenced only in the Debug CRT build 217 UNREFERENCED_PARAMETER(block_use); 218 UNREFERENCED_PARAMETER(file_name); 219 UNREFERENCED_PARAMETER(line_number); 220 221 typedef __crt_char_traits<Character> traits; 222 223 _VALIDATE_RETURN_ERRCODE(buffer_pointer != nullptr, EINVAL); 224 *buffer_pointer = nullptr; 225 226 if (buffer_count != nullptr) 227 *buffer_count = 0; 228 229 _VALIDATE_RETURN_ERRCODE(name != nullptr, EINVAL); 230 231 Character const* const value = common_getenv_nolock(name); 232 if (value == nullptr) 233 return 0; 234 235 size_t const value_count = traits::tcslen(value) + 1; 236 237 *buffer_pointer = static_cast<Character*>(_calloc_dbg( 238 value_count, 239 sizeof(Character), 240 block_use, 241 file_name, 242 line_number)); 243 _VALIDATE_RETURN_ERRCODE_NOEXC(*buffer_pointer != nullptr, ENOMEM); 244 245 _ERRCHECK(traits::tcscpy_s(*buffer_pointer, value_count, value)); 246 if (buffer_count != nullptr) 247 *buffer_count = value_count; 248 249 return 0; 250} 251 252template <typename Character> 253_Success_(return != 0) 254static errno_t __cdecl common_dupenv_s( 255 _Outptr_result_buffer_maybenull_(*buffer_count) _Outptr_result_maybenull_z_ Character** const buffer_pointer, 256 _Out_opt_ size_t* const buffer_count, 257 Character const* const name, 258 int const block_use, 259 char const* const file_name, 260 int const line_number 261 ) throw() 262{ 263 errno_t status = 0; 264 265 __acrt_lock(__acrt_environment_lock); 266 __try 267 { 268 status = common_dupenv_s_nolock( 269 buffer_pointer, 270 buffer_count, 271 name, 272 block_use, 273 file_name, 274 line_number); 275 } 276 __finally 277 { 278 __acrt_unlock(__acrt_environment_lock); 279 } 280 __endtry 281 282 return status; 283} 284 285extern "C" errno_t __cdecl _dupenv_s( 286 char** const buffer_pointer, 287 size_t* const buffer_count, 288 char const* const name 289 ) 290{ 291 return common_dupenv_s(buffer_pointer, buffer_count, name, _NORMAL_BLOCK, nullptr, 0); 292} 293 294extern "C" errno_t __cdecl _wdupenv_s( 295 wchar_t** const buffer_pointer, 296 size_t* const buffer_count, 297 wchar_t const* const name 298 ) 299{ 300 return common_dupenv_s(buffer_pointer, buffer_count, name, _NORMAL_BLOCK, nullptr, 0); 301} 302 303#ifdef _DEBUG 304 305#undef _dupenv_s_dbg 306#undef _wdupenv_s_dbg 307 308extern "C" errno_t __cdecl _dupenv_s_dbg( 309 char** const buffer_pointer, 310 size_t* const buffer_count, 311 char const* const name, 312 int const block_use, 313 char const* const file_name, 314 int const line_number 315 ) 316{ 317 return common_dupenv_s(buffer_pointer, buffer_count, name, block_use, file_name, line_number); 318} 319 320extern "C" errno_t __cdecl _wdupenv_s_dbg( 321 wchar_t** const buffer_pointer, 322 size_t* const buffer_count, 323 wchar_t const* const name, 324 int const block_use, 325 char const* const file_name, 326 int const line_number 327 ) 328{ 329 return common_dupenv_s(buffer_pointer, buffer_count, name, block_use, file_name, line_number); 330} 331 332#endif // _DEBUG