- Update to r53061
[reactos.git] / dll / win32 / kernel32 / client / 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 BaseSetLastNTError(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 PLARGE_INTEGER
121 WINAPI
122 BaseFormatTimeOut(OUT PLARGE_INTEGER Timeout,
123 IN DWORD dwMilliseconds)
124 {
125 /* Check if this is an infinite wait, which means no timeout argument */
126 if (dwMilliseconds == INFINITE) return NULL;
127
128 /* Otherwise, convert the time to NT Format */
129 Timeout->QuadPart = UInt32x32To64(dwMilliseconds, -10000);
130 return Timeout;
131 }
132
133 /*
134 * Converts lpSecurityAttributes + Object Name into ObjectAttributes.
135 */
136 POBJECT_ATTRIBUTES
137 WINAPI
138 BasepConvertObjectAttributes(OUT POBJECT_ATTRIBUTES ObjectAttributes,
139 IN PSECURITY_ATTRIBUTES SecurityAttributes OPTIONAL,
140 IN PUNICODE_STRING ObjectName)
141 {
142 ULONG Attributes = 0;
143 HANDLE RootDirectory = 0;
144 PVOID SecurityDescriptor = NULL;
145 BOOLEAN NeedOba = FALSE;
146
147 DPRINT("BasepConvertObjectAttributes. Security: %p, Name: %p\n",
148 SecurityAttributes, ObjectName);
149
150 /* Get the attributes if present */
151 if (SecurityAttributes)
152 {
153 Attributes = SecurityAttributes->bInheritHandle ? OBJ_INHERIT : 0;
154 SecurityDescriptor = SecurityAttributes->lpSecurityDescriptor;
155 NeedOba = TRUE;
156 }
157
158 if (ObjectName)
159 {
160 Attributes |= OBJ_OPENIF;
161 RootDirectory = hBaseDir;
162 NeedOba = TRUE;
163 }
164
165 DPRINT("Attributes: %lx, RootDirectory: %lx, SecurityDescriptor: %p\n",
166 Attributes, RootDirectory, SecurityDescriptor);
167
168 /* Create the Object Attributes */
169 if (NeedOba)
170 {
171 InitializeObjectAttributes(ObjectAttributes,
172 ObjectName,
173 Attributes,
174 RootDirectory,
175 SecurityDescriptor);
176 return ObjectAttributes;
177 }
178
179 /* Nothing to return */
180 return NULL;
181 }
182
183 /*
184 * Creates a stack for a thread or fiber
185 */
186 NTSTATUS
187 WINAPI
188 BasepCreateStack(HANDLE hProcess,
189 SIZE_T StackReserve,
190 SIZE_T StackCommit,
191 PINITIAL_TEB InitialTeb)
192 {
193 NTSTATUS Status;
194 SYSTEM_BASIC_INFORMATION SystemBasicInfo;
195 PIMAGE_NT_HEADERS Headers;
196 ULONG_PTR Stack = 0;
197 BOOLEAN UseGuard = FALSE;
198
199 DPRINT("BasepCreateStack (hProcess: %lx, Max: %lx, Current: %lx)\n",
200 hProcess, StackReserve, StackCommit);
201
202 /* Get some memory information */
203 Status = NtQuerySystemInformation(SystemBasicInformation,
204 &SystemBasicInfo,
205 sizeof(SYSTEM_BASIC_INFORMATION),
206 NULL);
207 if (!NT_SUCCESS(Status))
208 {
209 DPRINT1("Failure to query system info\n");
210 return Status;
211 }
212
213 /* Use the Image Settings if we are dealing with the current Process */
214 if (hProcess == NtCurrentProcess())
215 {
216 /* Get the Image Headers */
217 Headers = RtlImageNtHeader(NtCurrentPeb()->ImageBaseAddress);
218
219 /* If we didn't get the parameters, find them ourselves */
220 StackReserve = (StackReserve) ?
221 StackReserve : Headers->OptionalHeader.SizeOfStackReserve;
222 StackCommit = (StackCommit) ?
223 StackCommit : Headers->OptionalHeader.SizeOfStackCommit;
224 }
225 else
226 {
227 /* Use the System Settings if needed */
228 StackReserve = (StackReserve) ? StackReserve :
229 SystemBasicInfo.AllocationGranularity;
230 StackCommit = (StackCommit) ? StackCommit : SystemBasicInfo.PageSize;
231 }
232
233 /* Align everything to Page Size */
234 StackReserve = ROUND_UP(StackReserve, SystemBasicInfo.AllocationGranularity);
235 StackCommit = ROUND_UP(StackCommit, SystemBasicInfo.PageSize);
236 #if 1 // FIXME: Remove once Guard Page support is here
237 StackCommit = StackReserve;
238 #endif
239 DPRINT("StackReserve: %lx, StackCommit: %lx\n", StackReserve, StackCommit);
240
241 /* Reserve memory for the stack */
242 Status = ZwAllocateVirtualMemory(hProcess,
243 (PVOID*)&Stack,
244 0,
245 &StackReserve,
246 MEM_RESERVE,
247 PAGE_READWRITE);
248 if (!NT_SUCCESS(Status))
249 {
250 DPRINT1("Failure to reserve stack\n");
251 return Status;
252 }
253
254 /* Now set up some basic Initial TEB Parameters */
255 InitialTeb->AllocatedStackBase = (PVOID)Stack;
256 InitialTeb->StackBase = (PVOID)(Stack + StackReserve);
257 InitialTeb->PreviousStackBase = NULL;
258 InitialTeb->PreviousStackLimit = NULL;
259
260 /* Update the Stack Position */
261 Stack += StackReserve - StackCommit;
262
263 /* Check if we will need a guard page */
264 if (StackReserve > StackCommit)
265 {
266 Stack -= SystemBasicInfo.PageSize;
267 StackCommit += SystemBasicInfo.PageSize;
268 UseGuard = TRUE;
269 }
270
271 /* Allocate memory for the stack */
272 Status = ZwAllocateVirtualMemory(hProcess,
273 (PVOID*)&Stack,
274 0,
275 &StackCommit,
276 MEM_COMMIT,
277 PAGE_READWRITE);
278 if (!NT_SUCCESS(Status))
279 {
280 DPRINT1("Failure to allocate stack\n");
281 return Status;
282 }
283
284 /* Now set the current Stack Limit */
285 InitialTeb->StackLimit = (PVOID)Stack;
286
287 /* Create a guard page */
288 if (UseGuard)
289 {
290 SIZE_T GuardPageSize = SystemBasicInfo.PageSize;
291 ULONG Dummy;
292
293 /* Attempt maximum space possible */
294 Status = ZwProtectVirtualMemory(hProcess,
295 (PVOID*)&Stack,
296 &GuardPageSize,
297 PAGE_GUARD | PAGE_READWRITE,
298 &Dummy);
299 if (!NT_SUCCESS(Status))
300 {
301 DPRINT1("Failure to create guard page\n");
302 return Status;
303 }
304
305 /* Update the Stack Limit keeping in mind the Guard Page */
306 InitialTeb->StackLimit = (PVOID)((ULONG_PTR)InitialTeb->StackLimit - GuardPageSize);
307 }
308
309 /* We are done! */
310 return STATUS_SUCCESS;
311 }
312
313 VOID
314 WINAPI
315 BasepFreeStack(HANDLE hProcess,
316 PINITIAL_TEB InitialTeb)
317 {
318 SIZE_T Dummy = 0;
319
320 /* Free the Stack */
321 NtFreeVirtualMemory(hProcess,
322 &InitialTeb->AllocatedStackBase,
323 &Dummy,
324 MEM_RELEASE);
325 }
326
327 /*
328 * Creates the Initial Context for a Thread or Fiber
329 */
330 VOID
331 WINAPI
332 BasepInitializeContext(IN PCONTEXT Context,
333 IN PVOID Parameter,
334 IN PVOID StartAddress,
335 IN PVOID StackAddress,
336 IN ULONG ContextType)
337 {
338 #ifdef _M_IX86
339 ULONG ContextFlags;
340 DPRINT("BasepInitializeContext: %p\n", Context);
341
342 /* Setup the Initial Win32 Thread Context */
343 Context->Eax = (ULONG)StartAddress;
344 Context->Ebx = (ULONG)Parameter;
345 Context->Esp = (ULONG)StackAddress;
346 /* The other registers are undefined */
347
348 /* Setup the Segments */
349 Context->SegFs = KGDT_R3_TEB | RPL_MASK;
350 Context->SegEs = KGDT_R3_DATA | RPL_MASK;
351 Context->SegDs = KGDT_R3_DATA | RPL_MASK;
352 Context->SegCs = KGDT_R3_CODE | RPL_MASK;
353 Context->SegSs = KGDT_R3_DATA | RPL_MASK;
354 Context->SegGs = 0;
355
356 /* Set the Context Flags */
357 ContextFlags = Context->ContextFlags;
358 Context->ContextFlags = CONTEXT_FULL;
359
360 /* Give it some room for the Parameter */
361 Context->Esp -= sizeof(PVOID);
362
363 /* Set the EFLAGS */
364 Context->EFlags = 0x3000; /* IOPL 3 */
365
366 /* What kind of context is being created? */
367 if (ContextType == 1)
368 {
369 /* For Threads */
370 Context->Eip = (ULONG)BaseThreadStartupThunk;
371 }
372 else if (ContextType == 2)
373 {
374 /* This is a fiber: make space for the return address */
375 Context->Esp -= sizeof(PVOID);
376 *((PVOID*)Context->Esp) = BaseFiberStartup;
377
378 /* Is FPU state required? */
379 Context->ContextFlags |= ContextFlags;
380 if (ContextFlags == CONTEXT_FLOATING_POINT)
381 {
382 /* Set an initial state */
383 Context->FloatSave.ControlWord = 0x27F;
384 Context->FloatSave.StatusWord = 0;
385 Context->FloatSave.TagWord = 0xFFFF;
386 Context->FloatSave.ErrorOffset = 0;
387 Context->FloatSave.ErrorSelector = 0;
388 Context->FloatSave.DataOffset = 0;
389 Context->FloatSave.DataSelector = 0;
390 if (SharedUserData->ProcessorFeatures[PF_XMMI_INSTRUCTIONS_AVAILABLE])
391 Context->Dr6 = 0x1F80;
392 }
393 }
394 else
395 {
396 /* For first thread in a Process */
397 Context->Eip = (ULONG)BaseProcessStartThunk;
398 }
399
400 #elif defined(_M_AMD64)
401 DPRINT("BasepInitializeContext: %p\n", Context);
402
403 /* Setup the Initial Win32 Thread Context */
404 Context->Rax = (ULONG_PTR)StartAddress;
405 Context->Rbx = (ULONG_PTR)Parameter;
406 Context->Rsp = (ULONG_PTR)StackAddress;
407 /* The other registers are undefined */
408
409 /* Setup the Segments */
410 Context->SegGs = KGDT64_R3_DATA | RPL_MASK;
411 Context->SegEs = KGDT64_R3_DATA | RPL_MASK;
412 Context->SegDs = KGDT64_R3_DATA | RPL_MASK;
413 Context->SegCs = KGDT64_R3_CODE | RPL_MASK;
414 Context->SegSs = KGDT64_R3_DATA | RPL_MASK;
415 Context->SegFs = KGDT64_R3_CMTEB | RPL_MASK;
416
417 /* Set the EFLAGS */
418 Context->EFlags = 0x3000; /* IOPL 3 */
419
420 if (ContextType == 1) /* For Threads */
421 {
422 Context->Rip = (ULONG_PTR)BaseThreadStartupThunk;
423 }
424 else if (ContextType == 2) /* For Fibers */
425 {
426 Context->Rip = (ULONG_PTR)BaseFiberStartup;
427 }
428 else /* For first thread in a Process */
429 {
430 Context->Rip = (ULONG_PTR)BaseProcessStartThunk;
431 }
432
433 /* Set the Context Flags */
434 Context->ContextFlags = CONTEXT_FULL;
435
436 /* Give it some room for the Parameter */
437 Context->Rsp -= sizeof(PVOID);
438 #else
439 #warning Unknown architecture
440 UNIMPLEMENTED;
441 DbgBreakPoint();
442 #endif
443 }
444
445 /*
446 * Checks if the privilege for Real-Time Priority is there
447 */
448 BOOLEAN
449 WINAPI
450 BasepCheckRealTimePrivilege(VOID)
451 {
452 return TRUE;
453 }
454
455 /*
456 * Maps an image file into a section
457 */
458 NTSTATUS
459 WINAPI
460 BasepMapFile(IN LPCWSTR lpApplicationName,
461 OUT PHANDLE hSection,
462 IN PUNICODE_STRING ApplicationName)
463 {
464 RTL_RELATIVE_NAME_U RelativeName;
465 OBJECT_ATTRIBUTES ObjectAttributes;
466 NTSTATUS Status;
467 HANDLE hFile = NULL;
468 IO_STATUS_BLOCK IoStatusBlock;
469
470 DPRINT("BasepMapFile\n");
471
472 /* Zero out the Relative Directory */
473 RelativeName.ContainingDirectory = NULL;
474
475 /* Find the application name */
476 if (!RtlDosPathNameToNtPathName_U(lpApplicationName,
477 ApplicationName,
478 NULL,
479 &RelativeName))
480 {
481 return STATUS_OBJECT_PATH_NOT_FOUND;
482 }
483
484 DPRINT("ApplicationName %wZ\n", ApplicationName);
485 DPRINT("RelativeName %wZ\n", &RelativeName.RelativeName);
486
487 /* Did we get a relative name? */
488 if (RelativeName.RelativeName.Length)
489 {
490 ApplicationName = &RelativeName.RelativeName;
491 }
492
493 /* Initialize the Object Attributes */
494 InitializeObjectAttributes(&ObjectAttributes,
495 ApplicationName,
496 OBJ_CASE_INSENSITIVE,
497 RelativeName.ContainingDirectory,
498 NULL);
499
500 /* Try to open the executable */
501 Status = NtOpenFile(&hFile,
502 SYNCHRONIZE | FILE_EXECUTE | FILE_READ_DATA,
503 &ObjectAttributes,
504 &IoStatusBlock,
505 FILE_SHARE_DELETE | FILE_SHARE_READ,
506 FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE);
507 if (!NT_SUCCESS(Status))
508 {
509 DPRINT1("Failed to open file\n");
510 BaseSetLastNTError(Status);
511 return Status;
512 }
513
514 /* Create a section for this file */
515 Status = NtCreateSection(hSection,
516 SECTION_ALL_ACCESS,
517 NULL,
518 NULL,
519 PAGE_EXECUTE,
520 SEC_IMAGE,
521 hFile);
522 NtClose(hFile);
523
524 /* Return status */
525 DPRINT("Section: %lx for file: %lx\n", *hSection, hFile);
526 return Status;
527 }
528
529 /*
530 * @unimplemented
531 */
532 BOOL
533 WINAPI
534 BaseCheckRunApp(IN DWORD Unknown1,
535 IN DWORD Unknown2,
536 IN DWORD Unknown3,
537 IN DWORD Unknown4,
538 IN DWORD Unknown5,
539 IN DWORD Unknown6,
540 IN DWORD Unknown7,
541 IN DWORD Unknown8,
542 IN DWORD Unknown9,
543 IN DWORD Unknown10)
544 {
545 STUB;
546 return FALSE;
547 }
548
549 /*
550 * @unimplemented
551 */
552 BOOL
553 WINAPI
554 BasepCheckWinSaferRestrictions(IN DWORD Unknown1,
555 IN DWORD Unknown2,
556 IN DWORD Unknown3,
557 IN DWORD Unknown4,
558 IN DWORD Unknown5,
559 IN DWORD Unknown6)
560 {
561 STUB;
562 return FALSE;
563 }