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