xref: /reactos/dll/win32/kernel32/client/utils.c (revision 09dde2cf)
1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         ReactOS system libraries
4  * FILE:            dll/win32/kernel32/client/utils.c
5  * PURPOSE:         Utility and Support Functions
6  * PROGRAMMER:      Alex Ionescu (alex@relsoft.net)
7  *                  Pierre Schweitzer (pierre.schweitzer@reactos.org)
8  */
9 
10 /* INCLUDES ******************************************************************/
11 
12 #include <k32.h>
13 #ifdef _M_IX86
14 #include "i386/ketypes.h"
15 #elif defined _M_AMD64
16 #include "amd64/ketypes.h"
17 #endif
18 
19 #define NDEBUG
20 #include <debug.h>
21 
22 /* GLOBALS ********************************************************************/
23 
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;
30 
31 /* FUNCTIONS ******************************************************************/
32 
33 ULONG
34 NTAPI
35 BasepUnicodeStringToOemSize(IN PUNICODE_STRING String)
36 {
37     return RtlUnicodeStringToOemSize(String);
38 }
39 
40 ULONG
41 NTAPI
42 BasepOemStringToUnicodeSize(IN PANSI_STRING String)
43 {
44     return RtlOemStringToUnicodeSize(String);
45 }
46 
47 ULONG
48 NTAPI
49 BasepUnicodeStringToAnsiSize(IN PUNICODE_STRING String)
50 {
51     return RtlUnicodeStringToAnsiSize(String);
52 }
53 
54 ULONG
55 NTAPI
56 BasepAnsiStringToUnicodeSize(IN PANSI_STRING String)
57 {
58     return RtlAnsiStringToUnicodeSize(String);
59 }
60 
61 HANDLE
62 WINAPI
63 BaseGetNamedObjectDirectory(VOID)
64 {
65     OBJECT_ATTRIBUTES ObjectAttributes;
66     NTSTATUS Status;
67     HANDLE DirHandle, BnoHandle, Token, NewToken;
68 
69     if (BaseNamedObjectDirectory) return BaseNamedObjectDirectory;
70 
71     if (NtCurrentTeb()->IsImpersonating)
72     {
73         Status = NtOpenThreadToken(NtCurrentThread(),
74                                    TOKEN_IMPERSONATE,
75                                    TRUE,
76                                    &Token);
77         if (!NT_SUCCESS(Status)) return BaseNamedObjectDirectory;
78 
79         NewToken = NULL;
80         Status = NtSetInformationThread(NtCurrentThread(),
81                                         ThreadImpersonationToken,
82                                         &NewToken,
83                                         sizeof(HANDLE));
84         if (!NT_SUCCESS (Status))
85         {
86             NtClose(Token);
87             return BaseNamedObjectDirectory;
88         }
89     }
90     else
91     {
92         Token = NULL;
93     }
94 
95     RtlAcquirePebLock();
96     if (BaseNamedObjectDirectory) goto Quickie;
97 
98     InitializeObjectAttributes(&ObjectAttributes,
99                                &BaseStaticServerData->NamedObjectDirectory,
100                                OBJ_CASE_INSENSITIVE,
101                                NULL,
102                                NULL);
103 
104     Status = NtOpenDirectoryObject(&BnoHandle,
105                                    DIRECTORY_QUERY |
106                                    DIRECTORY_TRAVERSE |
107                                    DIRECTORY_CREATE_OBJECT |
108                                    DIRECTORY_CREATE_SUBDIRECTORY,
109                                    &ObjectAttributes);
110     if (!NT_SUCCESS(Status))
111     {
112         Status = NtOpenDirectoryObject(&DirHandle,
113                                        DIRECTORY_TRAVERSE,
114                                        &ObjectAttributes);
115 
116         if (NT_SUCCESS(Status))
117         {
118             InitializeObjectAttributes(&ObjectAttributes,
119                                        (PUNICODE_STRING)&Restricted,
120                                        OBJ_CASE_INSENSITIVE,
121                                        DirHandle,
122                                        NULL);
123 
124             Status = NtOpenDirectoryObject(&BnoHandle,
125                                            DIRECTORY_QUERY |
126                                            DIRECTORY_TRAVERSE |
127                                            DIRECTORY_CREATE_OBJECT |
128                                            DIRECTORY_CREATE_SUBDIRECTORY,
129                                            &ObjectAttributes);
130             NtClose(DirHandle);
131 
132         }
133     }
134 
135     if (NT_SUCCESS(Status)) BaseNamedObjectDirectory = BnoHandle;
136 
137 Quickie:
138 
139     RtlReleasePebLock();
140 
141     if (Token)
142     {
143         NtSetInformationThread(NtCurrentThread(),
144                                ThreadImpersonationToken,
145                                &Token,
146                                sizeof(Token));
147 
148         NtClose(Token);
149     }
150 
151     return BaseNamedObjectDirectory;
152 }
153 
154 VOID
155 NTAPI
156 BasepLocateExeLdrEntry(IN PLDR_DATA_TABLE_ENTRY Entry,
157                        IN PVOID Context,
158                        OUT BOOLEAN *StopEnumeration)
159 {
160     /* Make sure we get Entry, Context and valid StopEnumeration pointer */
161     ASSERT(Entry);
162     ASSERT(Context);
163     ASSERT(StopEnumeration);
164 
165     /* If entry is already found - signal to stop */
166     if (BasepExeLdrEntry)
167     {
168         *StopEnumeration = TRUE;
169         return;
170     }
171 
172     /* Otherwise keep enumerating until we find a match */
173     if (Entry->DllBase == Context)
174     {
175         /* It matches, so remember the ldr entry */
176         BasepExeLdrEntry = Entry;
177 
178         /* And stop enumeration */
179         *StopEnumeration = TRUE;
180     }
181 }
182 
183 /*
184  * Converts an ANSI or OEM String to the TEB StaticUnicodeString
185  */
186 PUNICODE_STRING
187 WINAPI
188 Basep8BitStringToStaticUnicodeString(IN LPCSTR String)
189 {
190     PUNICODE_STRING StaticString = &(NtCurrentTeb()->StaticUnicodeString);
191     ANSI_STRING AnsiString;
192     NTSTATUS Status;
193 
194     /* Initialize an ANSI String */
195     Status = RtlInitAnsiStringEx(&AnsiString, String);
196     if (!NT_SUCCESS(Status))
197     {
198         Status = STATUS_BUFFER_OVERFLOW;
199     }
200     else
201     {
202         /* Convert it */
203         Status = Basep8BitStringToUnicodeString(StaticString, &AnsiString, FALSE);
204     }
205 
206     if (NT_SUCCESS(Status)) return StaticString;
207 
208     if (Status == STATUS_BUFFER_OVERFLOW)
209     {
210         SetLastError(ERROR_FILENAME_EXCED_RANGE);
211     }
212     else
213     {
214         BaseSetLastNTError(Status);
215     }
216 
217     return NULL;
218 }
219 
220 /*
221  * Allocates space from the Heap and converts an Unicode String into it
222  */
223 BOOLEAN
224 WINAPI
225 Basep8BitStringToDynamicUnicodeString(OUT PUNICODE_STRING UnicodeString,
226                                       IN LPCSTR String)
227 {
228     ANSI_STRING AnsiString;
229     NTSTATUS Status;
230 
231     /* Initialize an ANSI String */
232     Status = RtlInitAnsiStringEx(&AnsiString, String);
233     if (!NT_SUCCESS(Status))
234     {
235         Status = STATUS_BUFFER_OVERFLOW;
236     }
237     else
238     {
239         /* Convert it */
240         Status = Basep8BitStringToUnicodeString(UnicodeString, &AnsiString, TRUE);
241     }
242 
243     if (NT_SUCCESS(Status)) return TRUE;
244 
245     if (Status == STATUS_BUFFER_OVERFLOW)
246     {
247         SetLastError(ERROR_FILENAME_EXCED_RANGE);
248     }
249     else
250     {
251         BaseSetLastNTError(Status);
252     }
253 
254     return FALSE;
255 }
256 
257 /*
258  * Allocates space from the Heap and converts an Ansi String into it
259  */
260  /*NOTE: API IS A HACK */
261 VOID
262 WINAPI
263 BasepAnsiStringToHeapUnicodeString(IN LPCSTR AnsiString,
264                                    OUT LPWSTR* UnicodeString)
265 {
266     ANSI_STRING AnsiTemp;
267     UNICODE_STRING UnicodeTemp;
268 
269     DPRINT("BasepAnsiStringToHeapUnicodeString\n");
270 
271     /* First create the ANSI_STRING */
272     RtlInitAnsiString(&AnsiTemp, AnsiString);
273 
274     if (NT_SUCCESS(RtlAnsiStringToUnicodeString(&UnicodeTemp,
275                                                 &AnsiTemp,
276                                                 TRUE)))
277     {
278         *UnicodeString = UnicodeTemp.Buffer;
279     }
280     else
281     {
282         *UnicodeString = NULL;
283     }
284 }
285 
286 PLARGE_INTEGER
287 WINAPI
288 BaseFormatTimeOut(OUT PLARGE_INTEGER Timeout,
289                   IN DWORD dwMilliseconds)
290 {
291     /* Check if this is an infinite wait, which means no timeout argument */
292     if (dwMilliseconds == INFINITE) return NULL;
293 
294     /* Otherwise, convert the time to NT Format */
295     Timeout->QuadPart = dwMilliseconds * -10000LL;
296     return Timeout;
297 }
298 
299 /*
300  * Converts lpSecurityAttributes + Object Name into ObjectAttributes.
301  */
302 POBJECT_ATTRIBUTES
303 WINAPI
304 BaseFormatObjectAttributes(OUT POBJECT_ATTRIBUTES ObjectAttributes,
305                            IN PSECURITY_ATTRIBUTES SecurityAttributes OPTIONAL,
306                            IN PUNICODE_STRING ObjectName)
307 {
308     ULONG Attributes;
309     HANDLE RootDirectory;
310     PVOID SecurityDescriptor;
311     DPRINT("BaseFormatObjectAttributes. Security: %p, Name: %p\n",
312             SecurityAttributes, ObjectName);
313 
314     /* Get the attributes if present */
315     if (SecurityAttributes)
316     {
317         Attributes = SecurityAttributes->bInheritHandle ? OBJ_INHERIT : 0;
318         SecurityDescriptor = SecurityAttributes->lpSecurityDescriptor;
319     }
320     else
321     {
322         if (!ObjectName) return NULL;
323         Attributes = 0;
324         SecurityDescriptor = NULL;
325     }
326 
327     if (ObjectName)
328     {
329         Attributes |= OBJ_OPENIF;
330         RootDirectory = BaseGetNamedObjectDirectory();
331     }
332     else
333     {
334         RootDirectory = NULL;
335     }
336 
337     /* Create the Object Attributes */
338     InitializeObjectAttributes(ObjectAttributes,
339                                ObjectName,
340                                Attributes,
341                                RootDirectory,
342                                SecurityDescriptor);
343     DPRINT("Attributes: %lx, RootDirectory: %p, SecurityDescriptor: %p\n",
344             Attributes, RootDirectory, SecurityDescriptor);
345     return ObjectAttributes;
346 }
347 
348 /*
349  * Creates a stack for a thread or fiber.
350  * NOTE: Adapted from sdk/lib/rtl/thread.c:RtlpCreateUserStack().
351  */
352 NTSTATUS
353 WINAPI
354 BaseCreateStack(
355     _In_ HANDLE hProcess,
356     _In_opt_ SIZE_T StackCommit,
357     _In_opt_ SIZE_T StackReserve,
358     _Out_ PINITIAL_TEB InitialTeb)
359 {
360     NTSTATUS Status;
361     PIMAGE_NT_HEADERS Headers;
362     ULONG_PTR Stack;
363     BOOLEAN UseGuard;
364     ULONG PageSize, AllocationGranularity, Dummy;
365     SIZE_T MinimumStackCommit, GuardPageSize;
366 
367     DPRINT("BaseCreateStack(hProcess: 0x%p, Max: 0x%lx, Current: 0x%lx)\n",
368             hProcess, StackReserve, StackCommit);
369 
370     /* Read page size */
371     PageSize = BaseStaticServerData->SysInfo.PageSize;
372     AllocationGranularity = BaseStaticServerData->SysInfo.AllocationGranularity;
373 
374     /* Get the Image Headers */
375     Headers = RtlImageNtHeader(NtCurrentPeb()->ImageBaseAddress);
376     if (!Headers) return STATUS_INVALID_IMAGE_FORMAT;
377 
378     if (StackReserve == 0)
379         StackReserve = Headers->OptionalHeader.SizeOfStackReserve;
380 
381     if (StackCommit == 0)
382     {
383         StackCommit = Headers->OptionalHeader.SizeOfStackCommit;
384     }
385     /* Check if the commit is higher than the reserve */
386     else if (StackCommit >= StackReserve)
387     {
388         /* Grow the reserve beyond the commit, up to 1MB alignment */
389         StackReserve = ROUND_UP(StackCommit, 1024 * 1024);
390     }
391 
392     /* Align everything to Page Size */
393     StackCommit = ROUND_UP(StackCommit, PageSize);
394     StackReserve = ROUND_UP(StackReserve, AllocationGranularity);
395 
396     MinimumStackCommit = NtCurrentPeb()->MinimumStackCommit;
397     if ((MinimumStackCommit != 0) && (StackCommit < MinimumStackCommit))
398     {
399         StackCommit = MinimumStackCommit;
400     }
401 
402     /* Check if the commit is higher than the reserve */
403     if (StackCommit >= StackReserve)
404     {
405         /* Grow the reserve beyond the commit, up to 1MB alignment */
406         StackReserve = ROUND_UP(StackCommit, 1024 * 1024);
407     }
408 
409     /* Align everything to Page Size */
410     StackCommit = ROUND_UP(StackCommit, PageSize);
411     StackReserve = ROUND_UP(StackReserve, AllocationGranularity);
412 
413     /* Reserve memory for the stack */
414     Stack = 0;
415     Status = NtAllocateVirtualMemory(hProcess,
416                                      (PVOID*)&Stack,
417                                      0,
418                                      &StackReserve,
419                                      MEM_RESERVE,
420                                      PAGE_READWRITE);
421     if (!NT_SUCCESS(Status))
422     {
423         DPRINT1("Failure to reserve stack: %lx\n", Status);
424         return Status;
425     }
426 
427     /* Now set up some basic Initial TEB Parameters */
428     InitialTeb->AllocatedStackBase = (PVOID)Stack;
429     InitialTeb->StackBase = (PVOID)(Stack + StackReserve);
430     InitialTeb->PreviousStackBase = NULL;
431     InitialTeb->PreviousStackLimit = NULL;
432 
433     /* Update the stack position */
434     Stack += StackReserve - StackCommit;
435 
436     /* Check if we can add a guard page */
437     if (StackReserve >= StackCommit + PageSize)
438     {
439         Stack -= PageSize;
440         StackCommit += PageSize;
441         UseGuard = TRUE;
442     }
443     else
444     {
445         UseGuard = FALSE;
446     }
447 
448     /* Allocate memory for the stack */
449     Status = NtAllocateVirtualMemory(hProcess,
450                                      (PVOID*)&Stack,
451                                      0,
452                                      &StackCommit,
453                                      MEM_COMMIT,
454                                      PAGE_READWRITE);
455     if (!NT_SUCCESS(Status))
456     {
457         DPRINT1("Failure to allocate stack\n");
458         GuardPageSize = 0;
459         NtFreeVirtualMemory(hProcess, (PVOID*)&Stack, &GuardPageSize, MEM_RELEASE);
460         return Status;
461     }
462 
463     /* Now set the current Stack Limit */
464     InitialTeb->StackLimit = (PVOID)Stack;
465 
466     /* Create a guard page if needed */
467     if (UseGuard)
468     {
469         GuardPageSize = PageSize;
470         Status = NtProtectVirtualMemory(hProcess,
471                                         (PVOID*)&Stack,
472                                         &GuardPageSize,
473                                         PAGE_GUARD | PAGE_READWRITE,
474                                         &Dummy);
475         if (!NT_SUCCESS(Status))
476         {
477             DPRINT1("Failure to set guard page\n");
478             return Status;
479         }
480 
481         /* Update the Stack Limit keeping in mind the Guard Page */
482         InitialTeb->StackLimit = (PVOID)((ULONG_PTR)InitialTeb->StackLimit +
483                                          GuardPageSize);
484     }
485 
486     /* We are done! */
487     return STATUS_SUCCESS;
488 }
489 
490 /*
491  * NOTE: Adapted from sdk/lib/rtl/thread.c:RtlpFreeUserStack().
492  */
493 VOID
494 WINAPI
495 BaseFreeThreadStack(
496     _In_ HANDLE hProcess,
497     _In_ PINITIAL_TEB InitialTeb)
498 {
499     SIZE_T Dummy = 0;
500 
501     /* Free the Stack */
502     NtFreeVirtualMemory(hProcess,
503                         &InitialTeb->AllocatedStackBase,
504                         &Dummy,
505                         MEM_RELEASE);
506 }
507 
508 /*
509  * Creates the Initial Context for a Thread or Fiber
510  */
511 VOID
512 WINAPI
513 BaseInitializeContext(IN PCONTEXT Context,
514                       IN PVOID Parameter,
515                       IN PVOID StartAddress,
516                       IN PVOID StackAddress,
517                       IN ULONG ContextType)
518 {
519 #ifdef _M_IX86
520     ULONG ContextFlags;
521     DPRINT("BaseInitializeContext: %p\n", Context);
522 
523     /* Setup the Initial Win32 Thread Context */
524     Context->Eax = (ULONG)StartAddress;
525     Context->Ebx = (ULONG)Parameter;
526     Context->Esp = (ULONG)StackAddress;
527     /* The other registers are undefined */
528 
529     /* Setup the Segments */
530     Context->SegFs = KGDT_R3_TEB;
531     Context->SegEs = KGDT_R3_DATA;
532     Context->SegDs = KGDT_R3_DATA;
533     Context->SegCs = KGDT_R3_CODE;
534     Context->SegSs = KGDT_R3_DATA;
535     Context->SegGs = 0;
536 
537     /* Set the Context Flags */
538     ContextFlags = Context->ContextFlags;
539     Context->ContextFlags = CONTEXT_FULL;
540 
541     /* Give it some room for the Parameter */
542     Context->Esp -= sizeof(PVOID);
543 
544     /* Set the EFLAGS */
545     Context->EFlags = 0x3000; /* IOPL 3 */
546 
547     /* What kind of context is being created? */
548     if (ContextType == 1)
549     {
550         /* For Threads */
551         Context->Eip = (ULONG)BaseThreadStartupThunk;
552     }
553     else if (ContextType == 2)
554     {
555         /* This is a fiber: make space for the return address */
556         Context->Esp -= sizeof(PVOID);
557         *((PVOID*)Context->Esp) = BaseFiberStartup;
558 
559         /* Is FPU state required? */
560         Context->ContextFlags |= ContextFlags;
561         if ((ContextFlags & CONTEXT_FLOATING_POINT) == CONTEXT_FLOATING_POINT)
562         {
563             /* Set an initial state */
564             Context->FloatSave.ControlWord = 0x27F;
565             Context->FloatSave.StatusWord = 0;
566             Context->FloatSave.TagWord = 0xFFFF;
567             Context->FloatSave.ErrorOffset = 0;
568             Context->FloatSave.ErrorSelector = 0;
569             Context->FloatSave.DataOffset = 0;
570             Context->FloatSave.DataSelector = 0;
571             if (SharedUserData->ProcessorFeatures[PF_XMMI_INSTRUCTIONS_AVAILABLE])
572                 Context->Dr6 = 0x1F80;
573         }
574     }
575     else
576     {
577         /* For first thread in a Process */
578         Context->Eip = (ULONG)BaseProcessStartThunk;
579     }
580 
581 #elif defined(_M_AMD64)
582     DPRINT("BaseInitializeContext: %p\n", Context);
583     ASSERT(((ULONG_PTR)StackAddress & 15) == 0);
584 
585     RtlZeroMemory(Context, sizeof(*Context));
586 
587     /* Setup the Initial Win32 Thread Context */
588     Context->Rcx = (ULONG_PTR)StartAddress;
589     Context->Rdx = (ULONG_PTR)Parameter;
590     Context->Rsp = (ULONG_PTR)StackAddress - 5 * sizeof(PVOID);
591 
592     /* Setup the Segments */
593     Context->SegGs = KGDT64_R3_DATA | RPL_MASK;
594     Context->SegEs = KGDT64_R3_DATA | RPL_MASK;
595     Context->SegDs = KGDT64_R3_DATA | RPL_MASK;
596     Context->SegCs = KGDT64_R3_CODE | RPL_MASK;
597     Context->SegSs = KGDT64_R3_DATA | RPL_MASK;
598     Context->SegFs = KGDT64_R3_CMTEB | RPL_MASK;
599 
600     /* Set the EFLAGS */
601     Context->EFlags = 0x3000 | EFLAGS_INTERRUPT_MASK; /* IOPL 3 */
602 
603     /* Set MXCSR */
604     Context->MxCsr = INITIAL_MXCSR;
605 
606     if (ContextType == 1)      /* For Threads */
607     {
608         Context->Rip = (ULONG_PTR)BaseThreadStartup;
609     }
610     else if (ContextType == 2) /* For Fibers */
611     {
612         Context->Rip = (ULONG_PTR)BaseFiberStartup;
613     }
614     else                       /* For first thread in a Process */
615     {
616         Context->Rip = (ULONG_PTR)BaseProcessStartup;
617     }
618 
619     /* Set the Context Flags */
620     Context->ContextFlags = CONTEXT_FULL;
621 #elif defined(_M_ARM)
622     DPRINT("BaseInitializeContext: %p\n", Context);
623 
624     // FIXME: check if this is correct!
625     /* Setup the Initial Win32 Thread Context */
626     Context->R0 = (ULONG_PTR)StartAddress;
627     Context->R1 = (ULONG_PTR)Parameter;
628     Context->Sp = (ULONG_PTR)StackAddress;
629 
630     if (ContextType == 1)      /* For Threads */
631     {
632         Context->Pc = (ULONG_PTR)BaseThreadStartupThunk;
633     }
634     else if (ContextType == 2) /* For Fibers */
635     {
636         Context->Pc = (ULONG_PTR)BaseFiberStartup;
637     }
638     else                       /* For first thread in a Process */
639     {
640         Context->Pc = (ULONG_PTR)BaseProcessStartThunk;
641     }
642 
643     /* Set the Context Flags */
644     Context->ContextFlags = CONTEXT_FULL;
645 
646     /* Give it some room for the Parameter */
647     Context->Sp -= sizeof(PVOID);
648 #else
649 #warning Unknown architecture
650     UNIMPLEMENTED;
651     DbgBreakPoint();
652 #endif
653 }
654 
655 /*
656  * Checks if the privilege for Real-Time Priority is there
657  * Beware about this function behavior:
658  * - In case Keep is set to FALSE, then the function will only check
659  * whether real time is allowed and won't grant the privilege. In that case
660  * it will return TRUE if allowed, FALSE otherwise. Not a state!
661  * It means you don't have to release privilege when calling with FALSE.
662  */
663 PVOID
664 WINAPI
665 BasepIsRealtimeAllowed(IN BOOLEAN Keep)
666 {
667     ULONG Privilege = SE_INC_BASE_PRIORITY_PRIVILEGE;
668     PVOID State;
669     NTSTATUS Status;
670 
671     Status = RtlAcquirePrivilege(&Privilege, 1, 0, &State);
672     if (!NT_SUCCESS(Status)) return NULL;
673 
674     if (!Keep)
675     {
676         RtlReleasePrivilege(State);
677         State = (PVOID)TRUE;
678     }
679 
680     return State;
681 }
682 
683 /*
684  * Maps an image file into a section
685  */
686 NTSTATUS
687 WINAPI
688 BasepMapFile(IN LPCWSTR lpApplicationName,
689              OUT PHANDLE hSection,
690              IN PUNICODE_STRING ApplicationName)
691 {
692     RTL_RELATIVE_NAME_U RelativeName;
693     OBJECT_ATTRIBUTES ObjectAttributes;
694     NTSTATUS Status;
695     HANDLE hFile = NULL;
696     IO_STATUS_BLOCK IoStatusBlock;
697 
698     DPRINT("BasepMapFile\n");
699 
700     /* Zero out the Relative Directory */
701     RelativeName.ContainingDirectory = NULL;
702 
703     /* Find the application name */
704     if (!RtlDosPathNameToNtPathName_U(lpApplicationName,
705                                       ApplicationName,
706                                       NULL,
707                                       &RelativeName))
708     {
709         return STATUS_OBJECT_PATH_NOT_FOUND;
710     }
711 
712     DPRINT("ApplicationName %wZ\n", ApplicationName);
713     DPRINT("RelativeName %wZ\n", &RelativeName.RelativeName);
714 
715     /* Did we get a relative name? */
716     if (RelativeName.RelativeName.Length)
717     {
718         ApplicationName = &RelativeName.RelativeName;
719     }
720 
721     /* Initialize the Object Attributes */
722     InitializeObjectAttributes(&ObjectAttributes,
723                                ApplicationName,
724                                OBJ_CASE_INSENSITIVE,
725                                RelativeName.ContainingDirectory,
726                                NULL);
727 
728     /* Try to open the executable */
729     Status = NtOpenFile(&hFile,
730                         SYNCHRONIZE | FILE_EXECUTE | FILE_READ_DATA,
731                         &ObjectAttributes,
732                         &IoStatusBlock,
733                         FILE_SHARE_DELETE | FILE_SHARE_READ,
734                         FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE);
735     if (!NT_SUCCESS(Status))
736     {
737         DPRINT1("Failed to open file\n");
738         BaseSetLastNTError(Status);
739         return Status;
740     }
741 
742     /* Create a section for this file */
743     Status = NtCreateSection(hSection,
744                              SECTION_ALL_ACCESS,
745                              NULL,
746                              NULL,
747                              PAGE_EXECUTE,
748                              SEC_IMAGE,
749                              hFile);
750     NtClose(hFile);
751 
752     /* Return status */
753     DPRINT("Section: %p for file: %p\n", *hSection, hFile);
754     return Status;
755 }
756 
757 /*
758  * @implemented
759  */
760 BOOLEAN
761 WINAPI
762 Wow64EnableWow64FsRedirection(IN BOOLEAN Wow64EnableWow64FsRedirection)
763 {
764     NTSTATUS Status;
765     BOOL Result;
766 
767     Status = RtlWow64EnableFsRedirection(Wow64EnableWow64FsRedirection);
768     if (NT_SUCCESS(Status))
769     {
770         Result = TRUE;
771     }
772     else
773     {
774         BaseSetLastNTError(Status);
775         Result = FALSE;
776     }
777     return Result;
778 }
779 
780 /*
781  * @implemented
782  */
783 BOOL
784 WINAPI
785 Wow64DisableWow64FsRedirection(IN PVOID *OldValue)
786 {
787     NTSTATUS Status;
788     BOOL Result;
789 
790     Status = RtlWow64EnableFsRedirectionEx((PVOID)TRUE, OldValue);
791     if (NT_SUCCESS(Status))
792     {
793         Result = TRUE;
794     }
795     else
796     {
797         BaseSetLastNTError(Status);
798         Result = FALSE;
799     }
800     return Result;
801 }
802 
803 /*
804  * @implemented
805  */
806 BOOL
807 WINAPI
808 Wow64RevertWow64FsRedirection(IN PVOID OldValue)
809 {
810     NTSTATUS Status;
811     BOOL Result;
812 
813     Status = RtlWow64EnableFsRedirectionEx(OldValue, &OldValue);
814     if (NT_SUCCESS(Status))
815     {
816         Result = TRUE;
817     }
818     else
819     {
820         BaseSetLastNTError(Status);
821         Result = FALSE;
822     }
823     return Result;
824 }
825 
826 /*
827  * @implemented
828  */
829 VOID
830 WINAPI
831 SetFileApisToOEM(VOID)
832 {
833     /* Set the correct Base Api */
834     Basep8BitStringToUnicodeString = (PRTL_CONVERT_STRING)RtlOemStringToUnicodeString;
835     BasepUnicodeStringTo8BitString = RtlUnicodeStringToOemString;
836     BasepUnicodeStringTo8BitSize = BasepUnicodeStringToOemSize;
837     Basep8BitStringToUnicodeSize = BasepOemStringToUnicodeSize;
838 
839     /* FIXME: Old, deprecated way */
840     bIsFileApiAnsi = FALSE;
841 }
842 
843 
844 /*
845  * @implemented
846  */
847 VOID
848 WINAPI
849 SetFileApisToANSI(VOID)
850 {
851     /* Set the correct Base Api */
852     Basep8BitStringToUnicodeString = RtlAnsiStringToUnicodeString;
853     BasepUnicodeStringTo8BitString = RtlUnicodeStringToAnsiString;
854     BasepUnicodeStringTo8BitSize = BasepUnicodeStringToAnsiSize;
855     Basep8BitStringToUnicodeSize = BasepAnsiStringToUnicodeSize;
856 
857     /* FIXME: Old, deprecated way */
858     bIsFileApiAnsi = TRUE;
859 }
860 
861 /*
862  * @implemented
863  */
864 BOOL
865 WINAPI
866 AreFileApisANSI(VOID)
867 {
868    return Basep8BitStringToUnicodeString == RtlAnsiStringToUnicodeString;
869 }
870 
871 /*
872  * @implemented
873  */
874 VOID
875 WINAPI
876 BaseMarkFileForDelete(IN HANDLE FileHandle,
877                       IN ULONG FileAttributes)
878 {
879     IO_STATUS_BLOCK IoStatusBlock;
880     FILE_BASIC_INFORMATION FileBasicInfo;
881     FILE_DISPOSITION_INFORMATION FileDispositionInfo;
882 
883     /* If no attributes were given, get them */
884     if (!FileAttributes)
885     {
886         FileBasicInfo.FileAttributes = 0;
887         NtQueryInformationFile(FileHandle,
888                                &IoStatusBlock,
889                                &FileBasicInfo,
890                                sizeof(FileBasicInfo),
891                                FileBasicInformation);
892         FileAttributes = FileBasicInfo.FileAttributes;
893     }
894 
895     /* If file is marked as RO, reset its attributes */
896     if (FileAttributes & FILE_ATTRIBUTE_READONLY)
897     {
898         RtlZeroMemory(&FileBasicInfo, sizeof(FileBasicInfo));
899         FileBasicInfo.FileAttributes = FILE_ATTRIBUTE_NORMAL;
900         NtSetInformationFile(FileHandle,
901                              &IoStatusBlock,
902                              &FileBasicInfo,
903                              sizeof(FileBasicInfo),
904                              FileBasicInformation);
905     }
906 
907     /* Finally, mark the file for deletion */
908     FileDispositionInfo.DeleteFile = TRUE;
909     NtSetInformationFile(FileHandle,
910                          &IoStatusBlock,
911                          &FileDispositionInfo,
912                          sizeof(FileDispositionInfo),
913                          FileDispositionInformation);
914 }
915 
916 /*
917  * @unimplemented
918  */
919 NTSTATUS
920 WINAPI
921 BasepCheckWinSaferRestrictions(IN HANDLE UserToken,
922                                IN LPWSTR ApplicationName,
923                                IN HANDLE FileHandle,
924                                OUT PBOOLEAN InJob,
925                                OUT PHANDLE NewToken,
926                                OUT PHANDLE JobHandle)
927 {
928     NTSTATUS Status;
929 
930     /* Validate that there's a name */
931     if ((ApplicationName) && *(ApplicationName))
932     {
933         /* Validate that the required output parameters are there */
934         if ((InJob) && (NewToken) && (JobHandle))
935         {
936             /* Do the work (one day...) */
937             DPRINT("BasepCheckWinSaferRestrictions is UNIMPLEMENTED\n");
938             Status = STATUS_SUCCESS;
939         }
940         else
941         {
942             /* Act as if SEH hit this */
943             Status = STATUS_ACCESS_VIOLATION;
944         }
945     }
946     else
947     {
948         /* Input is invalid */
949         Status = STATUS_INVALID_PARAMETER;
950     }
951 
952     /* Return the status */
953     return Status;
954 }
955