2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS system libraries
4 * FILE: lib/kernel32/misc/utils.c
5 * PURPOSE: Utility and Support Functions
6 * PROGRAMMER: Alex Ionescu (alex@relsoft.net)
7 * Pierre Schweitzer (pierre.schweitzer@reactos.org)
10 /* INCLUDES ******************************************************************/
14 #include "i386/ketypes.h"
15 #elif defined _M_AMD64
16 #include "amd64/ketypes.h"
22 /* GLOBALS ********************************************************************/
24 UNICODE_STRING Restricted
= RTL_CONSTANT_STRING(L
"Restricted");
25 BOOL bIsFileApiAnsi
= TRUE
; // set the file api to ansi or oem
26 PRTL_CONVERT_STRING Basep8BitStringToUnicodeString
= RtlAnsiStringToUnicodeString
;
27 PRTL_CONVERT_STRINGA BasepUnicodeStringTo8BitString
= RtlUnicodeStringToAnsiString
;
28 PRTL_COUNT_STRING BasepUnicodeStringTo8BitSize
= BasepUnicodeStringToAnsiSize
;
29 PRTL_COUNT_STRINGA Basep8BitStringToUnicodeSize
= BasepAnsiStringToUnicodeSize
;
31 /* FUNCTIONS ******************************************************************/
35 BasepUnicodeStringToOemSize(IN PUNICODE_STRING String
)
37 return RtlUnicodeStringToOemSize(String
);
42 BasepOemStringToUnicodeSize(IN PANSI_STRING String
)
44 return RtlOemStringToUnicodeSize(String
);
49 BasepUnicodeStringToAnsiSize(IN PUNICODE_STRING String
)
51 return RtlUnicodeStringToAnsiSize(String
);
56 BasepAnsiStringToUnicodeSize(IN PANSI_STRING String
)
58 return RtlAnsiStringToUnicodeSize(String
);
63 BaseGetNamedObjectDirectory(VOID
)
65 OBJECT_ATTRIBUTES ObjectAttributes
;
67 HANDLE DirHandle
, BnoHandle
, Token
, NewToken
;
69 if (BaseNamedObjectDirectory
) return BaseNamedObjectDirectory
;
71 if (NtCurrentTeb()->IsImpersonating
)
73 Status
= NtOpenThreadToken(NtCurrentThread(),
77 if (!NT_SUCCESS(Status
)) return BaseNamedObjectDirectory
;
80 Status
= NtSetInformationThread(NtCurrentThread(),
81 ThreadImpersonationToken
,
84 if (!NT_SUCCESS (Status
))
87 return BaseNamedObjectDirectory
;
96 if (BaseNamedObjectDirectory
) goto Quickie
;
98 InitializeObjectAttributes(&ObjectAttributes
,
99 &BaseStaticServerData
->NamedObjectDirectory
,
100 OBJ_CASE_INSENSITIVE
,
104 Status
= NtOpenDirectoryObject(&BnoHandle
,
107 DIRECTORY_CREATE_OBJECT
|
108 DIRECTORY_CREATE_SUBDIRECTORY
,
110 if (!NT_SUCCESS(Status
))
112 Status
= NtOpenDirectoryObject(&DirHandle
,
116 if (NT_SUCCESS(Status
))
118 InitializeObjectAttributes(&ObjectAttributes
,
119 (PUNICODE_STRING
)&Restricted
,
120 OBJ_CASE_INSENSITIVE
,
124 Status
= NtOpenDirectoryObject(&BnoHandle
,
127 DIRECTORY_CREATE_OBJECT
|
128 DIRECTORY_CREATE_SUBDIRECTORY
,
135 if (NT_SUCCESS(Status
)) BaseNamedObjectDirectory
= BnoHandle
;
143 NtSetInformationThread(NtCurrentThread(),
144 ThreadImpersonationToken
,
151 return BaseNamedObjectDirectory
;
156 BasepLocateExeLdrEntry(IN PLDR_DATA_TABLE_ENTRY Entry
,
158 OUT BOOLEAN
*StopEnumeration
)
160 /* Make sure we get Entry, Context and valid StopEnumeration pointer */
163 ASSERT(StopEnumeration
);
165 /* If entry is already found - signal to stop */
166 if (BasepExeLdrEntry
)
168 *StopEnumeration
= TRUE
;
172 /* Otherwise keep enumerating until we find a match */
173 if (Entry
->DllBase
== Context
)
175 /* It matches, so remember the ldr entry */
176 BasepExeLdrEntry
= Entry
;
178 /* And stop enumeration */
179 *StopEnumeration
= TRUE
;
184 * Converts an ANSI or OEM String to the TEB StaticUnicodeString
188 Basep8BitStringToStaticUnicodeString(IN LPCSTR String
)
190 PUNICODE_STRING StaticString
= &(NtCurrentTeb()->StaticUnicodeString
);
191 ANSI_STRING AnsiString
;
194 /* Initialize an ANSI String */
195 Status
= RtlInitAnsiStringEx(&AnsiString
, String
);
196 if (!NT_SUCCESS(Status
))
198 Status
= STATUS_BUFFER_OVERFLOW
;
203 Status
= Basep8BitStringToUnicodeString(StaticString
, &AnsiString
, FALSE
);
206 if (NT_SUCCESS(Status
)) return StaticString
;
208 if (Status
== STATUS_BUFFER_OVERFLOW
)
210 SetLastError(ERROR_FILENAME_EXCED_RANGE
);
214 BaseSetLastNTError(Status
);
221 * Allocates space from the Heap and converts an Unicode String into it
225 Basep8BitStringToDynamicUnicodeString(OUT PUNICODE_STRING UnicodeString
,
228 ANSI_STRING AnsiString
;
231 /* Initialize an ANSI String */
232 Status
= RtlInitAnsiStringEx(&AnsiString
, String
);
233 if (!NT_SUCCESS(Status
))
235 Status
= STATUS_BUFFER_OVERFLOW
;
240 Status
= Basep8BitStringToUnicodeString(UnicodeString
, &AnsiString
, TRUE
);
243 if (NT_SUCCESS(Status
)) return TRUE
;
245 if (Status
== STATUS_BUFFER_OVERFLOW
)
247 SetLastError(ERROR_FILENAME_EXCED_RANGE
);
251 BaseSetLastNTError(Status
);
258 * Allocates space from the Heap and converts an Ansi String into it
260 /*NOTE: API IS A HACK */
263 BasepAnsiStringToHeapUnicodeString(IN LPCSTR AnsiString
,
264 OUT LPWSTR
* UnicodeString
)
266 ANSI_STRING AnsiTemp
;
267 UNICODE_STRING UnicodeTemp
;
269 DPRINT("BasepAnsiStringToHeapUnicodeString\n");
271 /* First create the ANSI_STRING */
272 RtlInitAnsiString(&AnsiTemp
, AnsiString
);
274 if (NT_SUCCESS(RtlAnsiStringToUnicodeString(&UnicodeTemp
,
278 *UnicodeString
= UnicodeTemp
.Buffer
;
282 *UnicodeString
= NULL
;
288 BaseFormatTimeOut(OUT PLARGE_INTEGER Timeout
,
289 IN DWORD dwMilliseconds
)
291 /* Check if this is an infinite wait, which means no timeout argument */
292 if (dwMilliseconds
== INFINITE
) return NULL
;
294 /* Otherwise, convert the time to NT Format */
295 Timeout
->QuadPart
= UInt32x32To64(dwMilliseconds
, -10000);
300 * Converts lpSecurityAttributes + Object Name into ObjectAttributes.
304 BaseFormatObjectAttributes(OUT POBJECT_ATTRIBUTES ObjectAttributes
,
305 IN PSECURITY_ATTRIBUTES SecurityAttributes OPTIONAL
,
306 IN PUNICODE_STRING ObjectName
)
309 HANDLE RootDirectory
;
310 PVOID SecurityDescriptor
;
311 DPRINT("BaseFormatObjectAttributes. Security: %p, Name: %p\n",
312 SecurityAttributes
, ObjectName
);
314 /* Get the attributes if present */
315 if (SecurityAttributes
)
317 Attributes
= SecurityAttributes
->bInheritHandle
? OBJ_INHERIT
: 0;
318 SecurityDescriptor
= SecurityAttributes
->lpSecurityDescriptor
;
322 if (!ObjectName
) return NULL
;
324 SecurityDescriptor
= NULL
;
329 Attributes
|= OBJ_OPENIF
;
330 RootDirectory
= BaseGetNamedObjectDirectory();
334 RootDirectory
= NULL
;
337 /* Create the Object Attributes */
338 InitializeObjectAttributes(ObjectAttributes
,
343 DPRINT("Attributes: %lx, RootDirectory: %lx, SecurityDescriptor: %p\n",
344 Attributes
, RootDirectory
, SecurityDescriptor
);
345 return ObjectAttributes
;
349 * Creates a stack for a thread or fiber
353 BaseCreateStack(HANDLE hProcess
,
356 PINITIAL_TEB InitialTeb
)
359 PIMAGE_NT_HEADERS Headers
;
362 ULONG PageSize
, Dummy
, AllocationGranularity
;
363 SIZE_T StackReserveHeader
, StackCommitHeader
, GuardPageSize
, GuaranteedStackCommit
;
364 DPRINT("BaseCreateStack (hProcess: %lx, Max: %lx, Current: %lx)\n",
365 hProcess
, StackReserve
, StackCommit
);
368 PageSize
= BaseStaticServerData
->SysInfo
.PageSize
;
369 AllocationGranularity
= BaseStaticServerData
->SysInfo
.AllocationGranularity
;
371 /* Get the Image Headers */
372 Headers
= RtlImageNtHeader(NtCurrentPeb()->ImageBaseAddress
);
373 if (!Headers
) return STATUS_INVALID_IMAGE_FORMAT
;
375 StackCommitHeader
= Headers
->OptionalHeader
.SizeOfStackCommit
;
376 StackReserveHeader
= Headers
->OptionalHeader
.SizeOfStackReserve
;
378 if (!StackReserve
) StackReserve
= StackReserveHeader
;
382 StackCommit
= StackCommitHeader
;
384 else if (StackCommit
>= StackReserve
)
386 StackReserve
= ROUND_UP(StackCommit
, 1024 * 1024);
389 StackCommit
= ROUND_UP(StackCommit
, PageSize
);
390 StackReserve
= ROUND_UP(StackReserve
, AllocationGranularity
);
392 GuaranteedStackCommit
= NtCurrentTeb()->GuaranteedStackBytes
;
393 if ((GuaranteedStackCommit
) && (StackCommit
< GuaranteedStackCommit
))
395 StackCommit
= GuaranteedStackCommit
;
398 if (StackCommit
>= StackReserve
)
400 StackReserve
= ROUND_UP(StackCommit
, 1024 * 1024);
403 StackCommit
= ROUND_UP(StackCommit
, PageSize
);
404 StackReserve
= ROUND_UP(StackReserve
, AllocationGranularity
);
406 /* ROS Hack until we support guard page stack expansion */
407 StackCommit
= StackReserve
;
409 /* Reserve memory for the stack */
411 Status
= NtAllocateVirtualMemory(hProcess
,
417 if (!NT_SUCCESS(Status
))
419 DPRINT1("Failure to reserve stack: %lx\n", Status
);
423 /* Now set up some basic Initial TEB Parameters */
424 InitialTeb
->AllocatedStackBase
= (PVOID
)Stack
;
425 InitialTeb
->StackBase
= (PVOID
)(Stack
+ StackReserve
);
426 InitialTeb
->PreviousStackBase
= NULL
;
427 InitialTeb
->PreviousStackLimit
= NULL
;
429 /* Update the Stack Position */
430 Stack
+= StackReserve
- StackCommit
;
432 /* Check if we will need a guard page */
433 if (StackReserve
> StackCommit
)
436 StackCommit
+= PageSize
;
444 /* Allocate memory for the stack */
445 Status
= NtAllocateVirtualMemory(hProcess
,
451 if (!NT_SUCCESS(Status
))
453 DPRINT1("Failure to allocate stack\n");
455 NtFreeVirtualMemory(hProcess
, (PVOID
*)&Stack
, &GuardPageSize
, MEM_RELEASE
);
459 /* Now set the current Stack Limit */
460 InitialTeb
->StackLimit
= (PVOID
)Stack
;
462 /* Create a guard page */
465 /* Set the guard page */
466 GuardPageSize
= PAGE_SIZE
;
467 Status
= NtProtectVirtualMemory(hProcess
,
470 PAGE_GUARD
| PAGE_READWRITE
,
472 if (!NT_SUCCESS(Status
))
474 DPRINT1("Failure to set guard page\n");
478 /* Update the Stack Limit keeping in mind the Guard Page */
479 InitialTeb
->StackLimit
= (PVOID
)((ULONG_PTR
)InitialTeb
->StackLimit
+
484 return STATUS_SUCCESS
;
489 BaseFreeThreadStack(IN HANDLE hProcess
,
490 IN PINITIAL_TEB InitialTeb
)
495 NtFreeVirtualMemory(hProcess
,
496 &InitialTeb
->AllocatedStackBase
,
502 * Creates the Initial Context for a Thread or Fiber
506 BaseInitializeContext(IN PCONTEXT Context
,
508 IN PVOID StartAddress
,
509 IN PVOID StackAddress
,
510 IN ULONG ContextType
)
514 DPRINT("BaseInitializeContext: %p\n", Context
);
516 /* Setup the Initial Win32 Thread Context */
517 Context
->Eax
= (ULONG
)StartAddress
;
518 Context
->Ebx
= (ULONG
)Parameter
;
519 Context
->Esp
= (ULONG
)StackAddress
;
520 /* The other registers are undefined */
522 /* Setup the Segments */
523 Context
->SegFs
= KGDT_R3_TEB
;
524 Context
->SegEs
= KGDT_R3_DATA
;
525 Context
->SegDs
= KGDT_R3_DATA
;
526 Context
->SegCs
= KGDT_R3_CODE
;
527 Context
->SegSs
= KGDT_R3_DATA
;
530 /* Set the Context Flags */
531 ContextFlags
= Context
->ContextFlags
;
532 Context
->ContextFlags
= CONTEXT_FULL
;
534 /* Give it some room for the Parameter */
535 Context
->Esp
-= sizeof(PVOID
);
538 Context
->EFlags
= 0x3000; /* IOPL 3 */
540 /* What kind of context is being created? */
541 if (ContextType
== 1)
544 Context
->Eip
= (ULONG
)BaseThreadStartupThunk
;
546 else if (ContextType
== 2)
548 /* This is a fiber: make space for the return address */
549 Context
->Esp
-= sizeof(PVOID
);
550 *((PVOID
*)Context
->Esp
) = BaseFiberStartup
;
552 /* Is FPU state required? */
553 Context
->ContextFlags
|= ContextFlags
;
554 if (ContextFlags
== CONTEXT_FLOATING_POINT
)
556 /* Set an initial state */
557 Context
->FloatSave
.ControlWord
= 0x27F;
558 Context
->FloatSave
.StatusWord
= 0;
559 Context
->FloatSave
.TagWord
= 0xFFFF;
560 Context
->FloatSave
.ErrorOffset
= 0;
561 Context
->FloatSave
.ErrorSelector
= 0;
562 Context
->FloatSave
.DataOffset
= 0;
563 Context
->FloatSave
.DataSelector
= 0;
564 if (SharedUserData
->ProcessorFeatures
[PF_XMMI_INSTRUCTIONS_AVAILABLE
])
565 Context
->Dr6
= 0x1F80;
570 /* For first thread in a Process */
571 Context
->Eip
= (ULONG
)BaseProcessStartThunk
;
574 #elif defined(_M_AMD64)
575 DPRINT("BaseInitializeContext: %p\n", Context
);
577 /* Setup the Initial Win32 Thread Context */
578 Context
->Rax
= (ULONG_PTR
)StartAddress
;
579 Context
->Rbx
= (ULONG_PTR
)Parameter
;
580 Context
->Rsp
= (ULONG_PTR
)StackAddress
;
581 /* The other registers are undefined */
583 /* Setup the Segments */
584 Context
->SegGs
= KGDT64_R3_DATA
| RPL_MASK
;
585 Context
->SegEs
= KGDT64_R3_DATA
| RPL_MASK
;
586 Context
->SegDs
= KGDT64_R3_DATA
| RPL_MASK
;
587 Context
->SegCs
= KGDT64_R3_CODE
| RPL_MASK
;
588 Context
->SegSs
= KGDT64_R3_DATA
| RPL_MASK
;
589 Context
->SegFs
= KGDT64_R3_CMTEB
| RPL_MASK
;
592 Context
->EFlags
= 0x3000; /* IOPL 3 */
594 if (ContextType
== 1) /* For Threads */
596 Context
->Rip
= (ULONG_PTR
)BaseThreadStartupThunk
;
598 else if (ContextType
== 2) /* For Fibers */
600 Context
->Rip
= (ULONG_PTR
)BaseFiberStartup
;
602 else /* For first thread in a Process */
604 Context
->Rip
= (ULONG_PTR
)BaseProcessStartThunk
;
607 /* Set the Context Flags */
608 Context
->ContextFlags
= CONTEXT_FULL
;
610 /* Give it some room for the Parameter */
611 Context
->Rsp
-= sizeof(PVOID
);
613 #warning Unknown architecture
620 * Checks if the privilege for Real-Time Priority is there
624 BasepIsRealtimeAllowed(IN BOOLEAN Keep
)
626 ULONG Privilege
= SE_INC_BASE_PRIORITY_PRIVILEGE
;
630 Status
= RtlAcquirePrivilege(&Privilege
, 1, 0, &State
);
631 if (!NT_SUCCESS(Status
)) return NULL
;
635 RtlReleasePrivilege(State
);
643 * Maps an image file into a section
647 BasepMapFile(IN LPCWSTR lpApplicationName
,
648 OUT PHANDLE hSection
,
649 IN PUNICODE_STRING ApplicationName
)
651 RTL_RELATIVE_NAME_U RelativeName
;
652 OBJECT_ATTRIBUTES ObjectAttributes
;
655 IO_STATUS_BLOCK IoStatusBlock
;
657 DPRINT("BasepMapFile\n");
659 /* Zero out the Relative Directory */
660 RelativeName
.ContainingDirectory
= NULL
;
662 /* Find the application name */
663 if (!RtlDosPathNameToNtPathName_U(lpApplicationName
,
668 return STATUS_OBJECT_PATH_NOT_FOUND
;
671 DPRINT("ApplicationName %wZ\n", ApplicationName
);
672 DPRINT("RelativeName %wZ\n", &RelativeName
.RelativeName
);
674 /* Did we get a relative name? */
675 if (RelativeName
.RelativeName
.Length
)
677 ApplicationName
= &RelativeName
.RelativeName
;
680 /* Initialize the Object Attributes */
681 InitializeObjectAttributes(&ObjectAttributes
,
683 OBJ_CASE_INSENSITIVE
,
684 RelativeName
.ContainingDirectory
,
687 /* Try to open the executable */
688 Status
= NtOpenFile(&hFile
,
689 SYNCHRONIZE
| FILE_EXECUTE
| FILE_READ_DATA
,
692 FILE_SHARE_DELETE
| FILE_SHARE_READ
,
693 FILE_SYNCHRONOUS_IO_NONALERT
| FILE_NON_DIRECTORY_FILE
);
694 if (!NT_SUCCESS(Status
))
696 DPRINT1("Failed to open file\n");
697 BaseSetLastNTError(Status
);
701 /* Create a section for this file */
702 Status
= NtCreateSection(hSection
,
712 DPRINT("Section: %lx for file: %lx\n", *hSection
, hFile
);
721 Wow64EnableWow64FsRedirection(IN BOOLEAN Wow64EnableWow64FsRedirection
)
726 Status
= RtlWow64EnableFsRedirection(Wow64EnableWow64FsRedirection
);
727 if (NT_SUCCESS(Status
))
733 BaseSetLastNTError(Status
);
744 Wow64DisableWow64FsRedirection(IN PVOID
*OldValue
)
749 Status
= RtlWow64EnableFsRedirectionEx((PVOID
)TRUE
, OldValue
);
750 if (NT_SUCCESS(Status
))
756 BaseSetLastNTError(Status
);
767 Wow64RevertWow64FsRedirection(IN PVOID OldValue
)
772 Status
= RtlWow64EnableFsRedirectionEx(OldValue
, &OldValue
);
773 if (NT_SUCCESS(Status
))
779 BaseSetLastNTError(Status
);
790 SetFileApisToOEM(VOID
)
792 /* Set the correct Base Api */
793 Basep8BitStringToUnicodeString
= (PRTL_CONVERT_STRING
)RtlOemStringToUnicodeString
;
794 BasepUnicodeStringTo8BitString
= RtlUnicodeStringToOemString
;
795 BasepUnicodeStringTo8BitSize
= BasepUnicodeStringToOemSize
;
796 Basep8BitStringToUnicodeSize
= BasepOemStringToUnicodeSize
;
798 /* FIXME: Old, deprecated way */
799 bIsFileApiAnsi
= FALSE
;
808 SetFileApisToANSI(VOID
)
810 /* Set the correct Base Api */
811 Basep8BitStringToUnicodeString
= RtlAnsiStringToUnicodeString
;
812 BasepUnicodeStringTo8BitString
= RtlUnicodeStringToAnsiString
;
813 BasepUnicodeStringTo8BitSize
= BasepUnicodeStringToAnsiSize
;
814 Basep8BitStringToUnicodeSize
= BasepAnsiStringToUnicodeSize
;
816 /* FIXME: Old, deprecated way */
817 bIsFileApiAnsi
= TRUE
;
825 AreFileApisANSI(VOID
)
827 return Basep8BitStringToUnicodeString
== RtlAnsiStringToUnicodeString
;
835 BaseMarkFileForDelete(IN HANDLE FileHandle
,
836 IN ULONG FileAttributes
)
838 IO_STATUS_BLOCK IoStatusBlock
;
839 FILE_BASIC_INFORMATION FileBasicInfo
;
840 FILE_DISPOSITION_INFORMATION FileDispositionInfo
;
842 /* If no attributes were given, get them */
845 FileBasicInfo
.FileAttributes
= 0;
846 NtQueryInformationFile(FileHandle
,
849 sizeof(FileBasicInfo
),
850 FileBasicInformation
);
851 FileAttributes
= FileBasicInfo
.FileAttributes
;
854 /* If file is marked as RO, reset its attributes */
855 if (FileAttributes
& FILE_ATTRIBUTE_READONLY
)
857 RtlZeroMemory(&FileBasicInfo
, sizeof(FileBasicInfo
));
858 FileBasicInfo
.FileAttributes
= FILE_ATTRIBUTE_NORMAL
;
859 NtSetInformationFile(FileHandle
,
862 sizeof(FileBasicInfo
),
863 FileBasicInformation
);
866 /* Finally, mark the file for deletion */
867 FileDispositionInfo
.DeleteFile
= TRUE
;
868 NtSetInformationFile(FileHandle
,
870 &FileDispositionInfo
,
871 sizeof(FileDispositionInfo
),
872 FileDispositionInformation
);
880 BaseCheckRunApp(IN DWORD Unknown1
,
900 BasepCheckWinSaferRestrictions(IN HANDLE UserToken
,
901 IN LPWSTR ApplicationName
,
902 IN HANDLE FileHandle
,
904 OUT PHANDLE NewToken
,
905 OUT PHANDLE JobHandle
)
909 /* Validate that there's a name */
910 if ((ApplicationName
) && *(ApplicationName
))
912 /* Validate that the required output parameters are there */
913 if ((InJob
) && (NewToken
) && (JobHandle
))
915 /* Do the work (one day...) */
917 Status
= STATUS_SUCCESS
;
921 /* Act as if SEH hit this */
922 Status
= STATUS_ACCESS_VIOLATION
;
927 /* Input is invalid */
928 Status
= STATUS_INVALID_PARAMETER
;
931 /* Return the status */