[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 */
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 InitialTeb->PreviousStackBase = NULL;
261 InitialTeb->PreviousStackLimit = NULL;
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 ULONG 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 _M_IX86
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 #else
380 #warning Unknown architecture
381 UNIMPLEMENTED;
382 DbgBreakPoint();
383 #endif
384 }
385
386 /*
387 * Checks if the privilege for Real-Time Priority is there
388 */
389 BOOLEAN
390 WINAPI
391 BasepCheckRealTimePrivilege(VOID)
392 {
393 return TRUE;
394 }
395
396 /*
397 * Maps an image file into a section
398 */
399 NTSTATUS
400 WINAPI
401 BasepMapFile(IN LPCWSTR lpApplicationName,
402 OUT PHANDLE hSection,
403 IN PUNICODE_STRING ApplicationName)
404 {
405 CURDIR RelativeName;
406 OBJECT_ATTRIBUTES ObjectAttributes;
407 NTSTATUS Status;
408 HANDLE hFile = NULL;
409 IO_STATUS_BLOCK IoStatusBlock;
410
411 DPRINT("BasepMapFile\n");
412
413 /* Zero out the Relative Directory */
414 RelativeName.Handle = NULL;
415
416 /* Find the application name */
417 if (!RtlDosPathNameToNtPathName_U(lpApplicationName,
418 ApplicationName,
419 NULL,
420 &RelativeName))
421 {
422 return STATUS_OBJECT_PATH_NOT_FOUND;
423 }
424
425 DPRINT("ApplicationName %wZ\n", ApplicationName);
426 DPRINT("RelativeName %wZ\n", &RelativeName.DosPath);
427
428 /* Did we get a relative name? */
429 if (RelativeName.DosPath.Length)
430 {
431 ApplicationName = &RelativeName.DosPath;
432 }
433
434 /* Initialize the Object Attributes */
435 InitializeObjectAttributes(&ObjectAttributes,
436 ApplicationName,
437 OBJ_CASE_INSENSITIVE,
438 RelativeName.Handle,
439 NULL);
440
441 /* Try to open the executable */
442 Status = NtOpenFile(&hFile,
443 SYNCHRONIZE | FILE_EXECUTE | FILE_READ_DATA,
444 &ObjectAttributes,
445 &IoStatusBlock,
446 FILE_SHARE_DELETE | FILE_SHARE_READ,
447 FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE);
448 if (!NT_SUCCESS(Status))
449 {
450 DPRINT1("Failed to open file\n");
451 SetLastErrorByStatus(Status);
452 return Status;
453 }
454
455 /* Create a section for this file */
456 Status = NtCreateSection(hSection,
457 SECTION_ALL_ACCESS,
458 NULL,
459 NULL,
460 PAGE_EXECUTE,
461 SEC_IMAGE,
462 hFile);
463 NtClose(hFile);
464
465 /* Return status */
466 DPRINT("Section: %lx for file: %lx\n", *hSection, hFile);
467 return Status;
468 }