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