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