Branching for 0.3.15 release after two days of no response from a certain sphere...
[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 #ifndef _M_AMD64
22 // FIXME: Why "Not implemented"???
23 /*
24 * @implemented
25 */
26 ULONG
27 NTAPI
28 RtlWalkFrameChain(OUT PVOID *Callers,
29 IN ULONG Count,
30 IN ULONG Flags)
31 {
32 /* Not implemented for user-mode */
33 return 0;
34 }
35 #endif
36
37 BOOLEAN
38 NTAPI
39 RtlpCheckForActiveDebugger(VOID)
40 {
41 /* Return the flag in the PEB */
42 return NtCurrentPeb()->BeingDebugged;
43 }
44
45 BOOLEAN
46 NTAPI
47 RtlpSetInDbgPrint(VOID)
48 {
49 /* Check if it's already set and return TRUE if so */
50 if (NtCurrentTeb()->InDbgPrint) return TRUE;
51
52 /* Set it and return */
53 NtCurrentTeb()->InDbgPrint = TRUE;
54 return FALSE;
55 }
56
57 VOID
58 NTAPI
59 RtlpClearInDbgPrint(VOID)
60 {
61 /* Clear the flag */
62 NtCurrentTeb()->InDbgPrint = FALSE;
63 }
64
65 KPROCESSOR_MODE
66 NTAPI
67 RtlpGetMode()
68 {
69 return UserMode;
70 }
71
72 /*
73 * @implemented
74 */
75 PPEB
76 NTAPI
77 RtlGetCurrentPeb(VOID)
78 {
79 return NtCurrentPeb();
80 }
81
82 /*
83 * @implemented
84 */
85 VOID NTAPI
86 RtlAcquirePebLock(VOID)
87 {
88 PPEB Peb = NtCurrentPeb ();
89 RtlEnterCriticalSection(Peb->FastPebLock);
90 }
91
92 /*
93 * @implemented
94 */
95 VOID NTAPI
96 RtlReleasePebLock(VOID)
97 {
98 PPEB Peb = NtCurrentPeb ();
99 RtlLeaveCriticalSection(Peb->FastPebLock);
100 }
101
102 /*
103 * @implemented
104 */
105 ULONG
106 NTAPI
107 RtlGetNtGlobalFlags(VOID)
108 {
109 PPEB pPeb = NtCurrentPeb();
110 return pPeb->NtGlobalFlag;
111 }
112
113 NTSTATUS
114 NTAPI
115 RtlDeleteHeapLock(IN OUT PHEAP_LOCK Lock)
116 {
117 return RtlDeleteCriticalSection(&Lock->CriticalSection);
118 }
119
120 NTSTATUS
121 NTAPI
122 RtlEnterHeapLock(IN OUT PHEAP_LOCK Lock, IN BOOLEAN Exclusive)
123 {
124 UNREFERENCED_PARAMETER(Exclusive);
125
126 return RtlEnterCriticalSection(&Lock->CriticalSection);
127 }
128
129 NTSTATUS
130 NTAPI
131 RtlInitializeHeapLock(IN OUT PHEAP_LOCK *Lock)
132 {
133 return RtlInitializeCriticalSection(&(*Lock)->CriticalSection);
134 }
135
136 NTSTATUS
137 NTAPI
138 RtlLeaveHeapLock(IN OUT PHEAP_LOCK Lock)
139 {
140 return RtlLeaveCriticalSection(&Lock->CriticalSection);
141 }
142
143 PVOID
144 NTAPI
145 RtlpAllocateMemory(UINT Bytes,
146 ULONG Tag)
147 {
148 UNREFERENCED_PARAMETER(Tag);
149
150 return RtlAllocateHeap(RtlGetProcessHeap(),
151 0,
152 Bytes);
153 }
154
155
156 VOID
157 NTAPI
158 RtlpFreeMemory(PVOID Mem,
159 ULONG Tag)
160 {
161 UNREFERENCED_PARAMETER(Tag);
162
163 RtlFreeHeap(RtlGetProcessHeap(),
164 0,
165 Mem);
166 }
167
168
169 #if DBG
170 VOID FASTCALL
171 CHECK_PAGED_CODE_RTL(char *file, int line)
172 {
173 /* meaningless in user mode */
174 }
175 #endif
176
177 BOOLEAN
178 NTAPI
179 RtlpHandleDpcStackException(IN PEXCEPTION_REGISTRATION_RECORD RegistrationFrame,
180 IN ULONG_PTR RegistrationFrameEnd,
181 IN OUT PULONG_PTR StackLow,
182 IN OUT PULONG_PTR StackHigh)
183 {
184 /* There's no such thing as a DPC stack in user-mode */
185 return FALSE;
186 }
187
188 VOID
189 NTAPI
190 RtlpCheckLogException(IN PEXCEPTION_RECORD ExceptionRecord,
191 IN PCONTEXT ContextRecord,
192 IN PVOID ContextData,
193 IN ULONG Size)
194 {
195 /* Exception logging is not done in user-mode */
196 }
197
198 BOOLEAN
199 NTAPI
200 RtlpCaptureStackLimits(IN ULONG_PTR Ebp,
201 IN ULONG_PTR *StackBegin,
202 IN ULONG_PTR *StackEnd)
203 {
204 /* FIXME: Verify */
205 *StackBegin = (ULONG_PTR)NtCurrentTeb()->NtTib.StackLimit;
206 *StackEnd = (ULONG_PTR)NtCurrentTeb()->NtTib.StackBase;
207 return TRUE;
208 }
209
210 #ifdef _AMD64_
211 VOID
212 NTAPI
213 RtlpGetStackLimits(
214 OUT PULONG_PTR LowLimit,
215 OUT PULONG_PTR HighLimit)
216 {
217 *LowLimit = (ULONG_PTR)NtCurrentTeb()->NtTib.StackLimit;
218 *HighLimit = (ULONG_PTR)NtCurrentTeb()->NtTib.StackBase;
219 return;
220 }
221 #endif
222
223 BOOLEAN
224 NTAPI
225 RtlIsThreadWithinLoaderCallout(VOID)
226 {
227 return LdrpTopLevelDllBeingLoadedTeb == NtCurrentTeb();
228 }
229
230 /* RTL Atom Tables ************************************************************/
231
232 typedef struct _RTL_ATOM_HANDLE
233 {
234 RTL_HANDLE_TABLE_ENTRY Handle;
235 PRTL_ATOM_TABLE_ENTRY AtomEntry;
236 } RTL_ATOM_HANDLE, *PRTL_ATOM_HANDLE;
237
238 NTSTATUS
239 RtlpInitAtomTableLock(PRTL_ATOM_TABLE AtomTable)
240 {
241 RtlInitializeCriticalSection(&AtomTable->CriticalSection);
242 return STATUS_SUCCESS;
243 }
244
245
246 VOID
247 RtlpDestroyAtomTableLock(PRTL_ATOM_TABLE AtomTable)
248 {
249 RtlDeleteCriticalSection(&AtomTable->CriticalSection);
250 }
251
252
253 BOOLEAN
254 RtlpLockAtomTable(PRTL_ATOM_TABLE AtomTable)
255 {
256 RtlEnterCriticalSection(&AtomTable->CriticalSection);
257 return TRUE;
258 }
259
260
261 VOID
262 RtlpUnlockAtomTable(PRTL_ATOM_TABLE AtomTable)
263 {
264 RtlLeaveCriticalSection(&AtomTable->CriticalSection);
265 }
266
267
268 /* handle functions */
269
270 BOOLEAN
271 RtlpCreateAtomHandleTable(PRTL_ATOM_TABLE AtomTable)
272 {
273 RtlInitializeHandleTable(0xCFFF,
274 sizeof(RTL_ATOM_HANDLE),
275 &AtomTable->RtlHandleTable);
276
277 return TRUE;
278 }
279
280 VOID
281 RtlpDestroyAtomHandleTable(PRTL_ATOM_TABLE AtomTable)
282 {
283 RtlDestroyHandleTable(&AtomTable->RtlHandleTable);
284 }
285
286 PRTL_ATOM_TABLE
287 RtlpAllocAtomTable(ULONG Size)
288 {
289 return (PRTL_ATOM_TABLE)RtlAllocateHeap(RtlGetProcessHeap(),
290 HEAP_ZERO_MEMORY,
291 Size);
292 }
293
294 VOID
295 RtlpFreeAtomTable(PRTL_ATOM_TABLE AtomTable)
296 {
297 RtlFreeHeap(RtlGetProcessHeap(),
298 0,
299 AtomTable);
300 }
301
302 PRTL_ATOM_TABLE_ENTRY
303 RtlpAllocAtomTableEntry(ULONG Size)
304 {
305 return (PRTL_ATOM_TABLE_ENTRY)RtlAllocateHeap(RtlGetProcessHeap(),
306 HEAP_ZERO_MEMORY,
307 Size);
308 }
309
310 VOID
311 RtlpFreeAtomTableEntry(PRTL_ATOM_TABLE_ENTRY Entry)
312 {
313 RtlFreeHeap(RtlGetProcessHeap(),
314 0,
315 Entry);
316 }
317
318 VOID
319 RtlpFreeAtomHandle(PRTL_ATOM_TABLE AtomTable, PRTL_ATOM_TABLE_ENTRY Entry)
320 {
321 PRTL_HANDLE_TABLE_ENTRY RtlHandleEntry;
322
323 if (RtlIsValidIndexHandle(&AtomTable->RtlHandleTable,
324 (ULONG)Entry->HandleIndex,
325 &RtlHandleEntry))
326 {
327 RtlFreeHandle(&AtomTable->RtlHandleTable,
328 RtlHandleEntry);
329 }
330 }
331
332 BOOLEAN
333 RtlpCreateAtomHandle(PRTL_ATOM_TABLE AtomTable, PRTL_ATOM_TABLE_ENTRY Entry)
334 {
335 ULONG HandleIndex;
336 PRTL_HANDLE_TABLE_ENTRY RtlHandle;
337
338 RtlHandle = RtlAllocateHandle(&AtomTable->RtlHandleTable,
339 &HandleIndex);
340 if (RtlHandle != NULL)
341 {
342 PRTL_ATOM_HANDLE AtomHandle = (PRTL_ATOM_HANDLE)RtlHandle;
343
344 /* FIXME - Handle Indexes >= 0xC000 ?! */
345 if (HandleIndex < 0xC000)
346 {
347 Entry->HandleIndex = (USHORT)HandleIndex;
348 Entry->Atom = 0xC000 + (USHORT)HandleIndex;
349
350 AtomHandle->AtomEntry = Entry;
351 AtomHandle->Handle.Flags = RTL_HANDLE_VALID;
352
353 return TRUE;
354 }
355 else
356 {
357 /* set the valid flag, otherwise RtlFreeHandle will fail! */
358 AtomHandle->Handle.Flags = RTL_HANDLE_VALID;
359
360 RtlFreeHandle(&AtomTable->RtlHandleTable,
361 RtlHandle);
362 }
363 }
364
365 return FALSE;
366 }
367
368 PRTL_ATOM_TABLE_ENTRY
369 RtlpGetAtomEntry(PRTL_ATOM_TABLE AtomTable, ULONG Index)
370 {
371 PRTL_HANDLE_TABLE_ENTRY RtlHandle;
372
373 if (RtlIsValidIndexHandle(&AtomTable->RtlHandleTable,
374 Index,
375 &RtlHandle))
376 {
377 PRTL_ATOM_HANDLE AtomHandle = (PRTL_ATOM_HANDLE)RtlHandle;
378
379 return AtomHandle->AtomEntry;
380 }
381
382 return NULL;
383 }
384
385
386 /*
387 * Ldr Resource support code
388 */
389
390 IMAGE_RESOURCE_DIRECTORY *find_entry_by_name( IMAGE_RESOURCE_DIRECTORY *dir,
391 LPCWSTR name, void *root,
392 int want_dir );
393 IMAGE_RESOURCE_DIRECTORY *find_entry_by_id( IMAGE_RESOURCE_DIRECTORY *dir,
394 WORD id, void *root, int want_dir );
395 IMAGE_RESOURCE_DIRECTORY *find_first_entry( IMAGE_RESOURCE_DIRECTORY *dir,
396 void *root, int want_dir );
397 int push_language( USHORT *list, ULONG pos, WORD lang );
398
399 /**********************************************************************
400 * find_entry
401 *
402 * Find a resource entry
403 */
404 NTSTATUS find_entry( PVOID BaseAddress, LDR_RESOURCE_INFO *info,
405 ULONG level, void **ret, int want_dir )
406 {
407 ULONG size;
408 void *root;
409 IMAGE_RESOURCE_DIRECTORY *resdirptr;
410 USHORT list[9]; /* list of languages to try */
411 int i, pos = 0;
412 LCID user_lcid, system_lcid;
413
414 root = RtlImageDirectoryEntryToData( BaseAddress, TRUE, IMAGE_DIRECTORY_ENTRY_RESOURCE, &size );
415 if (!root) return STATUS_RESOURCE_DATA_NOT_FOUND;
416 resdirptr = root;
417
418 if (!level--) goto done;
419 if (!(*ret = find_entry_by_name( resdirptr, (LPCWSTR)info->Type, root, want_dir || level )))
420 return STATUS_RESOURCE_TYPE_NOT_FOUND;
421 if (!level--) return STATUS_SUCCESS;
422
423 resdirptr = *ret;
424 if (!(*ret = find_entry_by_name( resdirptr, (LPCWSTR)info->Name, root, want_dir || level )))
425 return STATUS_RESOURCE_NAME_NOT_FOUND;
426 if (!level--) return STATUS_SUCCESS;
427 if (level) return STATUS_INVALID_PARAMETER; /* level > 3 */
428
429 /* 1. specified language */
430 pos = push_language( list, pos, info->Language );
431
432 /* 2. specified language with neutral sublanguage */
433 pos = push_language( list, pos, MAKELANGID( PRIMARYLANGID(info->Language), SUBLANG_NEUTRAL ) );
434
435 /* 3. neutral language with neutral sublanguage */
436 pos = push_language( list, pos, MAKELANGID( LANG_NEUTRAL, SUBLANG_NEUTRAL ) );
437
438 /* if no explicitly specified language, try some defaults */
439 if (PRIMARYLANGID(info->Language) == LANG_NEUTRAL)
440 {
441 /* user defaults, unless SYS_DEFAULT sublanguage specified */
442 if (SUBLANGID(info->Language) != SUBLANG_SYS_DEFAULT)
443 {
444 /* 4. current thread locale language */
445 pos = push_language( list, pos, LANGIDFROMLCID(NtCurrentTeb()->CurrentLocale) );
446
447 if (NT_SUCCESS(NtQueryDefaultLocale(TRUE, &user_lcid)))
448 {
449 /* 5. user locale language */
450 pos = push_language( list, pos, LANGIDFROMLCID(user_lcid) );
451
452 /* 6. user locale language with neutral sublanguage */
453 pos = push_language( list, pos, MAKELANGID( PRIMARYLANGID(user_lcid), SUBLANG_NEUTRAL ) );
454 }
455 }
456
457 /* now system defaults */
458
459 if (NT_SUCCESS(NtQueryDefaultLocale(FALSE, &system_lcid)))
460 {
461 /* 7. system locale language */
462 pos = push_language( list, pos, LANGIDFROMLCID( system_lcid ) );
463
464 /* 8. system locale language with neutral sublanguage */
465 pos = push_language( list, pos, MAKELANGID( PRIMARYLANGID(system_lcid), SUBLANG_NEUTRAL ) );
466 }
467
468 /* 9. English */
469 pos = push_language( list, pos, MAKELANGID( LANG_ENGLISH, SUBLANG_DEFAULT ) );
470 }
471
472 resdirptr = *ret;
473 for (i = 0; i < pos; i++)
474 if ((*ret = find_entry_by_id( resdirptr, list[i], root, want_dir ))) return STATUS_SUCCESS;
475
476 /* if no explicitly specified language, return the first entry */
477 if (PRIMARYLANGID(info->Language) == LANG_NEUTRAL)
478 {
479 if ((*ret = find_first_entry( resdirptr, root, want_dir ))) return STATUS_SUCCESS;
480 }
481 return STATUS_RESOURCE_LANG_NOT_FOUND;
482
483 done:
484 *ret = resdirptr;
485 return STATUS_SUCCESS;
486 }
487
488 /*
489 * @implemented
490 */
491 PVOID NTAPI
492 RtlPcToFileHeader(IN PVOID PcValue,
493 PVOID* BaseOfImage)
494 {
495 PLIST_ENTRY ModuleListHead;
496 PLIST_ENTRY Entry;
497 PLDR_DATA_TABLE_ENTRY Module;
498 PVOID ImageBase = NULL;
499
500 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
501 ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
502 Entry = ModuleListHead->Flink;
503 while (Entry != ModuleListHead)
504 {
505 Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
506
507 if ((ULONG_PTR)PcValue >= (ULONG_PTR)Module->DllBase &&
508 (ULONG_PTR)PcValue < (ULONG_PTR)Module->DllBase + Module->SizeOfImage)
509 {
510 ImageBase = Module->DllBase;
511 break;
512 }
513 Entry = Entry->Flink;
514 }
515 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
516
517 *BaseOfImage = ImageBase;
518 return ImageBase;
519 }
520
521 /*
522 * @unimplemented
523 */
524 NTSYSAPI
525 NTSTATUS
526 NTAPI
527 RtlDosApplyFileIsolationRedirection_Ustr(IN ULONG Flags,
528 IN PUNICODE_STRING OriginalName,
529 IN PUNICODE_STRING Extension,
530 IN OUT PUNICODE_STRING StaticString,
531 IN OUT PUNICODE_STRING DynamicString,
532 IN OUT PUNICODE_STRING *NewName,
533 IN PULONG NewFlags,
534 IN PSIZE_T FileNameSize,
535 IN PSIZE_T RequiredLength)
536 {
537 return STATUS_SXS_KEY_NOT_FOUND;
538 }
539
540 /*
541 * @implemented
542 */
543 NTSYSAPI
544 NTSTATUS
545 NTAPI
546 RtlWow64EnableFsRedirection(IN BOOLEAN Wow64FsEnableRedirection)
547 {
548 /* This is what Windows returns on x86 */
549 return STATUS_NOT_IMPLEMENTED;
550 }
551
552 /*
553 * @implemented
554 */
555 NTSYSAPI
556 NTSTATUS
557 NTAPI
558 RtlWow64EnableFsRedirectionEx(IN PVOID Wow64FsEnableRedirection,
559 OUT PVOID *OldFsRedirectionLevel)
560 {
561 /* This is what Windows returns on x86 */
562 return STATUS_NOT_IMPLEMENTED;
563 }
564
565 /*
566 * @unimplemented
567 */
568 NTSYSAPI
569 NTSTATUS
570 NTAPI
571 RtlComputeImportTableHash(IN HANDLE FileHandle,
572 OUT PCHAR Hash,
573 IN ULONG ImporTTableHashSize)
574 {
575 UNIMPLEMENTED;
576 return STATUS_NOT_IMPLEMENTED;
577 }
578
579 NTSTATUS
580 NTAPI
581 RtlpSafeCopyMemory(
582 _Out_writes_bytes_all_(Length) VOID UNALIGNED *Destination,
583 _In_reads_bytes_(Length) CONST VOID UNALIGNED *Source,
584 _In_ SIZE_T Length)
585 {
586 _SEH2_TRY
587 {
588 RtlCopyMemory(Destination, Source, Length);
589 }
590 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
591 {
592 _SEH2_YIELD(return _SEH2_GetExceptionCode());
593 }
594 _SEH2_END;
595
596 return STATUS_SUCCESS;
597 }
598
599 /* EOF */