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