2 * Ntdll environment functions
4 * Copyright 1996, 1998 Alexandre Julliard
5 * Copyright 2003 Eric Pouech
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 #include "wine/unicode.h"
29 #include "wine/debug.h"
30 #include "ntdll_misc.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(environ
);
34 /******************************************************************************
35 * RtlCreateEnvironment [NTDLL.@]
37 NTSTATUS WINAPI
RtlCreateEnvironment(BOOLEAN inherit
, PWSTR
* env
)
41 TRACE("(%u,%p)!\n", inherit
, env
);
45 MEMORY_BASIC_INFORMATION mbi
;
49 nts
= NtQueryVirtualMemory(NtCurrentProcess(),
50 NtCurrentTeb()->Peb
->ProcessParameters
->Environment
,
51 0, &mbi
, sizeof(mbi
), NULL
);
52 if (nts
== STATUS_SUCCESS
)
55 nts
= NtAllocateVirtualMemory(NtCurrentProcess(), (void**)env
, 0, &mbi
.RegionSize
,
56 MEM_RESERVE
| MEM_COMMIT
, PAGE_READWRITE
);
57 if (nts
== STATUS_SUCCESS
)
58 memcpy(*env
, NtCurrentTeb()->Peb
->ProcessParameters
->Environment
, mbi
.RegionSize
);
67 nts
= NtAllocateVirtualMemory(NtCurrentProcess(), &addr
, 0, &size
,
68 MEM_RESERVE
| MEM_COMMIT
, PAGE_READWRITE
);
69 if (nts
== STATUS_SUCCESS
) *env
= addr
;
75 /******************************************************************************
76 * RtlDestroyEnvironment [NTDLL.@]
78 NTSTATUS WINAPI
RtlDestroyEnvironment(PWSTR env
)
82 TRACE("(%p)!\n", env
);
84 return NtFreeVirtualMemory(NtCurrentProcess(), (void**)&env
, &size
, MEM_RELEASE
);
87 static LPCWSTR
ENV_FindVariable(PCWSTR var
, PCWSTR name
, unsigned namelen
)
89 for (; *var
; var
+= strlenW(var
) + 1)
91 /* match var names, but avoid setting a var with a name including a '='
92 * (a starting '=' is valid though)
94 if (strncmpiW(var
, name
, namelen
) == 0 && var
[namelen
] == '=' &&
95 strchrW(var
+ 1, '=') == var
+ namelen
)
97 return var
+ namelen
+ 1;
103 /******************************************************************
104 * RtlQueryEnvironmentVariable_U [NTDLL.@]
106 * NOTES: when the buffer is too small, the string is not written, but if the
107 * terminating null char is the only char that cannot be written, then
108 * all chars (except the null) are written and success is returned
109 * (behavior of Win2k at least)
111 NTSTATUS WINAPI
RtlQueryEnvironmentVariable_U(PWSTR env
,
112 PUNICODE_STRING name
,
113 PUNICODE_STRING value
)
115 NTSTATUS nts
= STATUS_VARIABLE_NOT_FOUND
;
119 TRACE("%p %s %p\n", env
, debugstr_us(name
), value
);
122 namelen
= name
->Length
/ sizeof(WCHAR
);
123 if (!namelen
) return nts
;
128 var
= NtCurrentTeb()->Peb
->ProcessParameters
->Environment
;
132 var
= ENV_FindVariable(var
, name
->Buffer
, namelen
);
135 value
->Length
= strlenW(var
) * sizeof(WCHAR
);
137 if (value
->Length
<= value
->MaximumLength
)
139 memmove(value
->Buffer
, var
, min(value
->Length
+ sizeof(WCHAR
), value
->MaximumLength
));
140 nts
= STATUS_SUCCESS
;
142 else nts
= STATUS_BUFFER_TOO_SMALL
;
145 if (!env
) RtlReleasePebLock();
150 /******************************************************************
151 * RtlSetCurrentEnvironment [NTDLL.@]
154 void WINAPI
RtlSetCurrentEnvironment(PWSTR new_env
, PWSTR
* old_env
)
156 TRACE("(%p %p)\n", new_env
, old_env
);
160 if (old_env
) *old_env
= NtCurrentTeb()->Peb
->ProcessParameters
->Environment
;
161 NtCurrentTeb()->Peb
->ProcessParameters
->Environment
= new_env
;
167 /******************************************************************************
168 * RtlSetEnvironmentVariable [NTDLL.@]
170 NTSTATUS WINAPI
RtlSetEnvironmentVariable(PWSTR
* penv
, PUNICODE_STRING name
,
171 PUNICODE_STRING value
)
175 NTSTATUS nts
= STATUS_VARIABLE_NOT_FOUND
;
176 MEMORY_BASIC_INFORMATION mbi
;
178 TRACE("(%p, %s, %s)\n", penv
, debugstr_us(name
), debugstr_us(value
));
180 if (!name
|| !name
->Buffer
|| !name
->Length
)
181 return STATUS_INVALID_PARAMETER_1
;
183 len
= name
->Length
/ sizeof(WCHAR
);
185 /* variable names can't contain a '=' except as a first character */
186 for (p
= name
->Buffer
+ 1; p
< name
->Buffer
+ len
; p
++)
187 if (*p
== '=') return STATUS_INVALID_PARAMETER
;
192 env
= NtCurrentTeb()->Peb
->ProcessParameters
->Environment
;
195 /* compute current size of environment */
196 for (p
= env
; *p
; p
+= strlenW(p
) + 1);
197 old_size
= p
+ 1 - env
;
199 /* Find a place to insert the string */
200 for (p
= env
; *p
; p
+= strlenW(p
) + 1)
202 if (!strncmpiW(name
->Buffer
, p
, len
) && (p
[len
] == '=')) break;
204 if (!value
&& !*p
) goto done
; /* Value to remove doesn't exist */
206 /* Realloc the buffer */
207 len
= value
? len
+ value
->Length
/ sizeof(WCHAR
) + 2 : 0;
208 if (*p
) len
-= strlenW(p
) + 1; /* The name already exists */
212 LPWSTR next
= p
+ strlenW(p
) + 1; /* We know there is a next one */
213 memmove(next
+ len
, next
, (old_size
- (next
- env
)) * sizeof(WCHAR
));
216 nts
= NtQueryVirtualMemory(NtCurrentProcess(), env
, 0,
217 &mbi
, sizeof(mbi
), NULL
);
218 if (nts
!= STATUS_SUCCESS
) goto done
;
220 if ((old_size
+ len
) * sizeof(WCHAR
) > mbi
.RegionSize
)
223 ULONG new_size
= (old_size
+ len
) * sizeof(WCHAR
);
226 nts
= NtAllocateVirtualMemory(NtCurrentProcess(), (void**)&new_env
, 0,
227 &new_size
, MEM_RESERVE
| MEM_COMMIT
, PAGE_READWRITE
);
228 if (nts
!= STATUS_SUCCESS
) goto done
;
230 memmove(new_env
, env
, (p
- env
) * sizeof(WCHAR
));
232 memmove(new_env
+ (p
- env
) + len
, p
, (old_size
- (p
- env
)) * sizeof(WCHAR
));
233 p
= new_env
+ (p
- env
);
235 RtlDestroyEnvironment(env
);
236 if (!penv
) NtCurrentTeb()->Peb
->ProcessParameters
->Environment
= new_env
;
237 else *penv
= new_env
;
242 if (len
> 0) memmove(p
+ len
, p
, (old_size
- (p
- env
)) * sizeof(WCHAR
));
245 /* Set the new string */
248 memcpy( p
, name
->Buffer
, name
->Length
);
249 p
+= name
->Length
/ sizeof(WCHAR
);
251 memcpy( p
, value
->Buffer
, value
->Length
);
252 p
[value
->Length
/ sizeof(WCHAR
)] = 0;
255 if (!penv
) RtlReleasePebLock();
260 /******************************************************************
261 * RtlExpandEnvironmentStrings_U (NTDLL.@)
264 NTSTATUS WINAPI
RtlExpandEnvironmentStrings_U(PWSTR renv
, const UNICODE_STRING
* us_src
,
265 PUNICODE_STRING us_dst
, PULONG plen
)
267 DWORD src_len
, len
, count
, total_size
= 1; /* 1 for terminating '\0' */
268 LPCWSTR env
, src
, p
, var
;
271 src
= us_src
->Buffer
;
272 src_len
= us_src
->Length
/ sizeof(WCHAR
);
273 count
= us_dst
->MaximumLength
/ sizeof(WCHAR
);
274 dst
= count
? us_dst
->Buffer
: NULL
;
279 env
= NtCurrentTeb()->Peb
->ProcessParameters
->Environment
;
287 if ((p
= memchrW( src
, '%', src_len
))) len
= p
- src
;
293 else /* we are at the start of a variable */
295 if ((p
= memchrW( src
+ 1, '%', src_len
- 1 )))
297 len
= p
- src
- 1; /* Length of the variable name */
298 if ((var
= ENV_FindVariable( env
, src
+ 1, len
)))
300 src
+= len
+ 2; /* Skip the variable name */
306 var
= src
; /* Copy original name instead */
312 else /* unfinished variable name, ignore it */
315 len
= src_len
; /* Copy whole string */
323 if (count
< len
) len
= count
;
324 memcpy(dst
, var
, len
* sizeof(WCHAR
));
330 if (!renv
) RtlReleasePebLock();
332 /* Null-terminate the string */
333 if (dst
&& count
) *dst
= '\0';
335 us_dst
->Length
= (dst
) ? (dst
- us_dst
->Buffer
) * sizeof(WCHAR
) : 0;
336 if (plen
) *plen
= total_size
* sizeof(WCHAR
);
338 return (count
) ? STATUS_SUCCESS
: STATUS_BUFFER_TOO_SMALL
;
342 static inline void normalize( void *base
, WCHAR
**ptr
)
344 if (*ptr
) *ptr
= (WCHAR
*)((char *)base
+ (UINT_PTR
)*ptr
);
347 /******************************************************************************
348 * RtlNormalizeProcessParams [NTDLL.@]
350 PRTL_USER_PROCESS_PARAMETERS WINAPI
RtlNormalizeProcessParams( RTL_USER_PROCESS_PARAMETERS
*params
)
352 if (params
&& !(params
->Flags
& PROCESS_PARAMS_FLAG_NORMALIZED
))
354 normalize( params
, ¶ms
->CurrentDirectory
.DosPath
.Buffer
);
355 normalize( params
, ¶ms
->DllPath
.Buffer
);
356 normalize( params
, ¶ms
->ImagePathName
.Buffer
);
357 normalize( params
, ¶ms
->CommandLine
.Buffer
);
358 normalize( params
, ¶ms
->WindowTitle
.Buffer
);
359 normalize( params
, ¶ms
->Desktop
.Buffer
);
360 normalize( params
, ¶ms
->ShellInfo
.Buffer
);
361 normalize( params
, ¶ms
->RuntimeInfo
.Buffer
);
362 params
->Flags
|= PROCESS_PARAMS_FLAG_NORMALIZED
;
368 static inline void denormalize( void *base
, WCHAR
**ptr
)
370 if (*ptr
) *ptr
= (WCHAR
*)(UINT_PTR
)((char *)*ptr
- (char *)base
);
373 /******************************************************************************
374 * RtlDeNormalizeProcessParams [NTDLL.@]
376 PRTL_USER_PROCESS_PARAMETERS WINAPI
RtlDeNormalizeProcessParams( RTL_USER_PROCESS_PARAMETERS
*params
)
378 if (params
&& (params
->Flags
& PROCESS_PARAMS_FLAG_NORMALIZED
))
380 denormalize( params
, ¶ms
->CurrentDirectory
.DosPath
.Buffer
);
381 denormalize( params
, ¶ms
->DllPath
.Buffer
);
382 denormalize( params
, ¶ms
->ImagePathName
.Buffer
);
383 denormalize( params
, ¶ms
->CommandLine
.Buffer
);
384 denormalize( params
, ¶ms
->WindowTitle
.Buffer
);
385 denormalize( params
, ¶ms
->Desktop
.Buffer
);
386 denormalize( params
, ¶ms
->ShellInfo
.Buffer
);
387 denormalize( params
, ¶ms
->RuntimeInfo
.Buffer
);
388 params
->Flags
&= ~PROCESS_PARAMS_FLAG_NORMALIZED
;
394 /* append a unicode string to the process params data; helper for RtlCreateProcessParameters */
395 static void append_unicode_string( void **data
, const UNICODE_STRING
*src
,
396 UNICODE_STRING
*dst
)
398 dst
->Length
= src
->Length
;
399 dst
->MaximumLength
= src
->MaximumLength
;
401 memcpy( dst
->Buffer
, src
->Buffer
, dst
->MaximumLength
);
402 *data
= (char *)dst
->Buffer
+ dst
->MaximumLength
;
406 /******************************************************************************
407 * RtlCreateProcessParameters [NTDLL.@]
409 NTSTATUS WINAPI
RtlCreateProcessParameters( RTL_USER_PROCESS_PARAMETERS
**result
,
410 const UNICODE_STRING
*ImagePathName
,
411 const UNICODE_STRING
*DllPath
,
412 const UNICODE_STRING
*CurrentDirectoryName
,
413 const UNICODE_STRING
*CommandLine
,
415 const UNICODE_STRING
*WindowTitle
,
416 const UNICODE_STRING
*Desktop
,
417 const UNICODE_STRING
*ShellInfo
,
418 const UNICODE_STRING
*RuntimeInfo
)
420 static const WCHAR empty
[] = {0};
421 static const UNICODE_STRING empty_str
= { 0, sizeof(empty
), (WCHAR
*)empty
};
422 static const UNICODE_STRING null_str
= { 0, 0, NULL
};
424 const RTL_USER_PROCESS_PARAMETERS
*cur_params
;
425 ULONG size
, total_size
;
430 cur_params
= NtCurrentTeb()->Peb
->ProcessParameters
;
431 if (!DllPath
) DllPath
= &cur_params
->DllPath
;
432 if (!CurrentDirectoryName
) CurrentDirectoryName
= &cur_params
->CurrentDirectory
.DosPath
;
433 if (!CommandLine
) CommandLine
= ImagePathName
;
434 if (!Environment
) Environment
= cur_params
->Environment
;
435 if (!WindowTitle
) WindowTitle
= &empty_str
;
436 if (!Desktop
) Desktop
= &empty_str
;
437 if (!ShellInfo
) ShellInfo
= &empty_str
;
438 if (!RuntimeInfo
) RuntimeInfo
= &null_str
;
440 size
= (sizeof(RTL_USER_PROCESS_PARAMETERS
)
441 + ImagePathName
->MaximumLength
442 + DllPath
->MaximumLength
443 + CurrentDirectoryName
->MaximumLength
444 + CommandLine
->MaximumLength
445 + WindowTitle
->MaximumLength
446 + Desktop
->MaximumLength
447 + ShellInfo
->MaximumLength
448 + RuntimeInfo
->MaximumLength
);
452 if ((status
= NtAllocateVirtualMemory( NtCurrentProcess(), &ptr
, 0, &total_size
,
453 MEM_COMMIT
, PAGE_READWRITE
)) == STATUS_SUCCESS
)
455 RTL_USER_PROCESS_PARAMETERS
*params
= ptr
;
456 params
->AllocationSize
= total_size
;
458 params
->Flags
= PROCESS_PARAMS_FLAG_NORMALIZED
;
459 params
->ConsoleFlags
= cur_params
->ConsoleFlags
;
460 params
->Environment
= Environment
;
461 /* all other fields are zero */
464 append_unicode_string( &ptr
, CurrentDirectoryName
, ¶ms
->CurrentDirectory
.DosPath
);
465 append_unicode_string( &ptr
, DllPath
, ¶ms
->DllPath
);
466 append_unicode_string( &ptr
, ImagePathName
, ¶ms
->ImagePathName
);
467 append_unicode_string( &ptr
, CommandLine
, ¶ms
->CommandLine
);
468 append_unicode_string( &ptr
, WindowTitle
, ¶ms
->WindowTitle
);
469 append_unicode_string( &ptr
, Desktop
, ¶ms
->Desktop
);
470 append_unicode_string( &ptr
, ShellInfo
, ¶ms
->ShellInfo
);
471 append_unicode_string( &ptr
, RuntimeInfo
, ¶ms
->RuntimeInfo
);
472 *result
= RtlDeNormalizeProcessParams( params
);
479 /******************************************************************************
480 * RtlDestroyProcessParameters [NTDLL.@]
482 void WINAPI
RtlDestroyProcessParameters( RTL_USER_PROCESS_PARAMETERS
*params
)
486 NtFreeVirtualMemory( NtCurrentProcess(), &ptr
, &size
, MEM_RELEASE
);