[NTDLL] Implement RtlDosApplyFileIsolationRedirection_Ustr based on existing wine...
[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
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
509 /*
510 * Ldr Resource support code
511 */
512
513 IMAGE_RESOURCE_DIRECTORY *find_entry_by_name( IMAGE_RESOURCE_DIRECTORY *dir,
514 LPCWSTR name, void *root,
515 int want_dir );
516 IMAGE_RESOURCE_DIRECTORY *find_entry_by_id( IMAGE_RESOURCE_DIRECTORY *dir,
517 WORD id, void *root, int want_dir );
518 IMAGE_RESOURCE_DIRECTORY *find_first_entry( IMAGE_RESOURCE_DIRECTORY *dir,
519 void *root, int want_dir );
520 int push_language( USHORT *list, ULONG pos, WORD lang );
521
522 /**********************************************************************
523 * find_entry
524 *
525 * Find a resource entry
526 */
527 NTSTATUS find_entry( PVOID BaseAddress, LDR_RESOURCE_INFO *info,
528 ULONG level, void **ret, int want_dir )
529 {
530 ULONG size;
531 void *root;
532 IMAGE_RESOURCE_DIRECTORY *resdirptr;
533 USHORT list[9]; /* list of languages to try */
534 int i, pos = 0;
535 LCID user_lcid, system_lcid;
536
537 root = RtlImageDirectoryEntryToData( BaseAddress, TRUE, IMAGE_DIRECTORY_ENTRY_RESOURCE, &size );
538 if (!root) return STATUS_RESOURCE_DATA_NOT_FOUND;
539 if (size < sizeof(*resdirptr)) return STATUS_RESOURCE_DATA_NOT_FOUND;
540 resdirptr = root;
541
542 if (!level--) goto done;
543 if (!(*ret = find_entry_by_name( resdirptr, (LPCWSTR)info->Type, root, want_dir || level )))
544 return STATUS_RESOURCE_TYPE_NOT_FOUND;
545 if (!level--) return STATUS_SUCCESS;
546
547 resdirptr = *ret;
548 if (!(*ret = find_entry_by_name( resdirptr, (LPCWSTR)info->Name, root, want_dir || level )))
549 return STATUS_RESOURCE_NAME_NOT_FOUND;
550 if (!level--) return STATUS_SUCCESS;
551 if (level) return STATUS_INVALID_PARAMETER; /* level > 3 */
552
553 /* 1. specified language */
554 pos = push_language( list, pos, info->Language );
555
556 /* 2. specified language with neutral sublanguage */
557 pos = push_language( list, pos, MAKELANGID( PRIMARYLANGID(info->Language), SUBLANG_NEUTRAL ) );
558
559 /* 3. neutral language with neutral sublanguage */
560 pos = push_language( list, pos, MAKELANGID( LANG_NEUTRAL, SUBLANG_NEUTRAL ) );
561
562 /* if no explicitly specified language, try some defaults */
563 if (PRIMARYLANGID(info->Language) == LANG_NEUTRAL)
564 {
565 /* user defaults, unless SYS_DEFAULT sublanguage specified */
566 if (SUBLANGID(info->Language) != SUBLANG_SYS_DEFAULT)
567 {
568 /* 4. current thread locale language */
569 pos = push_language( list, pos, LANGIDFROMLCID(NtCurrentTeb()->CurrentLocale) );
570
571 if (NT_SUCCESS(NtQueryDefaultLocale(TRUE, &user_lcid)))
572 {
573 /* 5. user locale language */
574 pos = push_language( list, pos, LANGIDFROMLCID(user_lcid) );
575
576 /* 6. user locale language with neutral sublanguage */
577 pos = push_language( list, pos, MAKELANGID( PRIMARYLANGID(user_lcid), SUBLANG_NEUTRAL ) );
578 }
579 }
580
581 /* now system defaults */
582
583 if (NT_SUCCESS(NtQueryDefaultLocale(FALSE, &system_lcid)))
584 {
585 /* 7. system locale language */
586 pos = push_language( list, pos, LANGIDFROMLCID( system_lcid ) );
587
588 /* 8. system locale language with neutral sublanguage */
589 pos = push_language( list, pos, MAKELANGID( PRIMARYLANGID(system_lcid), SUBLANG_NEUTRAL ) );
590 }
591
592 /* 9. English */
593 pos = push_language( list, pos, MAKELANGID( LANG_ENGLISH, SUBLANG_DEFAULT ) );
594 }
595
596 resdirptr = *ret;
597 for (i = 0; i < pos; i++)
598 if ((*ret = find_entry_by_id( resdirptr, list[i], root, want_dir ))) return STATUS_SUCCESS;
599
600 /* if no explicitly specified language, return the first entry */
601 if (PRIMARYLANGID(info->Language) == LANG_NEUTRAL)
602 {
603 if ((*ret = find_first_entry( resdirptr, root, want_dir ))) return STATUS_SUCCESS;
604 }
605 return STATUS_RESOURCE_LANG_NOT_FOUND;
606
607 done:
608 *ret = resdirptr;
609 return STATUS_SUCCESS;
610 }
611
612 /*
613 * @implemented
614 */
615 PVOID NTAPI
616 RtlPcToFileHeader(IN PVOID PcValue,
617 PVOID* BaseOfImage)
618 {
619 PLIST_ENTRY ModuleListHead;
620 PLIST_ENTRY Entry;
621 PLDR_DATA_TABLE_ENTRY Module;
622 PVOID ImageBase = NULL;
623
624 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
625 ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
626 Entry = ModuleListHead->Flink;
627 while (Entry != ModuleListHead)
628 {
629 Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
630
631 if ((ULONG_PTR)PcValue >= (ULONG_PTR)Module->DllBase &&
632 (ULONG_PTR)PcValue < (ULONG_PTR)Module->DllBase + Module->SizeOfImage)
633 {
634 ImageBase = Module->DllBase;
635 break;
636 }
637 Entry = Entry->Flink;
638 }
639 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
640
641 *BaseOfImage = ImageBase;
642 return ImageBase;
643 }
644
645 NTSTATUS get_buffer(LPWSTR *buffer, SIZE_T needed, PUNICODE_STRING CallerBuffer, BOOLEAN bAllocateBuffer)
646 {
647 WCHAR *p;
648
649 if (CallerBuffer && CallerBuffer->MaximumLength > needed)
650 {
651 p = CallerBuffer->Buffer;
652 CallerBuffer->Length = needed - sizeof(WCHAR);
653 }
654 else
655 {
656 if (!bAllocateBuffer)
657 return STATUS_BUFFER_TOO_SMALL;
658
659 if (CallerBuffer)
660 CallerBuffer->Buffer[0] = 0;
661
662 p = RtlAllocateHeap(RtlGetProcessHeap(), 0, needed );
663 if (!p)
664 return STATUS_NO_MEMORY;
665 }
666 *buffer = p;
667
668 return STATUS_SUCCESS;
669 }
670
671 /* NOTE: Remove this one once our actctx support becomes better */
672 NTSTATUS find_actctx_dll( PUNICODE_STRING pnameW, LPWSTR *fullname, PUNICODE_STRING CallerBuffer, BOOLEAN bAllocateBuffer)
673 {
674 static const WCHAR winsxsW[] = {'\\','w','i','n','s','x','s','\\'};
675 static const WCHAR dotManifestW[] = {'.','m','a','n','i','f','e','s','t',0};
676
677 ACTIVATION_CONTEXT_ASSEMBLY_DETAILED_INFORMATION *info;
678 ACTCTX_SECTION_KEYED_DATA data;
679 NTSTATUS status;
680 SIZE_T needed, size = 1024;
681 WCHAR *p;
682
683 data.cbSize = sizeof(data);
684 status = RtlFindActivationContextSectionString( FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX, NULL,
685 ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION,
686 pnameW, &data );
687 if (status != STATUS_SUCCESS)
688 {
689 //DPRINT1("RtlFindActivationContextSectionString returned 0x%x for %wZ\n", status, pnameW);
690 return status;
691 }
692
693 for (;;)
694 {
695 if (!(info = RtlAllocateHeap( RtlGetProcessHeap(), 0, size )))
696 {
697 status = STATUS_NO_MEMORY;
698 goto done;
699 }
700 status = RtlQueryInformationActivationContext( 0, data.hActCtx, &data.ulAssemblyRosterIndex,
701 AssemblyDetailedInformationInActivationContext,
702 info, size, &needed );
703 if (status == STATUS_SUCCESS) break;
704 if (status != STATUS_BUFFER_TOO_SMALL) goto done;
705 RtlFreeHeap( RtlGetProcessHeap(), 0, info );
706 size = needed;
707 }
708
709 DPRINT("manifestpath === %S\n", info->lpAssemblyManifestPath);
710 DPRINT("DirectoryName === %S\n", info->lpAssemblyDirectoryName);
711 if (!info->lpAssemblyManifestPath /*|| !info->lpAssemblyDirectoryName*/)
712 {
713 status = STATUS_SXS_KEY_NOT_FOUND;
714 goto done;
715 }
716
717 if ((p = wcsrchr( info->lpAssemblyManifestPath, '\\' )))
718 {
719 DWORD dirlen = info->ulAssemblyDirectoryNameLength / sizeof(WCHAR);
720
721 p++;
722 if (!info->lpAssemblyDirectoryName || _wcsnicmp( p, info->lpAssemblyDirectoryName, dirlen ) || wcsicmp( p + dirlen, dotManifestW ))
723 {
724 /* manifest name does not match directory name, so it's not a global
725 * windows/winsxs manifest; use the manifest directory name instead */
726 dirlen = p - info->lpAssemblyManifestPath;
727 needed = (dirlen + 1) * sizeof(WCHAR) + pnameW->Length;
728
729 status = get_buffer(fullname, needed, CallerBuffer, bAllocateBuffer);
730 if (!NT_SUCCESS(status))
731 goto done;
732
733 p = *fullname;
734
735 memcpy( p, info->lpAssemblyManifestPath, dirlen * sizeof(WCHAR) );
736 p += dirlen;
737 memcpy( p, pnameW->Buffer, pnameW->Length);
738 p += (pnameW->Length / sizeof(WCHAR));
739 *p = L'\0';
740
741 goto done;
742 }
743 }
744
745 needed = (wcslen(SharedUserData->NtSystemRoot) * sizeof(WCHAR) +
746 sizeof(winsxsW) + info->ulAssemblyDirectoryNameLength + pnameW->Length + 2*sizeof(WCHAR));
747
748 status = get_buffer(fullname, needed, CallerBuffer, bAllocateBuffer);
749 if (!NT_SUCCESS(status))
750 goto done;
751
752 p = *fullname;
753
754 wcscpy( p, SharedUserData->NtSystemRoot );
755 p += wcslen(p);
756 memcpy( p, winsxsW, sizeof(winsxsW) );
757 p += sizeof(winsxsW) / sizeof(WCHAR);
758 memcpy( p, info->lpAssemblyDirectoryName, info->ulAssemblyDirectoryNameLength );
759 p += info->ulAssemblyDirectoryNameLength / sizeof(WCHAR);
760 *p++ = L'\\';
761 memcpy( p, pnameW->Buffer, pnameW->Length);
762 p += (pnameW->Length / sizeof(WCHAR));
763 *p = L'\0';
764
765 done:
766 RtlFreeHeap( RtlGetProcessHeap(), 0, info );
767 RtlReleaseActivationContext( data.hActCtx );
768 DPRINT("%S\n", fullname);
769 return status;
770 }
771
772 /*
773 * @unimplemented
774 */
775 NTSYSAPI
776 NTSTATUS
777 NTAPI
778 RtlDosApplyFileIsolationRedirection_Ustr(IN ULONG Flags,
779 IN PUNICODE_STRING OriginalName,
780 IN PUNICODE_STRING Extension,
781 IN OUT PUNICODE_STRING StaticString,
782 IN OUT PUNICODE_STRING DynamicString,
783 IN OUT PUNICODE_STRING *NewName,
784 IN PULONG NewFlags,
785 IN PSIZE_T FileNameSize,
786 IN PSIZE_T RequiredLength)
787 {
788 NTSTATUS Status;
789 LPWSTR fullname;
790 WCHAR buffer [MAX_PATH];
791 UNICODE_STRING localStr, localStr2, *pstrParam;
792 WCHAR *p;
793 BOOLEAN GotExtension;
794 WCHAR c;
795
796 /* Check for invalid parameters */
797 if (!OriginalName)
798 {
799 return STATUS_INVALID_PARAMETER;
800 }
801
802 if (!DynamicString && !StaticString)
803 {
804 return STATUS_INVALID_PARAMETER;
805 }
806
807 if ((DynamicString) && (StaticString) && !(NewName))
808 {
809 return STATUS_INVALID_PARAMETER;
810 }
811
812 if (!OriginalName->Buffer || OriginalName->Length == 0)
813 {
814 return STATUS_SXS_KEY_NOT_FOUND;
815 }
816
817 if (StaticString && (OriginalName == StaticString || OriginalName->Buffer == StaticString->Buffer))
818 {
819 return STATUS_SXS_KEY_NOT_FOUND;
820 }
821
822 pstrParam = OriginalName;
823
824 /* Get the file name with an extension */
825 p = OriginalName->Buffer + OriginalName->Length / sizeof(WCHAR) - 1;
826 GotExtension = FALSE;
827 while (p >= OriginalName->Buffer)
828 {
829 c = *p--;
830 if (c == L'.')
831 {
832 GotExtension = TRUE;
833 }
834 else if (c == L'\\')
835 {
836 localStr.Buffer = p + 2;
837 localStr.Length = OriginalName->Length - ((ULONG_PTR)localStr.Buffer - (ULONG_PTR)OriginalName->Buffer);
838 localStr.MaximumLength = OriginalName->MaximumLength - ((ULONG_PTR)localStr.Buffer - (ULONG_PTR)OriginalName->Buffer);
839 pstrParam = &localStr;
840 break;
841 }
842 }
843
844 if (!GotExtension)
845 {
846 if (!Extension)
847 {
848 return STATUS_SXS_KEY_NOT_FOUND;
849 }
850
851 if (pstrParam->Length + Extension->Length > sizeof(buffer))
852 {
853 //FIXME!
854 return STATUS_NO_MEMORY;
855 }
856
857 RtlInitEmptyUnicodeString(&localStr2, buffer, sizeof(buffer));
858 RtlAppendUnicodeStringToString(&localStr2, pstrParam);
859 RtlAppendUnicodeStringToString(&localStr2, Extension);
860 pstrParam = &localStr2;
861 }
862
863 /* Use wine's function as long as we use wine's sxs implementation in ntdll */
864 Status = find_actctx_dll(pstrParam, &fullname, StaticString, DynamicString != NULL);
865 if (!NT_SUCCESS(Status))
866 {
867 return Status;
868 }
869
870 DPRINT("Redirecting %wZ to %S\n", OriginalName, fullname);
871
872 if (!StaticString || StaticString->Buffer != fullname)
873 {
874 RtlInitUnicodeString(DynamicString, fullname);
875 *NewName = DynamicString;
876 }
877 else
878 {
879 *NewName = StaticString;
880 }
881
882 return Status;
883 }
884
885 /*
886 * @implemented
887 */
888 NTSYSAPI
889 NTSTATUS
890 NTAPI
891 RtlWow64EnableFsRedirection(IN BOOLEAN Wow64FsEnableRedirection)
892 {
893 /* This is what Windows returns on x86 */
894 return STATUS_NOT_IMPLEMENTED;
895 }
896
897 /*
898 * @implemented
899 */
900 NTSYSAPI
901 NTSTATUS
902 NTAPI
903 RtlWow64EnableFsRedirectionEx(IN PVOID Wow64FsEnableRedirection,
904 OUT PVOID *OldFsRedirectionLevel)
905 {
906 /* This is what Windows returns on x86 */
907 return STATUS_NOT_IMPLEMENTED;
908 }
909
910 /*
911 * @unimplemented
912 */
913 NTSYSAPI
914 NTSTATUS
915 NTAPI
916 RtlComputeImportTableHash(IN HANDLE FileHandle,
917 OUT PCHAR Hash,
918 IN ULONG ImportTableHashSize)
919 {
920 UNIMPLEMENTED;
921 return STATUS_NOT_IMPLEMENTED;
922 }
923
924 NTSTATUS
925 NTAPI
926 RtlpSafeCopyMemory(
927 _Out_writes_bytes_all_(Length) VOID UNALIGNED *Destination,
928 _In_reads_bytes_(Length) CONST VOID UNALIGNED *Source,
929 _In_ SIZE_T Length)
930 {
931 _SEH2_TRY
932 {
933 RtlCopyMemory(Destination, Source, Length);
934 }
935 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
936 {
937 _SEH2_YIELD(return _SEH2_GetExceptionCode());
938 }
939 _SEH2_END;
940
941 return STATUS_SUCCESS;
942 }
943
944 /* FIXME: code duplication with kernel32/client/time.c */
945 ULONG
946 NTAPI
947 RtlGetTickCount(VOID)
948 {
949 ULARGE_INTEGER TickCount;
950
951 #ifdef _WIN64
952 TickCount.QuadPart = *((volatile ULONG64*)&SharedUserData->TickCount);
953 #else
954 while (TRUE)
955 {
956 TickCount.HighPart = (ULONG)SharedUserData->TickCount.High1Time;
957 TickCount.LowPart = SharedUserData->TickCount.LowPart;
958
959 if (TickCount.HighPart == (ULONG)SharedUserData->TickCount.High2Time)
960 break;
961
962 YieldProcessor();
963 }
964 #endif
965
966 return (ULONG)((UInt32x32To64(TickCount.LowPart,
967 SharedUserData->TickCountMultiplier) >> 24) +
968 UInt32x32To64((TickCount.HighPart << 8) & 0xFFFFFFFF,
969 SharedUserData->TickCountMultiplier));
970 }
971
972 /* EOF */