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