Sync with trunk head (part 1 of x)
[reactos.git] / dll / ntdll / rtl / libsupp.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS NT User-Mode DLL
4 * FILE: lib/ntdll/rtl/libsup.c
5 * PURPOSE: RTL Support Routines
6 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
7 * Gunnar Dalsnes
8 */
9
10 /* INCLUDES *****************************************************************/
11
12 #include <ntdll.h>
13 #define NDEBUG
14 #include <debug.h>
15
16 SIZE_T RtlpAllocDeallocQueryBufferSize = PAGE_SIZE;
17 PTEB LdrpTopLevelDllBeingLoadedTeb = NULL;
18
19 /* FUNCTIONS ***************************************************************/
20
21 /*
22 * @implemented
23 */
24 ULONG
25 NTAPI
26 RtlWalkFrameChain(OUT PVOID *Callers,
27 IN ULONG Count,
28 IN ULONG Flags)
29 {
30 /* Not implemented for user-mode */
31 return 0;
32 }
33
34 BOOLEAN
35 NTAPI
36 RtlpCheckForActiveDebugger(VOID)
37 {
38 /* Return the flag in the PEB */
39 return NtCurrentPeb()->BeingDebugged;
40 }
41
42 BOOLEAN
43 NTAPI
44 RtlpSetInDbgPrint(VOID)
45 {
46 /* Check if it's already set and return TRUE if so */
47 if (NtCurrentTeb()->InDbgPrint) return TRUE;
48
49 /* Set it and return */
50 NtCurrentTeb()->InDbgPrint = TRUE;
51 return FALSE;
52 }
53
54 VOID
55 NTAPI
56 RtlpClearInDbgPrint(VOID)
57 {
58 /* Clear the flag */
59 NtCurrentTeb()->InDbgPrint = FALSE;
60 }
61
62 KPROCESSOR_MODE
63 NTAPI
64 RtlpGetMode()
65 {
66 return UserMode;
67 }
68
69 /*
70 * @implemented
71 */
72 PPEB
73 NTAPI
74 RtlGetCurrentPeb(VOID)
75 {
76 return NtCurrentPeb();
77 }
78
79 /*
80 * @implemented
81 */
82 VOID NTAPI
83 RtlAcquirePebLock(VOID)
84 {
85 PPEB Peb = NtCurrentPeb ();
86 RtlEnterCriticalSection(Peb->FastPebLock);
87 }
88
89 /*
90 * @implemented
91 */
92 VOID NTAPI
93 RtlReleasePebLock(VOID)
94 {
95 PPEB Peb = NtCurrentPeb ();
96 RtlLeaveCriticalSection(Peb->FastPebLock);
97 }
98
99 /*
100 * @implemented
101 */
102 ULONG
103 NTAPI
104 RtlGetNtGlobalFlags(VOID)
105 {
106 PPEB pPeb = NtCurrentPeb();
107 return pPeb->NtGlobalFlag;
108 }
109
110 NTSTATUS
111 NTAPI
112 RtlDeleteHeapLock(
113 PRTL_CRITICAL_SECTION CriticalSection)
114 {
115 return RtlDeleteCriticalSection(CriticalSection);
116 }
117
118 NTSTATUS
119 NTAPI
120 RtlEnterHeapLock(
121 PRTL_CRITICAL_SECTION CriticalSection)
122 {
123 return RtlEnterCriticalSection(CriticalSection);
124 }
125
126 NTSTATUS
127 NTAPI
128 RtlInitializeHeapLock(
129 PRTL_CRITICAL_SECTION CriticalSection)
130 {
131 return RtlInitializeCriticalSection(CriticalSection);
132 }
133
134 NTSTATUS
135 NTAPI
136 RtlLeaveHeapLock(
137 PRTL_CRITICAL_SECTION CriticalSection)
138 {
139 return RtlLeaveCriticalSection(CriticalSection );
140 }
141
142 PVOID
143 NTAPI
144 RtlpAllocateMemory(UINT Bytes,
145 ULONG Tag)
146 {
147 UNREFERENCED_PARAMETER(Tag);
148
149 return RtlAllocateHeap(RtlGetProcessHeap(),
150 0,
151 Bytes);
152 }
153
154
155 VOID
156 NTAPI
157 RtlpFreeMemory(PVOID Mem,
158 ULONG Tag)
159 {
160 UNREFERENCED_PARAMETER(Tag);
161
162 RtlFreeHeap(RtlGetProcessHeap(),
163 0,
164 Mem);
165 }
166
167
168 #if DBG
169 VOID FASTCALL
170 CHECK_PAGED_CODE_RTL(char *file, int line)
171 {
172 /* meaningless in user mode */
173 }
174 #endif
175
176 BOOLEAN
177 NTAPI
178 RtlpHandleDpcStackException(IN PEXCEPTION_REGISTRATION_RECORD RegistrationFrame,
179 IN ULONG_PTR RegistrationFrameEnd,
180 IN OUT PULONG_PTR StackLow,
181 IN OUT PULONG_PTR StackHigh)
182 {
183 /* There's no such thing as a DPC stack in user-mode */
184 return FALSE;
185 }
186
187 VOID
188 NTAPI
189 RtlpCheckLogException(IN PEXCEPTION_RECORD ExceptionRecord,
190 IN PCONTEXT ContextRecord,
191 IN PVOID ContextData,
192 IN ULONG Size)
193 {
194 /* Exception logging is not done in user-mode */
195 }
196
197 BOOLEAN
198 NTAPI
199 RtlpCaptureStackLimits(IN ULONG_PTR Ebp,
200 IN ULONG_PTR *StackBegin,
201 IN ULONG_PTR *StackEnd)
202 {
203 /* FIXME: Verify */
204 *StackBegin = (ULONG_PTR)NtCurrentTeb()->NtTib.StackLimit;
205 *StackEnd = (ULONG_PTR)NtCurrentTeb()->NtTib.StackBase;
206 return TRUE;
207 }
208
209 #ifdef _AMD64_
210 VOID
211 NTAPI
212 RtlpGetStackLimits(
213 OUT PULONG_PTR LowLimit,
214 OUT PULONG_PTR HighLimit)
215 {
216 *LowLimit = (ULONG_PTR)NtCurrentTeb()->NtTib.StackLimit;
217 *HighLimit = (ULONG_PTR)NtCurrentTeb()->NtTib.StackBase;
218 return;
219 }
220 #endif
221
222 BOOLEAN
223 NTAPI
224 RtlIsThreadWithinLoaderCallout(VOID)
225 {
226 return LdrpTopLevelDllBeingLoadedTeb == NtCurrentTeb();
227 }
228
229 /* RTL Atom Tables ************************************************************/
230
231 typedef struct _RTL_ATOM_HANDLE
232 {
233 RTL_HANDLE_TABLE_ENTRY Handle;
234 PRTL_ATOM_TABLE_ENTRY AtomEntry;
235 } RTL_ATOM_HANDLE, *PRTL_ATOM_HANDLE;
236
237 NTSTATUS
238 RtlpInitAtomTableLock(PRTL_ATOM_TABLE AtomTable)
239 {
240 RtlInitializeCriticalSection(&AtomTable->CriticalSection);
241 return STATUS_SUCCESS;
242 }
243
244
245 VOID
246 RtlpDestroyAtomTableLock(PRTL_ATOM_TABLE AtomTable)
247 {
248 RtlDeleteCriticalSection(&AtomTable->CriticalSection);
249 }
250
251
252 BOOLEAN
253 RtlpLockAtomTable(PRTL_ATOM_TABLE AtomTable)
254 {
255 RtlEnterCriticalSection(&AtomTable->CriticalSection);
256 return TRUE;
257 }
258
259
260 VOID
261 RtlpUnlockAtomTable(PRTL_ATOM_TABLE AtomTable)
262 {
263 RtlLeaveCriticalSection(&AtomTable->CriticalSection);
264 }
265
266
267 /* handle functions */
268
269 BOOLEAN
270 RtlpCreateAtomHandleTable(PRTL_ATOM_TABLE AtomTable)
271 {
272 RtlInitializeHandleTable(0xCFFF,
273 sizeof(RTL_ATOM_HANDLE),
274 &AtomTable->RtlHandleTable);
275
276 return TRUE;
277 }
278
279 VOID
280 RtlpDestroyAtomHandleTable(PRTL_ATOM_TABLE AtomTable)
281 {
282 RtlDestroyHandleTable(&AtomTable->RtlHandleTable);
283 }
284
285 PRTL_ATOM_TABLE
286 RtlpAllocAtomTable(ULONG Size)
287 {
288 return (PRTL_ATOM_TABLE)RtlAllocateHeap(RtlGetProcessHeap(),
289 HEAP_ZERO_MEMORY,
290 Size);
291 }
292
293 VOID
294 RtlpFreeAtomTable(PRTL_ATOM_TABLE AtomTable)
295 {
296 RtlFreeHeap(RtlGetProcessHeap(),
297 0,
298 AtomTable);
299 }
300
301 PRTL_ATOM_TABLE_ENTRY
302 RtlpAllocAtomTableEntry(ULONG Size)
303 {
304 return (PRTL_ATOM_TABLE_ENTRY)RtlAllocateHeap(RtlGetProcessHeap(),
305 HEAP_ZERO_MEMORY,
306 Size);
307 }
308
309 VOID
310 RtlpFreeAtomTableEntry(PRTL_ATOM_TABLE_ENTRY Entry)
311 {
312 RtlFreeHeap(RtlGetProcessHeap(),
313 0,
314 Entry);
315 }
316
317 VOID
318 RtlpFreeAtomHandle(PRTL_ATOM_TABLE AtomTable, PRTL_ATOM_TABLE_ENTRY Entry)
319 {
320 PRTL_HANDLE_TABLE_ENTRY RtlHandleEntry;
321
322 if (RtlIsValidIndexHandle(&AtomTable->RtlHandleTable,
323 (ULONG)Entry->HandleIndex,
324 &RtlHandleEntry))
325 {
326 RtlFreeHandle(&AtomTable->RtlHandleTable,
327 RtlHandleEntry);
328 }
329 }
330
331 BOOLEAN
332 RtlpCreateAtomHandle(PRTL_ATOM_TABLE AtomTable, PRTL_ATOM_TABLE_ENTRY Entry)
333 {
334 ULONG HandleIndex;
335 PRTL_HANDLE_TABLE_ENTRY RtlHandle;
336
337 RtlHandle = RtlAllocateHandle(&AtomTable->RtlHandleTable,
338 &HandleIndex);
339 if (RtlHandle != NULL)
340 {
341 PRTL_ATOM_HANDLE AtomHandle = (PRTL_ATOM_HANDLE)RtlHandle;
342
343 /* FIXME - Handle Indexes >= 0xC000 ?! */
344 if (HandleIndex < 0xC000)
345 {
346 Entry->HandleIndex = (USHORT)HandleIndex;
347 Entry->Atom = 0xC000 + (USHORT)HandleIndex;
348
349 AtomHandle->AtomEntry = Entry;
350 AtomHandle->Handle.Flags = RTL_HANDLE_VALID;
351
352 return TRUE;
353 }
354 else
355 {
356 /* set the valid flag, otherwise RtlFreeHandle will fail! */
357 AtomHandle->Handle.Flags = RTL_HANDLE_VALID;
358
359 RtlFreeHandle(&AtomTable->RtlHandleTable,
360 RtlHandle);
361 }
362 }
363
364 return FALSE;
365 }
366
367 PRTL_ATOM_TABLE_ENTRY
368 RtlpGetAtomEntry(PRTL_ATOM_TABLE AtomTable, ULONG Index)
369 {
370 PRTL_HANDLE_TABLE_ENTRY RtlHandle;
371
372 if (RtlIsValidIndexHandle(&AtomTable->RtlHandleTable,
373 Index,
374 &RtlHandle))
375 {
376 PRTL_ATOM_HANDLE AtomHandle = (PRTL_ATOM_HANDLE)RtlHandle;
377
378 return AtomHandle->AtomEntry;
379 }
380
381 return NULL;
382 }
383
384
385 /*
386 * Ldr Resource support code
387 */
388
389 IMAGE_RESOURCE_DIRECTORY *find_entry_by_name( IMAGE_RESOURCE_DIRECTORY *dir,
390 LPCWSTR name, void *root,
391 int want_dir );
392 IMAGE_RESOURCE_DIRECTORY *find_entry_by_id( IMAGE_RESOURCE_DIRECTORY *dir,
393 WORD id, void *root, int want_dir );
394 IMAGE_RESOURCE_DIRECTORY *find_first_entry( IMAGE_RESOURCE_DIRECTORY *dir,
395 void *root, int want_dir );
396 int push_language( USHORT *list, ULONG pos, WORD lang );
397
398 /**********************************************************************
399 * find_entry
400 *
401 * Find a resource entry
402 */
403 NTSTATUS find_entry( PVOID BaseAddress, LDR_RESOURCE_INFO *info,
404 ULONG level, void **ret, int want_dir )
405 {
406 ULONG size;
407 void *root;
408 IMAGE_RESOURCE_DIRECTORY *resdirptr;
409 USHORT list[9]; /* list of languages to try */
410 int i, pos = 0;
411 LCID user_lcid, system_lcid;
412
413 root = RtlImageDirectoryEntryToData( BaseAddress, TRUE, IMAGE_DIRECTORY_ENTRY_RESOURCE, &size );
414 if (!root) return STATUS_RESOURCE_DATA_NOT_FOUND;
415 resdirptr = root;
416
417 if (!level--) goto done;
418 if (!(*ret = find_entry_by_name( resdirptr, (LPCWSTR)info->Type, root, want_dir || level )))
419 return STATUS_RESOURCE_TYPE_NOT_FOUND;
420 if (!level--) return STATUS_SUCCESS;
421
422 resdirptr = *ret;
423 if (!(*ret = find_entry_by_name( resdirptr, (LPCWSTR)info->Name, root, want_dir || level )))
424 return STATUS_RESOURCE_NAME_NOT_FOUND;
425 if (!level--) return STATUS_SUCCESS;
426 if (level) return STATUS_INVALID_PARAMETER; /* level > 3 */
427
428 /* 1. specified language */
429 pos = push_language( list, pos, info->Language );
430
431 /* 2. specified language with neutral sublanguage */
432 pos = push_language( list, pos, MAKELANGID( PRIMARYLANGID(info->Language), SUBLANG_NEUTRAL ) );
433
434 /* 3. neutral language with neutral sublanguage */
435 pos = push_language( list, pos, MAKELANGID( LANG_NEUTRAL, SUBLANG_NEUTRAL ) );
436
437 /* if no explicitly specified language, try some defaults */
438 if (PRIMARYLANGID(info->Language) == LANG_NEUTRAL)
439 {
440 /* user defaults, unless SYS_DEFAULT sublanguage specified */
441 if (SUBLANGID(info->Language) != SUBLANG_SYS_DEFAULT)
442 {
443 /* 4. current thread locale language */
444 pos = push_language( list, pos, LANGIDFROMLCID(NtCurrentTeb()->CurrentLocale) );
445
446 if (NT_SUCCESS(NtQueryDefaultLocale(TRUE, &user_lcid)))
447 {
448 /* 5. user locale language */
449 pos = push_language( list, pos, LANGIDFROMLCID(user_lcid) );
450
451 /* 6. user locale language with neutral sublanguage */
452 pos = push_language( list, pos, MAKELANGID( PRIMARYLANGID(user_lcid), SUBLANG_NEUTRAL ) );
453 }
454 }
455
456 /* now system defaults */
457
458 if (NT_SUCCESS(NtQueryDefaultLocale(FALSE, &system_lcid)))
459 {
460 /* 7. system locale language */
461 pos = push_language( list, pos, LANGIDFROMLCID( system_lcid ) );
462
463 /* 8. system locale language with neutral sublanguage */
464 pos = push_language( list, pos, MAKELANGID( PRIMARYLANGID(system_lcid), SUBLANG_NEUTRAL ) );
465 }
466
467 /* 9. English */
468 pos = push_language( list, pos, MAKELANGID( LANG_ENGLISH, SUBLANG_DEFAULT ) );
469 }
470
471 resdirptr = *ret;
472 for (i = 0; i < pos; i++)
473 if ((*ret = find_entry_by_id( resdirptr, list[i], root, want_dir ))) return STATUS_SUCCESS;
474
475 /* if no explicitly specified language, return the first entry */
476 if (PRIMARYLANGID(info->Language) == LANG_NEUTRAL)
477 {
478 if ((*ret = find_first_entry( resdirptr, root, want_dir ))) return STATUS_SUCCESS;
479 }
480 return STATUS_RESOURCE_LANG_NOT_FOUND;
481
482 done:
483 *ret = resdirptr;
484 return STATUS_SUCCESS;
485 }