[NTDLL]
[reactos.git] / reactos / ntoskrnl / rtl / libsupp.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/rtl/libsupp.c
5 * PURPOSE: RTL Support Routines
6 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
7 * Gunnar Dalsnes
8 */
9
10 /* INCLUDES ******************************************************************/
11
12 #include <ntoskrnl.h>
13 #define NDEBUG
14 #include <debug.h>
15
16 #define TAG_ATMT 'TotA' /* Atom table */
17 #define TAG_RTHL 'LHtR' /* Heap Lock */
18
19 extern ULONG NtGlobalFlag;
20
21 typedef struct _RTL_RANGE_ENTRY
22 {
23 LIST_ENTRY Entry;
24 RTL_RANGE Range;
25 } RTL_RANGE_ENTRY, *PRTL_RANGE_ENTRY;
26
27 PAGED_LOOKASIDE_LIST RtlpRangeListEntryLookasideList;
28 SIZE_T RtlpAllocDeallocQueryBufferSize = 128;
29
30 /* FUNCTIONS *****************************************************************/
31
32 PVOID
33 NTAPI
34 RtlPcToFileHeader(
35 IN PVOID PcValue,
36 OUT PVOID *BaseOfImage)
37 {
38 PLDR_DATA_TABLE_ENTRY LdrEntry;
39 BOOLEAN InSystem;
40
41 /* Get the base for this file */
42 if ((ULONG_PTR)PcValue > (ULONG_PTR)MmHighestUserAddress)
43 {
44 /* We are in kernel */
45 *BaseOfImage = KiPcToFileHeader(PcValue, &LdrEntry, FALSE, &InSystem);
46 }
47 else
48 {
49 /* We are in user land */
50 *BaseOfImage = KiRosPcToUserFileHeader(PcValue, &LdrEntry);
51 }
52
53 return *BaseOfImage;
54 }
55
56 VOID
57 NTAPI
58 RtlInitializeRangeListPackage(VOID)
59 {
60 /* Setup the lookaside list for allocations (not used yet) */
61 ExInitializePagedLookasideList(&RtlpRangeListEntryLookasideList,
62 NULL,
63 NULL,
64 POOL_COLD_ALLOCATION,
65 sizeof(RTL_RANGE_ENTRY),
66 'elRR',
67 16);
68 }
69
70 BOOLEAN
71 NTAPI
72 RtlpCheckForActiveDebugger(VOID)
73 {
74 /* This check is meaningless in kernel-mode */
75 return FALSE;
76 }
77
78 BOOLEAN
79 NTAPI
80 RtlpSetInDbgPrint(VOID)
81 {
82 /* Nothing to set in kernel mode */
83 return FALSE;
84 }
85
86 VOID
87 NTAPI
88 RtlpClearInDbgPrint(VOID)
89 {
90 /* Nothing to clear in kernel mode */
91 }
92
93 KPROCESSOR_MODE
94 NTAPI
95 RtlpGetMode(VOID)
96 {
97 return KernelMode;
98 }
99
100 PVOID
101 NTAPI
102 RtlpAllocateMemory(ULONG Bytes,
103 ULONG Tag)
104 {
105 return ExAllocatePoolWithTag(PagedPool,
106 (SIZE_T)Bytes,
107 Tag);
108 }
109
110
111 #define TAG_USTR 'RTSU'
112 #define TAG_ASTR 'RTSA'
113 #define TAG_OSTR 'RTSO'
114 VOID
115 NTAPI
116 RtlpFreeMemory(PVOID Mem,
117 ULONG Tag)
118 {
119 if (Tag == TAG_ASTR || Tag == TAG_OSTR || Tag == TAG_USTR)
120 ExFreePool(Mem);
121 else
122 ExFreePoolWithTag(Mem, Tag);
123 }
124
125 /*
126 * @implemented
127 */
128 VOID NTAPI
129 RtlAcquirePebLock(VOID)
130 {
131
132 }
133
134 /*
135 * @implemented
136 */
137 VOID NTAPI
138 RtlReleasePebLock(VOID)
139 {
140
141 }
142
143 NTSTATUS
144 NTAPI
145 LdrShutdownThread(VOID)
146 {
147 return STATUS_SUCCESS;
148 }
149
150
151 PPEB
152 NTAPI
153 RtlGetCurrentPeb(VOID)
154 {
155 return ((PEPROCESS)(KeGetCurrentThread()->ApcState.Process))->Peb;
156 }
157
158 NTSTATUS
159 NTAPI
160 RtlDeleteHeapLock(IN OUT PHEAP_LOCK Lock)
161 {
162 ExDeleteResourceLite(&Lock->Resource);
163 ExFreePoolWithTag(Lock, TAG_RTHL);
164
165 return STATUS_SUCCESS;
166 }
167
168 NTSTATUS
169 NTAPI
170 RtlEnterHeapLock(IN OUT PHEAP_LOCK Lock, IN BOOLEAN Exclusive)
171 {
172 KeEnterCriticalRegion();
173
174 if (Exclusive)
175 ExAcquireResourceExclusiveLite(&Lock->Resource, TRUE);
176 else
177 ExAcquireResourceSharedLite(&Lock->Resource, TRUE);
178
179 return STATUS_SUCCESS;
180 }
181
182 BOOLEAN
183 NTAPI
184 RtlTryEnterHeapLock(IN OUT PHEAP_LOCK Lock, IN BOOLEAN Exclusive)
185 {
186 BOOLEAN Success;
187 KeEnterCriticalRegion();
188
189 if (Exclusive)
190 Success = ExAcquireResourceExclusiveLite(&Lock->Resource, FALSE);
191 else
192 Success = ExAcquireResourceSharedLite(&Lock->Resource, FALSE);
193
194 if (!Success)
195 KeLeaveCriticalRegion();
196
197 return Success;
198 }
199
200 NTSTATUS
201 NTAPI
202 RtlInitializeHeapLock(IN OUT PHEAP_LOCK *Lock)
203 {
204 PHEAP_LOCK HeapLock = ExAllocatePoolWithTag(NonPagedPool,
205 sizeof(HEAP_LOCK),
206 TAG_RTHL);
207 if (HeapLock == NULL)
208 return STATUS_NO_MEMORY;
209
210 ExInitializeResourceLite(&HeapLock->Resource);
211 *Lock = HeapLock;
212
213 return STATUS_SUCCESS;
214 }
215
216 NTSTATUS
217 NTAPI
218 RtlLeaveHeapLock(IN OUT PHEAP_LOCK Lock)
219 {
220 ExReleaseResourceLite(&Lock->Resource);
221 KeLeaveCriticalRegion();
222
223 return STATUS_SUCCESS;
224 }
225
226 struct _HEAP;
227
228 VOID
229 NTAPI
230 RtlpAddHeapToProcessList(struct _HEAP *Heap)
231 {
232 UNREFERENCED_PARAMETER(Heap);
233 }
234
235 VOID
236 NTAPI
237 RtlpRemoveHeapFromProcessList(struct _HEAP *Heap)
238 {
239 UNREFERENCED_PARAMETER(Heap);
240 }
241
242 VOID
243 RtlInitializeHeapManager(VOID)
244 {
245 }
246
247 #if DBG
248 VOID FASTCALL
249 CHECK_PAGED_CODE_RTL(char *file, int line)
250 {
251 if(KeGetCurrentIrql() > APC_LEVEL)
252 {
253 DbgPrint("%s:%i: Pagable code called at IRQL > APC_LEVEL (%u)\n", file, line, KeGetCurrentIrql());
254 ASSERT(FALSE);
255 }
256 }
257 #endif
258
259 VOID
260 NTAPI
261 RtlpSetHeapParameters(IN PRTL_HEAP_PARAMETERS Parameters)
262 {
263 /* Apply defaults for non-set parameters */
264 if (!Parameters->SegmentCommit) Parameters->SegmentCommit = MmHeapSegmentCommit;
265 if (!Parameters->SegmentReserve) Parameters->SegmentReserve = MmHeapSegmentReserve;
266 if (!Parameters->DeCommitFreeBlockThreshold) Parameters->DeCommitFreeBlockThreshold = MmHeapDeCommitFreeBlockThreshold;
267 if (!Parameters->DeCommitTotalFreeThreshold) Parameters->DeCommitTotalFreeThreshold = MmHeapDeCommitTotalFreeThreshold;
268 }
269
270 VOID
271 NTAPI
272 RtlpCheckLogException(IN PEXCEPTION_RECORD ExceptionRecord,
273 IN PCONTEXT ContextRecord,
274 IN PVOID ContextData,
275 IN ULONG Size)
276 {
277 /* Check the global flag */
278 if (NtGlobalFlag & FLG_ENABLE_EXCEPTION_LOGGING)
279 {
280 /* FIXME: Log this exception */
281 }
282 }
283
284 BOOLEAN
285 NTAPI
286 RtlpHandleDpcStackException(IN PEXCEPTION_REGISTRATION_RECORD RegistrationFrame,
287 IN ULONG_PTR RegistrationFrameEnd,
288 IN OUT PULONG_PTR StackLow,
289 IN OUT PULONG_PTR StackHigh)
290 {
291 PKPRCB Prcb;
292 ULONG_PTR DpcStack;
293
294 /* Check if we are at DISPATCH or higher */
295 if (KeGetCurrentIrql() >= DISPATCH_LEVEL)
296 {
297 /* Get the PRCB and DPC Stack */
298 Prcb = KeGetCurrentPrcb();
299 DpcStack = (ULONG_PTR)Prcb->DpcStack;
300
301 /* Check if we are in a DPC and the stack matches */
302 if ((Prcb->DpcRoutineActive) &&
303 (RegistrationFrameEnd <= DpcStack) &&
304 ((ULONG_PTR)RegistrationFrame >= DpcStack - KERNEL_STACK_SIZE))
305 {
306 /* Update the limits to the DPC Stack's */
307 *StackHigh = DpcStack;
308 *StackLow = DpcStack - KERNEL_STACK_SIZE;
309 return TRUE;
310 }
311 }
312
313 /* Not in DPC stack */
314 return FALSE;
315 }
316
317 #if !defined(_ARM_) && !defined(_AMD64_)
318
319 BOOLEAN
320 NTAPI
321 RtlpCaptureStackLimits(IN ULONG_PTR Ebp,
322 IN ULONG_PTR *StackBegin,
323 IN ULONG_PTR *StackEnd)
324 {
325 PKTHREAD Thread = KeGetCurrentThread();
326
327 /* Don't even try at ISR level or later */
328 if (KeGetCurrentIrql() > DISPATCH_LEVEL) return FALSE;
329
330 /* Start with defaults */
331 *StackBegin = Thread->StackLimit;
332 *StackEnd = (ULONG_PTR)Thread->StackBase;
333
334 /* Check if EBP is inside the stack */
335 if ((*StackBegin <= Ebp) && (Ebp <= *StackEnd))
336 {
337 /* Then make the stack start at EBP */
338 *StackBegin = Ebp;
339 }
340 else
341 {
342 /* Now we're going to assume we're on the DPC stack */
343 *StackEnd = (ULONG_PTR)(KeGetPcr()->Prcb->DpcStack);
344 *StackBegin = *StackEnd - KERNEL_STACK_SIZE;
345
346 /* Check if we seem to be on the DPC stack */
347 if ((*StackEnd) && (*StackBegin < Ebp) && (Ebp <= *StackEnd))
348 {
349 /* We're on the DPC stack */
350 *StackBegin = Ebp;
351 }
352 else
353 {
354 /* We're somewhere else entirely... use EBP for safety */
355 *StackBegin = Ebp;
356 *StackEnd = (ULONG_PTR)PAGE_ALIGN(*StackBegin);
357 }
358 }
359
360 /* Return success */
361 return TRUE;
362 }
363
364 /*
365 * @implemented
366 */
367 ULONG
368 NTAPI
369 RtlWalkFrameChain(OUT PVOID *Callers,
370 IN ULONG Count,
371 IN ULONG Flags)
372 {
373 ULONG_PTR Stack, NewStack, StackBegin, StackEnd = 0;
374 ULONG Eip;
375 BOOLEAN Result, StopSearch = FALSE;
376 ULONG i = 0;
377 PETHREAD Thread = PsGetCurrentThread();
378 PTEB Teb;
379 PKTRAP_FRAME TrapFrame;
380
381 /* Get current EBP */
382 #if defined(_M_IX86)
383 #if defined __GNUC__
384 __asm__("mov %%ebp, %0" : "=r" (Stack) : );
385 #elif defined(_MSC_VER)
386 __asm mov Stack, ebp
387 #endif
388 #elif defined(_M_MIPS)
389 __asm__("move $sp, %0" : "=r" (Stack) : );
390 #elif defined(_M_PPC)
391 __asm__("mr %0,1" : "=r" (Stack) : );
392 #elif defined(_M_ARM)
393 __asm__("mov sp, %0" : "=r"(Stack) : );
394 #else
395 #error Unknown architecture
396 #endif
397
398 /* Set it as the stack begin limit as well */
399 StackBegin = (ULONG_PTR)Stack;
400
401 /* Check if we're called for non-logging mode */
402 if (!Flags)
403 {
404 /* Get the actual safe limits */
405 Result = RtlpCaptureStackLimits((ULONG_PTR)Stack,
406 &StackBegin,
407 &StackEnd);
408 if (!Result) return 0;
409 }
410
411 /* Use a SEH block for maximum protection */
412 _SEH2_TRY
413 {
414 /* Check if we want the user-mode stack frame */
415 if (Flags == 1)
416 {
417 /* Get the trap frame and TEB */
418 TrapFrame = KeGetTrapFrame(&Thread->Tcb);
419 Teb = Thread->Tcb.Teb;
420
421 /* Make sure we can trust the TEB and trap frame */
422 if (!(Teb) ||
423 (KeIsAttachedProcess()) ||
424 (KeGetCurrentIrql() >= DISPATCH_LEVEL))
425 {
426 /* Invalid or unsafe attempt to get the stack */
427 _SEH2_YIELD(return 0;)
428 }
429
430 /* Get the stack limits */
431 StackBegin = (ULONG_PTR)Teb->NtTib.StackLimit;
432 StackEnd = (ULONG_PTR)Teb->NtTib.StackBase;
433 #ifdef _M_IX86
434 Stack = TrapFrame->Ebp;
435 #elif defined(_M_PPC)
436 Stack = TrapFrame->Gpr1;
437 #else
438 #error Unknown architecture
439 #endif
440
441 /* Validate them */
442 if (StackEnd <= StackBegin) _SEH2_YIELD(return 0);
443 ProbeForRead((PVOID)StackBegin,
444 StackEnd - StackBegin,
445 sizeof(CHAR));
446 }
447
448 /* Loop the frames */
449 for (i = 0; i < Count; i++)
450 {
451 /*
452 * Leave if we're past the stack,
453 * if we're before the stack,
454 * or if we've reached ourselves.
455 */
456 if ((Stack >= StackEnd) ||
457 (!i ? (Stack < StackBegin) : (Stack <= StackBegin)) ||
458 ((StackEnd - Stack) < (2 * sizeof(ULONG_PTR))))
459 {
460 /* We're done or hit a bad address */
461 break;
462 }
463
464 /* Get new stack and EIP */
465 NewStack = *(PULONG_PTR)Stack;
466 Eip = *(PULONG_PTR)(Stack + sizeof(ULONG_PTR));
467
468 /* Check if the new pointer is above the oldone and past the end */
469 if (!((Stack < NewStack) && (NewStack < StackEnd)))
470 {
471 /* Stop searching after this entry */
472 StopSearch = TRUE;
473 }
474
475 /* Also make sure that the EIP isn't a stack address */
476 if ((StackBegin < Eip) && (Eip < StackEnd)) break;
477
478 /* Check if we reached a user-mode address */
479 if (!(Flags) && !(Eip & 0x80000000)) break; // FIXME: 3GB breakage
480
481 /* Save this frame */
482 Callers[i] = (PVOID)Eip;
483
484 /* Check if we should continue */
485 if (StopSearch)
486 {
487 /* Return the next index */
488 i++;
489 break;
490 }
491
492 /* Move to the next stack */
493 Stack = NewStack;
494 }
495 }
496 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
497 {
498 /* No index */
499 i = 0;
500 }
501 _SEH2_END;
502
503 /* Return frames parsed */
504 return i;
505 }
506
507 #endif
508
509 #if defined(_M_AMD64) || defined(_M_ARM)
510 VOID
511 NTAPI
512 RtlpGetStackLimits(
513 OUT PULONG_PTR LowLimit,
514 OUT PULONG_PTR HighLimit)
515 {
516 PKTHREAD CurrentThread = KeGetCurrentThread();
517 *HighLimit = (ULONG_PTR)CurrentThread->InitialStack;
518 *LowLimit = (ULONG_PTR)CurrentThread->StackLimit;
519 }
520 #endif
521
522 /* RTL Atom Tables ************************************************************/
523
524 NTSTATUS
525 RtlpInitAtomTableLock(PRTL_ATOM_TABLE AtomTable)
526 {
527 ExInitializeFastMutex(&AtomTable->FastMutex);
528
529 return STATUS_SUCCESS;
530 }
531
532
533 VOID
534 RtlpDestroyAtomTableLock(PRTL_ATOM_TABLE AtomTable)
535 {
536 }
537
538
539 BOOLEAN
540 RtlpLockAtomTable(PRTL_ATOM_TABLE AtomTable)
541 {
542 ExAcquireFastMutex(&AtomTable->FastMutex);
543 return TRUE;
544 }
545
546 VOID
547 RtlpUnlockAtomTable(PRTL_ATOM_TABLE AtomTable)
548 {
549 ExReleaseFastMutex(&AtomTable->FastMutex);
550 }
551
552 BOOLEAN
553 RtlpCreateAtomHandleTable(PRTL_ATOM_TABLE AtomTable)
554 {
555 AtomTable->ExHandleTable = ExCreateHandleTable(NULL);
556 return (AtomTable->ExHandleTable != NULL);
557 }
558
559 BOOLEAN
560 NTAPI
561 RtlpCloseHandleCallback(
562 IN PHANDLE_TABLE_ENTRY HandleTableEntry,
563 IN HANDLE Handle,
564 IN PVOID HandleTable)
565 {
566 /* Destroy and unlock the handle entry */
567 return ExDestroyHandle(HandleTable, Handle, HandleTableEntry);
568 }
569
570 VOID
571 RtlpDestroyAtomHandleTable(PRTL_ATOM_TABLE AtomTable)
572 {
573 if (AtomTable->ExHandleTable)
574 {
575 ExSweepHandleTable(AtomTable->ExHandleTable,
576 RtlpCloseHandleCallback,
577 AtomTable->ExHandleTable);
578 ExDestroyHandleTable(AtomTable->ExHandleTable, NULL);
579 AtomTable->ExHandleTable = NULL;
580 }
581 }
582
583 PRTL_ATOM_TABLE
584 RtlpAllocAtomTable(ULONG Size)
585 {
586 PRTL_ATOM_TABLE Table = ExAllocatePoolWithTag(NonPagedPool,
587 Size,
588 TAG_ATMT);
589 if (Table != NULL)
590 {
591 RtlZeroMemory(Table,
592 Size);
593 }
594
595 return Table;
596 }
597
598 VOID
599 RtlpFreeAtomTable(PRTL_ATOM_TABLE AtomTable)
600 {
601 ExFreePoolWithTag(AtomTable, TAG_ATMT);
602 }
603
604 PRTL_ATOM_TABLE_ENTRY
605 RtlpAllocAtomTableEntry(ULONG Size)
606 {
607 PRTL_ATOM_TABLE_ENTRY Entry;
608
609 Entry = ExAllocatePoolWithTag(NonPagedPool, Size, TAG_ATMT);
610 if (Entry != NULL)
611 {
612 RtlZeroMemory(Entry, Size);
613 }
614
615 return Entry;
616 }
617
618 VOID
619 RtlpFreeAtomTableEntry(PRTL_ATOM_TABLE_ENTRY Entry)
620 {
621 ExFreePoolWithTag(Entry, TAG_ATMT);
622 }
623
624 VOID
625 RtlpFreeAtomHandle(PRTL_ATOM_TABLE AtomTable, PRTL_ATOM_TABLE_ENTRY Entry)
626 {
627 ExDestroyHandle(AtomTable->ExHandleTable,
628 (HANDLE)((ULONG_PTR)Entry->HandleIndex << 2),
629 NULL);
630 }
631
632 BOOLEAN
633 RtlpCreateAtomHandle(PRTL_ATOM_TABLE AtomTable, PRTL_ATOM_TABLE_ENTRY Entry)
634 {
635 HANDLE_TABLE_ENTRY ExEntry;
636 HANDLE Handle;
637 USHORT HandleIndex;
638
639 /* Initialize ex handle table entry */
640 ExEntry.Object = Entry;
641 ExEntry.GrantedAccess = 0x1; /* FIXME - valid handle */
642
643 /* Create ex handle */
644 Handle = ExCreateHandle(AtomTable->ExHandleTable,
645 &ExEntry);
646 if (!Handle) return FALSE;
647
648 /* Calculate HandleIndex (by getting rid of the first two bits) */
649 HandleIndex = (USHORT)((ULONG_PTR)Handle >> 2);
650
651 /* Index must be less than 0xC000 */
652 if (HandleIndex >= 0xC000)
653 {
654 /* Destroy ex handle */
655 ExDestroyHandle(AtomTable->ExHandleTable,
656 Handle,
657 NULL);
658
659 /* Return failure */
660 return FALSE;
661 }
662
663 /* Initialize atom table entry */
664 Entry->HandleIndex = HandleIndex;
665 Entry->Atom = 0xC000 + HandleIndex;
666
667 /* Return success */
668 return TRUE;
669 }
670
671 PRTL_ATOM_TABLE_ENTRY
672 RtlpGetAtomEntry(PRTL_ATOM_TABLE AtomTable, ULONG Index)
673 {
674 PHANDLE_TABLE_ENTRY ExEntry;
675 PRTL_ATOM_TABLE_ENTRY Entry = NULL;
676
677 /* NOTE: There's no need to explicitly enter a critical region because it's
678 guaranteed that we're in a critical region right now (as we hold
679 the atom table lock) */
680
681 ExEntry = ExMapHandleToPointer(AtomTable->ExHandleTable,
682 (HANDLE)((ULONG_PTR)Index << 2));
683 if (ExEntry != NULL)
684 {
685 Entry = ExEntry->Object;
686
687 ExUnlockHandleTableEntry(AtomTable->ExHandleTable,
688 ExEntry);
689 }
690
691 return Entry;
692 }
693
694 /*
695 * Ldr Resource support code
696 */
697
698 IMAGE_RESOURCE_DIRECTORY *find_entry_by_name( IMAGE_RESOURCE_DIRECTORY *dir,
699 LPCWSTR name, void *root,
700 int want_dir );
701 IMAGE_RESOURCE_DIRECTORY *find_entry_by_id( IMAGE_RESOURCE_DIRECTORY *dir,
702 USHORT id, void *root, int want_dir );
703 IMAGE_RESOURCE_DIRECTORY *find_first_entry( IMAGE_RESOURCE_DIRECTORY *dir,
704 void *root, int want_dir );
705
706 /**********************************************************************
707 * find_entry
708 *
709 * Find a resource entry
710 */
711 NTSTATUS find_entry( PVOID BaseAddress, LDR_RESOURCE_INFO *info,
712 ULONG level, void **ret, int want_dir )
713 {
714 ULONG size;
715 void *root;
716 IMAGE_RESOURCE_DIRECTORY *resdirptr;
717
718 root = RtlImageDirectoryEntryToData( BaseAddress, TRUE, IMAGE_DIRECTORY_ENTRY_RESOURCE, &size );
719 if (!root) return STATUS_RESOURCE_DATA_NOT_FOUND;
720 if (size < sizeof(*resdirptr)) return STATUS_RESOURCE_DATA_NOT_FOUND;
721 resdirptr = root;
722
723 if (!level--) goto done;
724 if (!(*ret = find_entry_by_name( resdirptr, (LPCWSTR)info->Type, root, want_dir || level )))
725 return STATUS_RESOURCE_TYPE_NOT_FOUND;
726 if (!level--) return STATUS_SUCCESS;
727
728 resdirptr = *ret;
729 if (!(*ret = find_entry_by_name( resdirptr, (LPCWSTR)info->Name, root, want_dir || level )))
730 return STATUS_RESOURCE_NAME_NOT_FOUND;
731 if (!level--) return STATUS_SUCCESS;
732 if (level) return STATUS_INVALID_PARAMETER; /* level > 3 */
733
734 resdirptr = *ret;
735
736 if ((*ret = find_first_entry( resdirptr, root, want_dir ))) return STATUS_SUCCESS;
737
738 return STATUS_RESOURCE_DATA_NOT_FOUND;
739
740 done:
741 *ret = resdirptr;
742 return STATUS_SUCCESS;
743 }
744
745 NTSTATUS
746 NTAPI
747 RtlpSafeCopyMemory(
748 _Out_writes_bytes_all_(Length) VOID UNALIGNED *Destination,
749 _In_reads_bytes_(Length) CONST VOID UNALIGNED *Source,
750 _In_ SIZE_T Length)
751 {
752 _SEH2_TRY
753 {
754 RtlCopyMemory(Destination, Source, Length);
755 }
756 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
757 {
758 _SEH2_YIELD(return _SEH2_GetExceptionCode());
759 }
760 _SEH2_END;
761
762 return STATUS_SUCCESS;
763 }
764
765 BOOLEAN
766 NTAPI
767 RtlCallVectoredExceptionHandlers(_In_ PEXCEPTION_RECORD ExceptionRecord,
768 _In_ PCONTEXT Context)
769 {
770 /* In the kernel we don't have vectored exception handlers */
771 return FALSE;
772 }
773
774 VOID
775 NTAPI
776 RtlCallVectoredContinueHandlers(_In_ PEXCEPTION_RECORD ExceptionRecord,
777 _In_ PCONTEXT Context)
778 {
779 /* No vectored continue handlers either in kernel mode */
780 return;
781 }
782
783 /* EOF */