xref: /reactos/sdk/lib/ucrt/env/getenv.cpp (revision e98e9000)
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.
25 template <typename Character>
common_getenv_nolock(Character const * const name)26 static 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 
60 template <typename Character>
common_getenv(Character const * const name)61 static 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 
getenv(char const * const name)84 extern "C" char* __cdecl getenv(char const* const name)
85 {
86     return common_getenv(name);
87 }
88 
_wgetenv(wchar_t const * const name)89 extern "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.
106 template <typename Character>
107 _Success_(return == 0)
common_getenv_s_nolock(size_t * const required_count,_Out_writes_z_ (buffer_count)Character * const buffer,size_t const buffer_count,Character const * const name)108 static 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 
144 template <typename Character>
145 _Success_(return == 0)
common_getenv_s(size_t * const required_count,_Out_writes_z_ (buffer_count)Character * const buffer,size_t const buffer_count,Character const * const name)146 static 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 
getenv_s(size_t * const required_count,char * const buffer,size_t const buffer_count,char const * const name)169 extern "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 
_wgetenv_s(size_t * const required_count,wchar_t * const buffer,size_t const buffer_count,wchar_t const * const name)179 extern "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).
206 template <typename Character>
common_dupenv_s_nolock(_Outptr_result_buffer_maybenull_ (* buffer_count)_Outptr_result_maybenull_z_ Character ** const buffer_pointer,_Out_opt_ size_t * const buffer_count,Character const * const name,int const block_use,char const * const file_name,int const line_number)207 static 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 
252 template <typename Character>
253 _Success_(return != 0)
common_dupenv_s(_Outptr_result_buffer_maybenull_ (* buffer_count)_Outptr_result_maybenull_z_ Character ** const buffer_pointer,_Out_opt_ size_t * const buffer_count,Character const * const name,int const block_use,char const * const file_name,int const line_number)254 static 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 
_dupenv_s(char ** const buffer_pointer,size_t * const buffer_count,char const * const name)285 extern "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 
_wdupenv_s(wchar_t ** const buffer_pointer,size_t * const buffer_count,wchar_t const * const name)294 extern "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 
_dupenv_s_dbg(char ** const buffer_pointer,size_t * const buffer_count,char const * const name,int const block_use,char const * const file_name,int const line_number)308 extern "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 
_wdupenv_s_dbg(wchar_t ** const buffer_pointer,size_t * const buffer_count,wchar_t const * const name,int const block_use,char const * const file_name,int const line_number)320 extern "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
333