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