xref: /reactos/dll/ntdll/rtl/libsupp.c (revision 7e069ccd)
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 PVOID MmHighestUserAddress = (PVOID)MI_HIGHEST_USER_ADDRESS;
20 
21 /* FUNCTIONS ***************************************************************/
22 
23 BOOLEAN
24 NTAPI
25 RtlpCheckForActiveDebugger(VOID)
26 {
27     /* Return the flag in the PEB */
28     return NtCurrentPeb()->BeingDebugged;
29 }
30 
31 BOOLEAN
32 NTAPI
33 RtlpSetInDbgPrint(VOID)
34 {
35     /* Check if it's already set and return TRUE if so */
36     if (NtCurrentTeb()->InDbgPrint) return TRUE;
37 
38     /* Set it and return */
39     NtCurrentTeb()->InDbgPrint = TRUE;
40     return FALSE;
41 }
42 
43 VOID
44 NTAPI
45 RtlpClearInDbgPrint(VOID)
46 {
47     /* Clear the flag */
48     NtCurrentTeb()->InDbgPrint = FALSE;
49 }
50 
51 KPROCESSOR_MODE
52 NTAPI
53 RtlpGetMode(VOID)
54 {
55    return UserMode;
56 }
57 
58 /*
59  * @implemented
60  */
61 PPEB
62 NTAPI
63 RtlGetCurrentPeb(VOID)
64 {
65     return NtCurrentPeb();
66 }
67 
68 /*
69  * @implemented
70  */
71 VOID NTAPI
72 RtlAcquirePebLock(VOID)
73 {
74    PPEB Peb = NtCurrentPeb ();
75    RtlEnterCriticalSection(Peb->FastPebLock);
76 }
77 
78 /*
79  * @implemented
80  */
81 VOID NTAPI
82 RtlReleasePebLock(VOID)
83 {
84    PPEB Peb = NtCurrentPeb ();
85    RtlLeaveCriticalSection(Peb->FastPebLock);
86 }
87 
88 /*
89 * @implemented
90 */
91 ULONG
92 NTAPI
93 RtlGetNtGlobalFlags(VOID)
94 {
95     PPEB pPeb = NtCurrentPeb();
96     return pPeb->NtGlobalFlag;
97 }
98 
99 NTSTATUS
100 NTAPI
101 RtlDeleteHeapLock(IN OUT PHEAP_LOCK Lock)
102 {
103     return RtlDeleteCriticalSection(&Lock->CriticalSection);
104 }
105 
106 NTSTATUS
107 NTAPI
108 RtlEnterHeapLock(IN OUT PHEAP_LOCK Lock, IN BOOLEAN Exclusive)
109 {
110     UNREFERENCED_PARAMETER(Exclusive);
111 
112     return RtlEnterCriticalSection(&Lock->CriticalSection);
113 }
114 
115 BOOLEAN
116 NTAPI
117 RtlTryEnterHeapLock(IN OUT PHEAP_LOCK Lock, IN BOOLEAN Exclusive)
118 {
119     UNREFERENCED_PARAMETER(Exclusive);
120 
121     return RtlTryEnterCriticalSection(&Lock->CriticalSection);
122 }
123 
124 NTSTATUS
125 NTAPI
126 RtlInitializeHeapLock(IN OUT PHEAP_LOCK *Lock)
127 {
128     return RtlInitializeCriticalSection(&(*Lock)->CriticalSection);
129 }
130 
131 NTSTATUS
132 NTAPI
133 RtlLeaveHeapLock(IN OUT PHEAP_LOCK Lock)
134 {
135     return RtlLeaveCriticalSection(&Lock->CriticalSection);
136 }
137 
138 PVOID
139 NTAPI
140 RtlpAllocateMemory(UINT Bytes,
141                    ULONG Tag)
142 {
143     UNREFERENCED_PARAMETER(Tag);
144 
145     return RtlAllocateHeap(RtlGetProcessHeap(),
146                            0,
147                            Bytes);
148 }
149 
150 
151 VOID
152 NTAPI
153 RtlpFreeMemory(PVOID Mem,
154                ULONG Tag)
155 {
156     UNREFERENCED_PARAMETER(Tag);
157 
158     RtlFreeHeap(RtlGetProcessHeap(),
159                 0,
160                 Mem);
161 }
162 
163 
164 #if DBG
165 VOID FASTCALL
166 CHECK_PAGED_CODE_RTL(char *file, int line)
167 {
168   /* meaningless in user mode */
169 }
170 #endif
171 
172 VOID
173 NTAPI
174 RtlpSetHeapParameters(IN PRTL_HEAP_PARAMETERS Parameters)
175 {
176     PPEB Peb;
177 
178     /* Get PEB */
179     Peb = RtlGetCurrentPeb();
180 
181     /* Apply defaults for non-set parameters */
182     if (!Parameters->SegmentCommit) Parameters->SegmentCommit = Peb->HeapSegmentCommit;
183     if (!Parameters->SegmentReserve) Parameters->SegmentReserve = Peb->HeapSegmentReserve;
184     if (!Parameters->DeCommitFreeBlockThreshold) Parameters->DeCommitFreeBlockThreshold = Peb->HeapDeCommitFreeBlockThreshold;
185     if (!Parameters->DeCommitTotalFreeThreshold) Parameters->DeCommitTotalFreeThreshold = Peb->HeapDeCommitTotalFreeThreshold;
186 }
187 
188 BOOLEAN
189 NTAPI
190 RtlpHandleDpcStackException(IN PEXCEPTION_REGISTRATION_RECORD RegistrationFrame,
191                             IN ULONG_PTR RegistrationFrameEnd,
192                             IN OUT PULONG_PTR StackLow,
193                             IN OUT PULONG_PTR StackHigh)
194 {
195     /* There's no such thing as a DPC stack in user-mode */
196     return FALSE;
197 }
198 
199 VOID
200 NTAPI
201 RtlpCheckLogException(IN PEXCEPTION_RECORD ExceptionRecord,
202                       IN PCONTEXT ContextRecord,
203                       IN PVOID ContextData,
204                       IN ULONG Size)
205 {
206     /* Exception logging is not done in user-mode */
207 }
208 
209 BOOLEAN
210 NTAPI
211 RtlpCaptureStackLimits(IN ULONG_PTR Ebp,
212                        IN ULONG_PTR *StackBegin,
213                        IN ULONG_PTR *StackEnd)
214 {
215     /* FIXME: Verify */
216     *StackBegin = (ULONG_PTR)NtCurrentTeb()->NtTib.StackLimit;
217     *StackEnd = (ULONG_PTR)NtCurrentTeb()->NtTib.StackBase;
218     return TRUE;
219 }
220 
221 #ifndef _M_AMD64
222 /*
223  * @implemented
224  */
225 ULONG
226 NTAPI
227 RtlWalkFrameChain(OUT PVOID *Callers,
228                   IN ULONG Count,
229                   IN ULONG Flags)
230 {
231     ULONG_PTR Stack, NewStack, StackBegin, StackEnd = 0;
232     ULONG Eip;
233     BOOLEAN Result, StopSearch = FALSE;
234     ULONG i = 0;
235 
236     /* Get current EBP */
237 #if defined(_M_IX86)
238 #if defined __GNUC__
239     __asm__("mov %%ebp, %0" : "=r" (Stack) : );
240 #elif defined(_MSC_VER)
241     __asm mov Stack, ebp
242 #endif
243 #elif defined(_M_MIPS)
244         __asm__("move $sp, %0" : "=r" (Stack) : );
245 #elif defined(_M_PPC)
246     __asm__("mr %0,1" : "=r" (Stack) : );
247 #elif defined(_M_ARM)
248 #if defined __GNUC__
249     __asm__("mov sp, %0" : "=r"(Stack) : );
250 #elif defined(_MSC_VER)
251     // FIXME: Hack. Probably won't work if this ever actually manages to run someday.
252     Stack = (ULONG_PTR)&Stack;
253 #endif
254 #else
255 #error Unknown architecture
256 #endif
257 
258     /* Set it as the stack begin limit as well */
259     StackBegin = (ULONG_PTR)Stack;
260 
261     /* Check if we're called for non-logging mode */
262     if (!Flags)
263     {
264         /* Get the actual safe limits */
265         Result = RtlpCaptureStackLimits((ULONG_PTR)Stack,
266                                         &StackBegin,
267                                         &StackEnd);
268         if (!Result) return 0;
269     }
270 
271     /* Use a SEH block for maximum protection */
272     _SEH2_TRY
273     {
274         /* Loop the frames */
275         for (i = 0; i < Count; i++)
276         {
277             /*
278              * Leave if we're past the stack,
279              * if we're before the stack,
280              * or if we've reached ourselves.
281              */
282             if ((Stack >= StackEnd) ||
283                 (!i ? (Stack < StackBegin) : (Stack <= StackBegin)) ||
284                 ((StackEnd - Stack) < (2 * sizeof(ULONG_PTR))))
285             {
286                 /* We're done or hit a bad address */
287                 break;
288             }
289 
290             /* Get new stack and EIP */
291             NewStack = *(PULONG_PTR)Stack;
292             Eip = *(PULONG_PTR)(Stack + sizeof(ULONG_PTR));
293 
294             /* Check if the new pointer is above the oldone and past the end */
295             if (!((Stack < NewStack) && (NewStack < StackEnd)))
296             {
297                 /* Stop searching after this entry */
298                 StopSearch = TRUE;
299             }
300 
301             /* Also make sure that the EIP isn't a stack address */
302             if ((StackBegin < Eip) && (Eip < StackEnd)) break;
303 
304             /* FIXME: Check that EIP is inside a loaded module */
305 
306             /* Save this frame */
307             Callers[i] = (PVOID)Eip;
308 
309             /* Check if we should continue */
310             if (StopSearch)
311             {
312                 /* Return the next index */
313                 i++;
314                 break;
315             }
316 
317             /* Move to the next stack */
318             Stack = NewStack;
319         }
320     }
321     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
322     {
323         /* No index */
324         i = 0;
325     }
326     _SEH2_END;
327 
328     /* Return frames parsed */
329     return i;
330 }
331 #endif
332 
333 #ifdef _AMD64_
334 VOID
335 NTAPI
336 RtlpGetStackLimits(
337     OUT PULONG_PTR LowLimit,
338     OUT PULONG_PTR HighLimit)
339 {
340     *LowLimit = (ULONG_PTR)NtCurrentTeb()->NtTib.StackLimit;
341     *HighLimit = (ULONG_PTR)NtCurrentTeb()->NtTib.StackBase;
342     return;
343 }
344 #endif
345 
346 BOOLEAN
347 NTAPI
348 RtlIsThreadWithinLoaderCallout(VOID)
349 {
350     return LdrpTopLevelDllBeingLoadedTeb == NtCurrentTeb();
351 }
352 
353 /* RTL Atom Tables ************************************************************/
354 
355 typedef struct _RTL_ATOM_HANDLE
356 {
357    RTL_HANDLE_TABLE_ENTRY Handle;
358    PRTL_ATOM_TABLE_ENTRY AtomEntry;
359 } RTL_ATOM_HANDLE, *PRTL_ATOM_HANDLE;
360 
361 NTSTATUS
362 RtlpInitAtomTableLock(PRTL_ATOM_TABLE AtomTable)
363 {
364    RtlInitializeCriticalSection(&AtomTable->CriticalSection);
365    return STATUS_SUCCESS;
366 }
367 
368 
369 VOID
370 RtlpDestroyAtomTableLock(PRTL_ATOM_TABLE AtomTable)
371 {
372    RtlDeleteCriticalSection(&AtomTable->CriticalSection);
373 }
374 
375 
376 BOOLEAN
377 RtlpLockAtomTable(PRTL_ATOM_TABLE AtomTable)
378 {
379    RtlEnterCriticalSection(&AtomTable->CriticalSection);
380    return TRUE;
381 }
382 
383 
384 VOID
385 RtlpUnlockAtomTable(PRTL_ATOM_TABLE AtomTable)
386 {
387    RtlLeaveCriticalSection(&AtomTable->CriticalSection);
388 }
389 
390 
391 /* handle functions */
392 
393 BOOLEAN
394 RtlpCreateAtomHandleTable(PRTL_ATOM_TABLE AtomTable)
395 {
396    RtlInitializeHandleTable(0xCFFF,
397                             sizeof(RTL_ATOM_HANDLE),
398                             &AtomTable->RtlHandleTable);
399 
400    return TRUE;
401 }
402 
403 VOID
404 RtlpDestroyAtomHandleTable(PRTL_ATOM_TABLE AtomTable)
405 {
406    RtlDestroyHandleTable(&AtomTable->RtlHandleTable);
407 }
408 
409 PRTL_ATOM_TABLE
410 RtlpAllocAtomTable(ULONG Size)
411 {
412    return (PRTL_ATOM_TABLE)RtlAllocateHeap(RtlGetProcessHeap(),
413                                            HEAP_ZERO_MEMORY,
414                                            Size);
415 }
416 
417 VOID
418 RtlpFreeAtomTable(PRTL_ATOM_TABLE AtomTable)
419 {
420    RtlFreeHeap(RtlGetProcessHeap(),
421                0,
422                AtomTable);
423 }
424 
425 PRTL_ATOM_TABLE_ENTRY
426 RtlpAllocAtomTableEntry(ULONG Size)
427 {
428    return (PRTL_ATOM_TABLE_ENTRY)RtlAllocateHeap(RtlGetProcessHeap(),
429                                                  HEAP_ZERO_MEMORY,
430                                                  Size);
431 }
432 
433 VOID
434 RtlpFreeAtomTableEntry(PRTL_ATOM_TABLE_ENTRY Entry)
435 {
436    RtlFreeHeap(RtlGetProcessHeap(),
437                0,
438                Entry);
439 }
440 
441 VOID
442 RtlpFreeAtomHandle(PRTL_ATOM_TABLE AtomTable, PRTL_ATOM_TABLE_ENTRY Entry)
443 {
444    PRTL_HANDLE_TABLE_ENTRY RtlHandleEntry;
445 
446    if (RtlIsValidIndexHandle(&AtomTable->RtlHandleTable,
447                              (ULONG)Entry->HandleIndex,
448                              &RtlHandleEntry))
449    {
450       RtlFreeHandle(&AtomTable->RtlHandleTable,
451                     RtlHandleEntry);
452    }
453 }
454 
455 BOOLEAN
456 RtlpCreateAtomHandle(PRTL_ATOM_TABLE AtomTable, PRTL_ATOM_TABLE_ENTRY Entry)
457 {
458    ULONG HandleIndex;
459    PRTL_HANDLE_TABLE_ENTRY RtlHandle;
460 
461    RtlHandle = RtlAllocateHandle(&AtomTable->RtlHandleTable,
462                                  &HandleIndex);
463    if (RtlHandle != NULL)
464    {
465       PRTL_ATOM_HANDLE AtomHandle = (PRTL_ATOM_HANDLE)RtlHandle;
466 
467       /* FIXME - Handle Indexes >= 0xC000 ?! */
468       if (HandleIndex < 0xC000)
469       {
470          Entry->HandleIndex = (USHORT)HandleIndex;
471          Entry->Atom = 0xC000 + (USHORT)HandleIndex;
472 
473          AtomHandle->AtomEntry = Entry;
474          AtomHandle->Handle.Flags = RTL_HANDLE_VALID;
475 
476          return TRUE;
477       }
478       else
479       {
480          /* set the valid flag, otherwise RtlFreeHandle will fail! */
481          AtomHandle->Handle.Flags = RTL_HANDLE_VALID;
482 
483          RtlFreeHandle(&AtomTable->RtlHandleTable,
484                        RtlHandle);
485       }
486    }
487 
488    return FALSE;
489 }
490 
491 PRTL_ATOM_TABLE_ENTRY
492 RtlpGetAtomEntry(PRTL_ATOM_TABLE AtomTable, ULONG Index)
493 {
494    PRTL_HANDLE_TABLE_ENTRY RtlHandle;
495 
496    if (RtlIsValidIndexHandle(&AtomTable->RtlHandleTable,
497                              Index,
498                              &RtlHandle))
499    {
500       PRTL_ATOM_HANDLE AtomHandle = (PRTL_ATOM_HANDLE)RtlHandle;
501 
502       return AtomHandle->AtomEntry;
503    }
504 
505    return NULL;
506 }
507 
508 /* Ldr SEH-Protected access to IMAGE_NT_HEADERS */
509 
510 /* Rtl SEH-Free version of this */
511 NTSTATUS
512 NTAPI
513 RtlpImageNtHeaderEx(
514     _In_ ULONG Flags,
515     _In_ PVOID Base,
516     _In_ ULONG64 Size,
517     _Out_ PIMAGE_NT_HEADERS *OutHeaders);
518 
519 
520 /*
521  * @implemented
522  * @note: This is here, so that we do not drag SEH into rosload, freeldr and bootmgfw
523  */
524 NTSTATUS
525 NTAPI
526 RtlImageNtHeaderEx(
527     _In_ ULONG Flags,
528     _In_ PVOID Base,
529     _In_ ULONG64 Size,
530     _Out_ PIMAGE_NT_HEADERS *OutHeaders)
531 {
532     NTSTATUS Status;
533 
534     /* Assume failure. This is also done in RtlpImageNtHeaderEx, but this is guarded by SEH. */
535     if (OutHeaders != NULL)
536         *OutHeaders = NULL;
537 
538     _SEH2_TRY
539     {
540         Status = RtlpImageNtHeaderEx(Flags, Base, Size, OutHeaders);
541     }
542     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
543     {
544         /* Fail with the SEH error */
545         Status = _SEH2_GetExceptionCode();
546     }
547     _SEH2_END;
548 
549     return Status;
550 }
551 
552 /*
553  * Ldr Resource support code
554  */
555 
556 IMAGE_RESOURCE_DIRECTORY *find_entry_by_name( IMAGE_RESOURCE_DIRECTORY *dir,
557                                               LPCWSTR name, void *root,
558                                               int want_dir );
559 IMAGE_RESOURCE_DIRECTORY *find_entry_by_id( IMAGE_RESOURCE_DIRECTORY *dir,
560                                             WORD id, void *root, int want_dir );
561 IMAGE_RESOURCE_DIRECTORY *find_first_entry( IMAGE_RESOURCE_DIRECTORY *dir,
562                                             void *root, int want_dir );
563 int push_language( USHORT *list, ULONG pos, WORD lang );
564 
565 /**********************************************************************
566  *  find_entry
567  *
568  * Find a resource entry
569  */
570 NTSTATUS find_entry( PVOID BaseAddress, LDR_RESOURCE_INFO *info,
571                      ULONG level, void **ret, int want_dir )
572 {
573     ULONG size;
574     void *root;
575     IMAGE_RESOURCE_DIRECTORY *resdirptr;
576     USHORT list[9];  /* list of languages to try */
577     int i, pos = 0;
578     LCID user_lcid, system_lcid;
579 
580     root = RtlImageDirectoryEntryToData( BaseAddress, TRUE, IMAGE_DIRECTORY_ENTRY_RESOURCE, &size );
581     if (!root) return STATUS_RESOURCE_DATA_NOT_FOUND;
582     if (size < sizeof(*resdirptr)) return STATUS_RESOURCE_DATA_NOT_FOUND;
583     resdirptr = root;
584 
585     if (!level--) goto done;
586     if (!(*ret = find_entry_by_name( resdirptr, (LPCWSTR)info->Type, root, want_dir || level )))
587         return STATUS_RESOURCE_TYPE_NOT_FOUND;
588     if (!level--) return STATUS_SUCCESS;
589 
590     resdirptr = *ret;
591     if (!(*ret = find_entry_by_name( resdirptr, (LPCWSTR)info->Name, root, want_dir || level )))
592         return STATUS_RESOURCE_NAME_NOT_FOUND;
593     if (!level--) return STATUS_SUCCESS;
594     if (level) return STATUS_INVALID_PARAMETER;  /* level > 3 */
595 
596     /* 1. specified language */
597     pos = push_language( list, pos, info->Language );
598 
599     /* 2. specified language with neutral sublanguage */
600     pos = push_language( list, pos, MAKELANGID( PRIMARYLANGID(info->Language), SUBLANG_NEUTRAL ) );
601 
602     /* 3. neutral language with neutral sublanguage */
603     pos = push_language( list, pos, MAKELANGID( LANG_NEUTRAL, SUBLANG_NEUTRAL ) );
604 
605     /* if no explicitly specified language, try some defaults */
606     if (PRIMARYLANGID(info->Language) == LANG_NEUTRAL)
607     {
608         /* user defaults, unless SYS_DEFAULT sublanguage specified  */
609         if (SUBLANGID(info->Language) != SUBLANG_SYS_DEFAULT)
610         {
611             /* 4. current thread locale language */
612             pos = push_language( list, pos, LANGIDFROMLCID(NtCurrentTeb()->CurrentLocale) );
613 
614             if (NT_SUCCESS(NtQueryDefaultLocale(TRUE, &user_lcid)))
615             {
616                 /* 5. user locale language */
617                 pos = push_language( list, pos, LANGIDFROMLCID(user_lcid) );
618 
619                 /* 6. user locale language with neutral sublanguage  */
620                 pos = push_language( list, pos, MAKELANGID( PRIMARYLANGID(user_lcid), SUBLANG_NEUTRAL ) );
621             }
622         }
623 
624         /* now system defaults */
625 
626         if (NT_SUCCESS(NtQueryDefaultLocale(FALSE, &system_lcid)))
627         {
628             /* 7. system locale language */
629             pos = push_language( list, pos, LANGIDFROMLCID( system_lcid ) );
630 
631             /* 8. system locale language with neutral sublanguage */
632             pos = push_language( list, pos, MAKELANGID( PRIMARYLANGID(system_lcid), SUBLANG_NEUTRAL ) );
633         }
634 
635         /* 9. English */
636         pos = push_language( list, pos, MAKELANGID( LANG_ENGLISH, SUBLANG_DEFAULT ) );
637     }
638 
639     resdirptr = *ret;
640     for (i = 0; i < pos; i++)
641         if ((*ret = find_entry_by_id( resdirptr, list[i], root, want_dir ))) return STATUS_SUCCESS;
642 
643     /* if no explicitly specified language, return the first entry */
644     if (PRIMARYLANGID(info->Language) == LANG_NEUTRAL)
645     {
646         if ((*ret = find_first_entry( resdirptr, root, want_dir ))) return STATUS_SUCCESS;
647     }
648     return STATUS_RESOURCE_LANG_NOT_FOUND;
649 
650 done:
651     *ret = resdirptr;
652     return STATUS_SUCCESS;
653 }
654 
655 /*
656  * @implemented
657  */
658 PVOID NTAPI
659 RtlPcToFileHeader(IN PVOID PcValue,
660                   PVOID* BaseOfImage)
661 {
662     PLIST_ENTRY ModuleListHead;
663     PLIST_ENTRY Entry;
664     PLDR_DATA_TABLE_ENTRY Module;
665     PVOID ImageBase = NULL;
666 
667     RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
668     ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
669     Entry = ModuleListHead->Flink;
670     while (Entry != ModuleListHead)
671     {
672         Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
673 
674         if ((ULONG_PTR)PcValue >= (ULONG_PTR)Module->DllBase &&
675                 (ULONG_PTR)PcValue < (ULONG_PTR)Module->DllBase + Module->SizeOfImage)
676         {
677             ImageBase = Module->DllBase;
678             break;
679         }
680         Entry = Entry->Flink;
681     }
682     RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
683 
684     *BaseOfImage = ImageBase;
685     return ImageBase;
686 }
687 
688 NTSTATUS get_buffer(LPWSTR *buffer, SIZE_T needed, PUNICODE_STRING CallerBuffer, BOOLEAN bAllocateBuffer)
689 {
690     WCHAR *p;
691 
692     if (CallerBuffer && CallerBuffer->MaximumLength > needed)
693     {
694         p = CallerBuffer->Buffer;
695         CallerBuffer->Length = needed - sizeof(WCHAR);
696     }
697     else
698     {
699         if (!bAllocateBuffer)
700             return STATUS_BUFFER_TOO_SMALL;
701 
702         if (CallerBuffer)
703             CallerBuffer->Buffer[0] = 0;
704 
705         p = RtlAllocateHeap(RtlGetProcessHeap(), 0, needed );
706         if (!p)
707             return STATUS_NO_MEMORY;
708     }
709     *buffer = p;
710 
711     return STATUS_SUCCESS;
712 }
713 
714 /* NOTE: Remove this one once our actctx support becomes better */
715 NTSTATUS find_actctx_dll( PUNICODE_STRING pnameW, LPWSTR *fullname, PUNICODE_STRING CallerBuffer, BOOLEAN bAllocateBuffer)
716 {
717     static const WCHAR winsxsW[] = {'\\','w','i','n','s','x','s','\\'};
718     static const WCHAR dotManifestW[] = {'.','m','a','n','i','f','e','s','t',0};
719 
720     ACTIVATION_CONTEXT_ASSEMBLY_DETAILED_INFORMATION *info;
721     ACTCTX_SECTION_KEYED_DATA data;
722     NTSTATUS status;
723     SIZE_T needed, size = 1024;
724     WCHAR *p;
725 
726     data.cbSize = sizeof(data);
727     status = RtlFindActivationContextSectionString( FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX, NULL,
728                                                     ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION,
729                                                     pnameW, &data );
730     if (status != STATUS_SUCCESS)
731     {
732         //DPRINT1("RtlFindActivationContextSectionString returned 0x%x for %wZ\n", status, pnameW);
733         return status;
734     }
735 
736     for (;;)
737     {
738         if (!(info = RtlAllocateHeap( RtlGetProcessHeap(), 0, size )))
739         {
740             status = STATUS_NO_MEMORY;
741             goto done;
742         }
743         status = RtlQueryInformationActivationContext( 0, data.hActCtx, &data.ulAssemblyRosterIndex,
744                                                        AssemblyDetailedInformationInActivationContext,
745                                                        info, size, &needed );
746         if (status == STATUS_SUCCESS) break;
747         if (status != STATUS_BUFFER_TOO_SMALL) goto done;
748         RtlFreeHeap( RtlGetProcessHeap(), 0, info );
749         size = needed;
750     }
751 
752     DPRINT("manifestpath === %S\n", info->lpAssemblyManifestPath);
753     DPRINT("DirectoryName === %S\n", info->lpAssemblyDirectoryName);
754     if (!info->lpAssemblyManifestPath /*|| !info->lpAssemblyDirectoryName*/)
755     {
756         status = STATUS_SXS_KEY_NOT_FOUND;
757         goto done;
758     }
759 
760     if ((p = wcsrchr( info->lpAssemblyManifestPath, '\\' )))
761     {
762         DWORD dirlen = info->ulAssemblyDirectoryNameLength / sizeof(WCHAR);
763 
764         p++;
765         if (!info->lpAssemblyDirectoryName || _wcsnicmp( p, info->lpAssemblyDirectoryName, dirlen ) || wcsicmp( p + dirlen, dotManifestW ))
766         {
767             /* manifest name does not match directory name, so it's not a global
768              * windows/winsxs manifest; use the manifest directory name instead */
769             dirlen = p - info->lpAssemblyManifestPath;
770             needed = (dirlen + 1) * sizeof(WCHAR) + pnameW->Length;
771 
772             status = get_buffer(fullname, needed, CallerBuffer, bAllocateBuffer);
773             if (!NT_SUCCESS(status))
774                 goto done;
775 
776             p = *fullname;
777 
778             memcpy( p, info->lpAssemblyManifestPath, dirlen * sizeof(WCHAR) );
779             p += dirlen;
780             memcpy( p, pnameW->Buffer, pnameW->Length);
781             p += (pnameW->Length / sizeof(WCHAR));
782             *p = L'\0';
783 
784             goto done;
785         }
786     }
787 
788     needed = (wcslen(SharedUserData->NtSystemRoot) * sizeof(WCHAR) +
789               sizeof(winsxsW) + info->ulAssemblyDirectoryNameLength + pnameW->Length + 2*sizeof(WCHAR));
790 
791     status = get_buffer(fullname, needed, CallerBuffer, bAllocateBuffer);
792     if (!NT_SUCCESS(status))
793         goto done;
794 
795     p = *fullname;
796 
797     wcscpy( p, SharedUserData->NtSystemRoot );
798     p += wcslen(p);
799     memcpy( p, winsxsW, sizeof(winsxsW) );
800     p += sizeof(winsxsW) / sizeof(WCHAR);
801     memcpy( p, info->lpAssemblyDirectoryName, info->ulAssemblyDirectoryNameLength );
802     p += info->ulAssemblyDirectoryNameLength / sizeof(WCHAR);
803     *p++ = L'\\';
804     memcpy( p, pnameW->Buffer, pnameW->Length);
805     p += (pnameW->Length / sizeof(WCHAR));
806     *p = L'\0';
807 
808 done:
809     RtlFreeHeap( RtlGetProcessHeap(), 0, info );
810     RtlReleaseActivationContext( data.hActCtx );
811     DPRINT("%S\n", fullname);
812     return status;
813 }
814 
815 /*
816  * @unimplemented
817  */
818 NTSYSAPI
819 NTSTATUS
820 NTAPI
821 RtlDosApplyFileIsolationRedirection_Ustr(IN ULONG Flags,
822                                          IN PUNICODE_STRING OriginalName,
823                                          IN PUNICODE_STRING Extension,
824                                          IN OUT PUNICODE_STRING StaticString,
825                                          IN OUT PUNICODE_STRING DynamicString,
826                                          IN OUT PUNICODE_STRING *NewName,
827                                          IN PULONG NewFlags,
828                                          IN PSIZE_T FileNameSize,
829                                          IN PSIZE_T RequiredLength)
830 {
831     NTSTATUS Status;
832     LPWSTR fullname;
833     WCHAR buffer [MAX_PATH];
834     UNICODE_STRING localStr, localStr2, *pstrParam;
835     WCHAR *p;
836     BOOLEAN GotExtension;
837     WCHAR c;
838     C_ASSERT(sizeof(UNICODE_NULL) == sizeof(WCHAR));
839 
840 
841     /* Check for invalid parameters */
842     if (!OriginalName)
843     {
844         return STATUS_INVALID_PARAMETER;
845     }
846 
847     if (!DynamicString && !StaticString)
848     {
849         return STATUS_INVALID_PARAMETER;
850     }
851 
852     if ((DynamicString) && (StaticString) && !(NewName))
853     {
854         return STATUS_INVALID_PARAMETER;
855     }
856 
857     if (!OriginalName->Buffer || OriginalName->Length == 0)
858     {
859         return STATUS_SXS_KEY_NOT_FOUND;
860     }
861 
862     if (StaticString && (OriginalName == StaticString || OriginalName->Buffer == StaticString->Buffer))
863     {
864         return STATUS_SXS_KEY_NOT_FOUND;
865     }
866 
867     if (NtCurrentPeb()->ProcessParameters &&
868         (NtCurrentPeb()->ProcessParameters->Flags & RTL_USER_PROCESS_PARAMETERS_PRIVATE_DLL_PATH))
869     {
870         UNICODE_STRING RealName, LocalName;
871         WCHAR RealNameBuf[MAX_PATH], LocalNameBuf[MAX_PATH];
872 
873         RtlInitEmptyUnicodeString(&RealName, RealNameBuf, sizeof(RealNameBuf));
874         RtlInitEmptyUnicodeString(&LocalName, LocalNameBuf, sizeof(LocalNameBuf));
875 
876         Status = RtlComputePrivatizedDllName_U(OriginalName, &RealName, &LocalName);
877         if (!NT_SUCCESS(Status))
878         {
879             DPRINT1("RtlComputePrivatizedDllName_U failed for %wZ: 0x%lx\n", OriginalName, Status);
880             return Status;
881         }
882 
883         if (RtlDoesFileExists_UStr(&LocalName))
884         {
885             Status = get_buffer(&fullname, LocalName.Length + sizeof(UNICODE_NULL), StaticString, DynamicString != NULL);
886             if (NT_SUCCESS(Status))
887             {
888                 RtlCopyMemory(fullname, LocalName.Buffer, LocalName.Length + sizeof(UNICODE_NULL));
889             }
890             else
891             {
892                 DPRINT1("Error while retrieving buffer for %wZ: 0x%lx\n", OriginalName, Status);
893             }
894         }
895         else if (RtlDoesFileExists_UStr(&RealName))
896         {
897             Status = get_buffer(&fullname, RealName.Length + sizeof(UNICODE_NULL), StaticString, DynamicString != NULL);
898             if (NT_SUCCESS(Status))
899             {
900                 RtlCopyMemory(fullname, RealName.Buffer, RealName.Length + sizeof(UNICODE_NULL));
901             }
902             else
903             {
904                 DPRINT1("Error while retrieving buffer for %wZ: 0x%lx\n", OriginalName, Status);
905             }
906         }
907         else
908         {
909             Status = STATUS_NOT_FOUND;
910         }
911 
912         if (RealName.Buffer != RealNameBuf)
913             RtlFreeUnicodeString(&RealName);
914         if (LocalName.Buffer != LocalNameBuf)
915             RtlFreeUnicodeString(&LocalName);
916 
917         if (NT_SUCCESS(Status))
918         {
919             DPRINT("Redirecting %wZ to %S\n", OriginalName, fullname);
920             if (!StaticString || StaticString->Buffer != fullname)
921             {
922                 RtlInitUnicodeString(DynamicString, fullname);
923                 *NewName = DynamicString;
924             }
925             else
926             {
927                 *NewName = StaticString;
928             }
929             return Status;
930         }
931     }
932 
933     pstrParam = OriginalName;
934 
935     /* Get the file name with an extension */
936     p = OriginalName->Buffer + OriginalName->Length / sizeof(WCHAR) - 1;
937     GotExtension = FALSE;
938     while (p >= OriginalName->Buffer)
939     {
940         c = *p--;
941         if (c == L'.')
942         {
943             GotExtension = TRUE;
944         }
945         else if (c == L'\\')
946         {
947             localStr.Buffer = p + 2;
948             localStr.Length = OriginalName->Length - ((ULONG_PTR)localStr.Buffer - (ULONG_PTR)OriginalName->Buffer);
949             localStr.MaximumLength = OriginalName->MaximumLength - ((ULONG_PTR)localStr.Buffer - (ULONG_PTR)OriginalName->Buffer);
950             pstrParam = &localStr;
951             break;
952         }
953     }
954 
955     if (!GotExtension)
956     {
957         if (!Extension)
958         {
959             return STATUS_SXS_KEY_NOT_FOUND;
960         }
961 
962         if (pstrParam->Length + Extension->Length > sizeof(buffer))
963         {
964             //FIXME!
965             return STATUS_NO_MEMORY;
966         }
967 
968         RtlInitEmptyUnicodeString(&localStr2, buffer, sizeof(buffer));
969         RtlAppendUnicodeStringToString(&localStr2, pstrParam);
970         RtlAppendUnicodeStringToString(&localStr2, Extension);
971         pstrParam = &localStr2;
972     }
973 
974     /* Use wine's function as long as we use wine's sxs implementation in ntdll */
975     Status = find_actctx_dll(pstrParam, &fullname, StaticString, DynamicString != NULL);
976     if (!NT_SUCCESS(Status))
977     {
978         return Status;
979     }
980 
981     DPRINT("Redirecting %wZ to %S\n", OriginalName, fullname);
982 
983     if (!StaticString || StaticString->Buffer != fullname)
984     {
985         RtlInitUnicodeString(DynamicString, fullname);
986         *NewName = DynamicString;
987     }
988     else
989     {
990         *NewName = StaticString;
991     }
992 
993     return Status;
994 }
995 
996 /*
997  * @implemented
998  */
999 NTSYSAPI
1000 NTSTATUS
1001 NTAPI
1002 RtlWow64EnableFsRedirection(IN BOOLEAN Wow64FsEnableRedirection)
1003 {
1004     /* This is what Windows returns on x86 */
1005     return STATUS_NOT_IMPLEMENTED;
1006 }
1007 
1008 /*
1009  * @implemented
1010  */
1011 NTSYSAPI
1012 NTSTATUS
1013 NTAPI
1014 RtlWow64EnableFsRedirectionEx(IN PVOID Wow64FsEnableRedirection,
1015                               OUT PVOID *OldFsRedirectionLevel)
1016 {
1017     /* This is what Windows returns on x86 */
1018     return STATUS_NOT_IMPLEMENTED;
1019 }
1020 
1021 /*
1022  * @unimplemented
1023  */
1024 NTSYSAPI
1025 NTSTATUS
1026 NTAPI
1027 RtlComputeImportTableHash(IN HANDLE FileHandle,
1028                           OUT PCHAR Hash,
1029                           IN ULONG ImportTableHashSize)
1030 {
1031     UNIMPLEMENTED;
1032     return STATUS_NOT_IMPLEMENTED;
1033 }
1034 
1035 NTSTATUS
1036 NTAPI
1037 RtlpSafeCopyMemory(
1038    _Out_writes_bytes_all_(Length) VOID UNALIGNED *Destination,
1039    _In_reads_bytes_(Length) CONST VOID UNALIGNED *Source,
1040    _In_ SIZE_T Length)
1041 {
1042     _SEH2_TRY
1043     {
1044         RtlCopyMemory(Destination, Source, Length);
1045     }
1046     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1047     {
1048         _SEH2_YIELD(return _SEH2_GetExceptionCode());
1049     }
1050     _SEH2_END;
1051 
1052     return STATUS_SUCCESS;
1053 }
1054 
1055 /* FIXME: code duplication with kernel32/client/time.c */
1056 ULONG
1057 NTAPI
1058 RtlGetTickCount(VOID)
1059 {
1060     ULARGE_INTEGER TickCount;
1061 
1062 #ifdef _WIN64
1063     TickCount.QuadPart = *((volatile ULONG64*)&SharedUserData->TickCount);
1064 #else
1065     while (TRUE)
1066     {
1067         TickCount.HighPart = (ULONG)SharedUserData->TickCount.High1Time;
1068         TickCount.LowPart = SharedUserData->TickCount.LowPart;
1069 
1070         if (TickCount.HighPart == (ULONG)SharedUserData->TickCount.High2Time)
1071             break;
1072 
1073         YieldProcessor();
1074     }
1075 #endif
1076 
1077     return (ULONG)((UInt32x32To64(TickCount.LowPart,
1078                                   SharedUserData->TickCountMultiplier) >> 24) +
1079                     UInt32x32To64((TickCount.HighPart << 8) & 0xFFFFFFFF,
1080                                   SharedUserData->TickCountMultiplier));
1081 }
1082 
1083 /* EOF */
1084