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