Fixed some bugs in CreateProcessA which was introduced by r16730.
[reactos.git] / reactos / lib / kernel32 / misc / utils.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS system libraries
4 * FILE: lib/kernel32/misc/utils.c
5 * PURPOSE: Utility and Support Functions
6 * PROGRAMMER: Alex Ionescu (alex@relsoft.net)
7 */
8
9 /* INCLUDES ****************************************************************/
10
11 #include <k32.h>
12
13 #define NDEBUG
14 #include "../include/debug.h"
15
16 /* FUNCTIONS ****************************************************************/
17
18 /*
19 * Converts an ANSI or OEM String to the specified Unicode String
20 */
21 NTSTATUS
22 STDCALL
23 Basep8BitStringToLiveUnicodeString(OUT PUNICODE_STRING UnicodeString,
24 IN LPCSTR String)
25 {
26 ANSI_STRING AnsiString;
27 NTSTATUS Status;
28
29 DPRINT("Basep8BitStringToLiveUnicodeString\n");
30
31 /* Create the ANSI String */
32 RtlInitAnsiString(&AnsiString, String);
33
34 /* Convert from OEM or ANSI */
35 Status = Basep8BitStringToUnicodeString(UnicodeString, &AnsiString, FALSE);
36
37 /* Return Status */
38 if (!NT_SUCCESS(Status))
39 {
40 SetLastErrorByStatus(Status);
41 }
42 return Status;
43 }
44
45
46 /*
47 * Converts an ANSI or OEM String to the TEB StaticUnicodeString
48 */
49 PUNICODE_STRING
50 STDCALL
51 Basep8BitStringToCachedUnicodeString(IN LPCSTR String)
52 {
53 PUNICODE_STRING StaticString = &NtCurrentTeb()->StaticUnicodeString;
54 ANSI_STRING AnsiString;
55 NTSTATUS Status;
56
57 DPRINT("Basep8BitStringToCachedUnicodeString\n");
58
59 /* Initialize an ANSI String */
60 RtlInitAnsiString(&AnsiString, String);
61
62 /* Convert it */
63 Status = Basep8BitStringToUnicodeString(StaticString, &AnsiString, FALSE);
64
65 /* Handle failure */
66 if (!NT_SUCCESS(Status))
67 {
68 SetLastErrorByStatus(Status);
69 return NULL;
70 }
71
72 /* Return pointer to the string */
73 return StaticString;
74 }
75
76 NTSTATUS
77 STDCALL
78 Basep8BitStringToHeapUnicodeString(OUT PUNICODE_STRING UnicodeString,
79 IN LPCSTR String)
80 {
81 ANSI_STRING AnsiString;
82 NTSTATUS Status;
83
84 DPRINT("Basep8BitStringToCachedUnicodeString\n");
85
86 /* Initialize an ANSI String */
87 RtlInitAnsiString(&AnsiString, String);
88
89 /* Convert it */
90 Status = Basep8BitStringToUnicodeString(UnicodeString, &AnsiString, TRUE);
91
92 /* Handle failure */
93 /* Return Status */
94 if (!NT_SUCCESS(Status))
95 {
96 SetLastErrorByStatus(Status);
97 }
98 return Status;
99 }
100
101 /*
102 * Allocates space from the Heap and converts an Ansi String into it
103 */
104 VOID
105 STDCALL
106 BasepAnsiStringToHeapUnicodeString(IN LPCSTR AnsiString,
107 IN LPWSTR* UnicodeString)
108 {
109 ANSI_STRING AnsiTemp;
110 UNICODE_STRING UnicodeTemp;
111
112 DPRINT("BasepAnsiStringToHeapUnicodeString\n");
113
114 /* First create the ANSI_STRING */
115 RtlInitAnsiString(&AnsiTemp, AnsiString);
116
117 /* Now get the size needed */
118 UnicodeTemp.MaximumLength = RtlAnsiStringToUnicodeSize(&AnsiTemp);
119
120 /* Allocate space from the Heap for the string */
121 *UnicodeString = RtlAllocateHeap(GetProcessHeap(),
122 0,
123 UnicodeTemp.MaximumLength);
124
125 /* Save the buffer and convert */
126 UnicodeTemp.Buffer = *UnicodeString;
127 RtlAnsiStringToUnicodeString(&UnicodeTemp, &AnsiTemp, FALSE);
128 }
129
130 /*
131 * Converts lpSecurityAttributes + Object Name into ObjectAttributes.
132 */
133 POBJECT_ATTRIBUTES
134 STDCALL
135 BasepConvertObjectAttributes(OUT POBJECT_ATTRIBUTES ObjectAttributes,
136 IN PSECURITY_ATTRIBUTES SecurityAttributes OPTIONAL,
137 IN PUNICODE_STRING ObjectName)
138 {
139 ULONG Attributes = 0;
140 HANDLE RootDirectory = 0;
141 PVOID SecurityDescriptor = NULL;
142 BOOLEAN NeedOba = FALSE;
143
144 DPRINT("BasepConvertObjectAttributes. Security: %p, Name: %p\n",
145 SecurityAttributes, ObjectName);
146
147 /* Get the attributes if present */
148 if (SecurityAttributes)
149 {
150 Attributes = SecurityAttributes->bInheritHandle ? OBJ_INHERIT : 0;
151 SecurityDescriptor = SecurityAttributes->lpSecurityDescriptor;
152 NeedOba = TRUE;
153 }
154
155 if (ObjectName)
156 {
157 Attributes |= OBJ_OPENIF;
158 RootDirectory = hBaseDir;
159 NeedOba = TRUE;
160 }
161
162 DPRINT("Attributes: %lx, RootDirectory: %lx, SecurityDescriptor: %p\n",
163 Attributes, RootDirectory, SecurityDescriptor);
164
165 /* Create the Object Attributes */
166 if (NeedOba)
167 {
168 InitializeObjectAttributes(ObjectAttributes,
169 ObjectName,
170 Attributes,
171 RootDirectory,
172 SecurityDescriptor);
173 return ObjectAttributes;
174 }
175
176 /* Nothing to return */
177 return NULL;
178 }
179
180 /*
181 * Creates a stack for a thread or fiber
182 */
183 NTSTATUS
184 STDCALL
185 BasepCreateStack(HANDLE hProcess,
186 ULONG StackReserve,
187 ULONG StackCommit,
188 PINITIAL_TEB InitialTeb)
189 {
190 NTSTATUS Status;
191 SYSTEM_BASIC_INFORMATION SystemBasicInfo;
192 PIMAGE_NT_HEADERS Headers;
193 ULONG_PTR Stack = 0;
194 BOOLEAN UseGuard = FALSE;
195
196 DPRINT("BasepCreateStack (hProcess: %lx, Max: %lx, Current: %lx)\n",
197 hProcess, StackReserve, StackCommit);
198
199 /* Get some memory information */
200 Status = NtQuerySystemInformation(SystemBasicInformation,
201 &SystemBasicInfo,
202 sizeof(SYSTEM_BASIC_INFORMATION),
203 NULL);
204 if (!NT_SUCCESS(Status))
205 {
206 DPRINT1("Failure to query system info\n");
207 return Status;
208 }
209
210 /* Use the Image Settings if we are dealing with the current Process */
211 if (hProcess == NtCurrentProcess())
212 {
213 /* Get the Image Headers */
214 Headers = RtlImageNtHeader(NtCurrentPeb()->ImageBaseAddress);
215
216 /* If we didn't get the parameters, find them ourselves */
217 StackReserve = (StackReserve) ?
218 StackReserve : Headers->OptionalHeader.SizeOfStackReserve;
219 StackCommit = (StackCommit) ?
220 StackCommit : Headers->OptionalHeader.SizeOfStackCommit;
221 }
222 else
223 {
224 /* Use the System Settings if needed */
225 StackReserve = (StackReserve) ? StackReserve :
226 SystemBasicInfo.AllocationGranularity;
227 StackCommit = (StackCommit) ? StackCommit : SystemBasicInfo.PageSize;
228 }
229
230 /* Align everything to Page Size */
231 StackReserve = ROUND_UP(StackReserve, SystemBasicInfo.AllocationGranularity);
232 StackCommit = ROUND_UP(StackCommit, SystemBasicInfo.PageSize);
233 #if 1 // FIXME: Remove once Guard Page support is here
234 StackCommit = StackReserve;
235 #endif
236 DPRINT("StackReserve: %lx, StackCommit: %lx\n", StackReserve, StackCommit);
237
238 /* Reserve memory for the stack */
239 Status = ZwAllocateVirtualMemory(hProcess,
240 (PVOID*)&Stack,
241 0,
242 &StackReserve,
243 MEM_RESERVE,
244 PAGE_READWRITE);
245 if (!NT_SUCCESS(Status))
246 {
247 DPRINT1("Failure to reserve stack\n");
248 return Status;
249 }
250
251 /* Now set up some basic Initial TEB Parameters */
252 InitialTeb->AllocatedStackBase = (PVOID)Stack;
253 InitialTeb->StackBase = (PVOID)(Stack + StackReserve);
254
255 /* Update the Stack Position */
256 Stack += StackReserve - StackCommit;
257
258 /* Check if we will need a guard page */
259 if (StackReserve > StackCommit)
260 {
261 Stack -= SystemBasicInfo.PageSize;
262 StackCommit += SystemBasicInfo.PageSize;
263 UseGuard = TRUE;
264 }
265
266 /* Allocate memory for the stack */
267 Status = ZwAllocateVirtualMemory(hProcess,
268 (PVOID*)&Stack,
269 0,
270 &StackCommit,
271 MEM_COMMIT,
272 PAGE_READWRITE);
273 if (!NT_SUCCESS(Status))
274 {
275 DPRINT1("Failure to allocate stack\n");
276 return Status;
277 }
278
279 /* Now set the current Stack Limit */
280 InitialTeb->StackLimit = (PVOID)Stack;
281
282 /* Create a guard page */
283 if (UseGuard)
284 {
285 ULONG GuardPageSize = SystemBasicInfo.PageSize;
286 ULONG Dummy;
287
288 /* Attempt maximum space possible */
289 Status = ZwProtectVirtualMemory(hProcess,
290 (PVOID*)&Stack,
291 &GuardPageSize,
292 PAGE_GUARD | PAGE_READWRITE,
293 &Dummy);
294 if (!NT_SUCCESS(Status))
295 {
296 DPRINT1("Failure to create guard page\n");
297 return Status;
298 }
299
300 /* Update the Stack Limit keeping in mind the Guard Page */
301 InitialTeb->StackLimit = (PVOID)((ULONG_PTR)InitialTeb->StackLimit - GuardPageSize);
302 }
303
304 /* We are done! */
305 return STATUS_SUCCESS;
306 }
307
308 VOID
309 STDCALL
310 BasepFreeStack(HANDLE hProcess,
311 PINITIAL_TEB InitialTeb)
312 {
313 ULONG Dummy = 0;
314
315 /* Free the Stack */
316 NtFreeVirtualMemory(hProcess,
317 &InitialTeb->AllocatedStackBase,
318 &Dummy,
319 MEM_RELEASE);
320 }
321
322 /*
323 * Creates the Initial Context for a Thread or Fiber
324 */
325 VOID
326 STDCALL
327 BasepInitializeContext(IN PCONTEXT Context,
328 IN PVOID Parameter,
329 IN PVOID StartAddress,
330 IN PVOID StackAddress,
331 IN ULONG ContextType)
332 {
333 DPRINT("BasepInitializeContext: %p\n", Context);
334
335 /* Setup the Initial Win32 Thread Context */
336 Context->Eax = (ULONG)StartAddress;
337 Context->Ebx = (ULONG)Parameter;
338 Context->Esp = (ULONG)StackAddress;
339 /* The other registers are undefined */
340
341 /* Setup the Segments */
342 Context->SegCs = USER_CS;
343 Context->SegDs = USER_DS;
344 Context->SegEs = USER_DS;
345 Context->SegFs = TEB_SELECTOR;
346 Context->SegSs = USER_DS;
347 Context->SegGs = 0;
348
349 /* Set the EFLAGS */
350 Context->EFlags = 0x3000; /* IOPL 3 */
351
352 if (ContextType == 1) /* For Threads */
353 {
354 Context->Eip = (ULONG)BaseThreadStartupThunk;
355 }
356 else if (ContextType == 2) /* For Fibers */
357 {
358 //Context->Eip = (ULONG)BaseFiberStartup;
359 }
360 else /* For first thread in a Process */
361 {
362 Context->Eip = (ULONG)BaseProcessStartThunk;
363 }
364
365 /* Set the Context Flags */
366 Context->ContextFlags = CONTEXT_FULL;
367
368 /* Give it some room for the Parameter */
369 Context->Esp -= sizeof(PVOID);
370 }
371
372 /*
373 * Checks if the privilege for Real-Time Priority is there
374 */
375 BOOLEAN
376 STDCALL
377 BasepCheckRealTimePrivilege(VOID)
378 {
379 return TRUE;
380 }
381
382 /*
383 * Maps an image file into a section
384 */
385 NTSTATUS
386 STDCALL
387 BasepMapFile(IN LPCWSTR lpApplicationName,
388 OUT PHANDLE hSection,
389 IN PUNICODE_STRING ApplicationName)
390 {
391 CURDIR RelativeName;
392 OBJECT_ATTRIBUTES ObjectAttributes;
393 NTSTATUS Status;
394 HANDLE hFile = NULL;
395 IO_STATUS_BLOCK IoStatusBlock;
396
397 DPRINT("BasepMapFile\n");
398
399 /* Zero out the Relative Directory */
400 RelativeName.Handle = NULL;
401
402 /* Find the application name */
403 RtlDosPathNameToNtPathName_U((LPWSTR)lpApplicationName,
404 ApplicationName,
405 NULL,
406 &RelativeName);
407 DPRINT("ApplicationName %wZ\n", ApplicationName);
408 DPRINT("RelativeName %wZ\n", &RelativeName.DosPath);
409
410 /* Did we get a relative name? */
411 if (RelativeName.DosPath.Length)
412 {
413 ApplicationName = &RelativeName.DosPath;
414 }
415
416 /* Initialize the Object Attributes */
417 InitializeObjectAttributes(&ObjectAttributes,
418 ApplicationName,
419 OBJ_CASE_INSENSITIVE,
420 RelativeName.Handle,
421 NULL);
422
423 /* Try to open the executable */
424 Status = NtOpenFile(&hFile,
425 SYNCHRONIZE | FILE_EXECUTE | FILE_READ_DATA,
426 &ObjectAttributes,
427 &IoStatusBlock,
428 FILE_SHARE_DELETE | FILE_SHARE_READ,
429 FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE);
430 if (!NT_SUCCESS(Status))
431 {
432 DPRINT1("Failed to open file\n");
433 SetLastErrorByStatus (Status);
434 return Status;
435 }
436
437 /* Create a section for this file */
438 Status = NtCreateSection(hSection,
439 SECTION_ALL_ACCESS,
440 NULL,
441 NULL,
442 PAGE_EXECUTE,
443 SEC_IMAGE,
444 hFile);
445 NtClose(hFile);
446
447 /* Return status */
448 DPRINT("Section: %lx for file: %lx\n", *hSection, hFile);
449 return Status;
450 }