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