xref: /reactos/dll/win32/kernel32/client/utils.c (revision 40462c92)
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 
584     /* Setup the Initial Win32 Thread Context */
585     Context->Rax = (ULONG_PTR)StartAddress;
586     Context->Rbx = (ULONG_PTR)Parameter;
587     Context->Rsp = (ULONG_PTR)StackAddress;
588     /* The other registers are undefined */
589 
590     /* Setup the Segments */
591     Context->SegGs = KGDT64_R3_DATA | RPL_MASK;
592     Context->SegEs = KGDT64_R3_DATA | RPL_MASK;
593     Context->SegDs = KGDT64_R3_DATA | RPL_MASK;
594     Context->SegCs = KGDT64_R3_CODE | RPL_MASK;
595     Context->SegSs = KGDT64_R3_DATA | RPL_MASK;
596     Context->SegFs = KGDT64_R3_CMTEB | RPL_MASK;
597 
598     /* Set the EFLAGS */
599     Context->EFlags = 0x3000; /* IOPL 3 */
600 
601     if (ContextType == 1)      /* For Threads */
602     {
603         Context->Rip = (ULONG_PTR)BaseThreadStartupThunk;
604     }
605     else if (ContextType == 2) /* For Fibers */
606     {
607         Context->Rip = (ULONG_PTR)BaseFiberStartup;
608     }
609     else                       /* For first thread in a Process */
610     {
611         Context->Rip = (ULONG_PTR)BaseProcessStartThunk;
612     }
613 
614     /* Set the Context Flags */
615     Context->ContextFlags = CONTEXT_FULL;
616 
617     /* Give it some room for the Parameter */
618     Context->Rsp -= sizeof(PVOID);
619 #elif defined(_M_ARM)
620     DPRINT("BaseInitializeContext: %p\n", Context);
621 
622     // FIXME: check if this is correct!
623     /* Setup the Initial Win32 Thread Context */
624     Context->R0 = (ULONG_PTR)StartAddress;
625     Context->R1 = (ULONG_PTR)Parameter;
626     Context->Sp = (ULONG_PTR)StackAddress;
627 
628     if (ContextType == 1)      /* For Threads */
629     {
630         Context->Pc = (ULONG_PTR)BaseThreadStartupThunk;
631     }
632     else if (ContextType == 2) /* For Fibers */
633     {
634         Context->Pc = (ULONG_PTR)BaseFiberStartup;
635     }
636     else                       /* For first thread in a Process */
637     {
638         Context->Pc = (ULONG_PTR)BaseProcessStartThunk;
639     }
640 
641     /* Set the Context Flags */
642     Context->ContextFlags = CONTEXT_FULL;
643 
644     /* Give it some room for the Parameter */
645     Context->Sp -= sizeof(PVOID);
646 #else
647 #warning Unknown architecture
648     UNIMPLEMENTED;
649     DbgBreakPoint();
650 #endif
651 }
652 
653 /*
654  * Checks if the privilege for Real-Time Priority is there
655  * Beware about this function behavior:
656  * - In case Keep is set to FALSE, then the function will only check
657  * whether real time is allowed and won't grant the privilege. In that case
658  * it will return TRUE if allowed, FALSE otherwise. Not a state!
659  * It means you don't have to release privilege when calling with FALSE.
660  */
661 PVOID
662 WINAPI
663 BasepIsRealtimeAllowed(IN BOOLEAN Keep)
664 {
665     ULONG Privilege = SE_INC_BASE_PRIORITY_PRIVILEGE;
666     PVOID State;
667     NTSTATUS Status;
668 
669     Status = RtlAcquirePrivilege(&Privilege, 1, 0, &State);
670     if (!NT_SUCCESS(Status)) return NULL;
671 
672     if (!Keep)
673     {
674         RtlReleasePrivilege(State);
675         State = (PVOID)TRUE;
676     }
677 
678     return State;
679 }
680 
681 /*
682  * Maps an image file into a section
683  */
684 NTSTATUS
685 WINAPI
686 BasepMapFile(IN LPCWSTR lpApplicationName,
687              OUT PHANDLE hSection,
688              IN PUNICODE_STRING ApplicationName)
689 {
690     RTL_RELATIVE_NAME_U RelativeName;
691     OBJECT_ATTRIBUTES ObjectAttributes;
692     NTSTATUS Status;
693     HANDLE hFile = NULL;
694     IO_STATUS_BLOCK IoStatusBlock;
695 
696     DPRINT("BasepMapFile\n");
697 
698     /* Zero out the Relative Directory */
699     RelativeName.ContainingDirectory = NULL;
700 
701     /* Find the application name */
702     if (!RtlDosPathNameToNtPathName_U(lpApplicationName,
703                                       ApplicationName,
704                                       NULL,
705                                       &RelativeName))
706     {
707         return STATUS_OBJECT_PATH_NOT_FOUND;
708     }
709 
710     DPRINT("ApplicationName %wZ\n", ApplicationName);
711     DPRINT("RelativeName %wZ\n", &RelativeName.RelativeName);
712 
713     /* Did we get a relative name? */
714     if (RelativeName.RelativeName.Length)
715     {
716         ApplicationName = &RelativeName.RelativeName;
717     }
718 
719     /* Initialize the Object Attributes */
720     InitializeObjectAttributes(&ObjectAttributes,
721                                ApplicationName,
722                                OBJ_CASE_INSENSITIVE,
723                                RelativeName.ContainingDirectory,
724                                NULL);
725 
726     /* Try to open the executable */
727     Status = NtOpenFile(&hFile,
728                         SYNCHRONIZE | FILE_EXECUTE | FILE_READ_DATA,
729                         &ObjectAttributes,
730                         &IoStatusBlock,
731                         FILE_SHARE_DELETE | FILE_SHARE_READ,
732                         FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE);
733     if (!NT_SUCCESS(Status))
734     {
735         DPRINT1("Failed to open file\n");
736         BaseSetLastNTError(Status);
737         return Status;
738     }
739 
740     /* Create a section for this file */
741     Status = NtCreateSection(hSection,
742                              SECTION_ALL_ACCESS,
743                              NULL,
744                              NULL,
745                              PAGE_EXECUTE,
746                              SEC_IMAGE,
747                              hFile);
748     NtClose(hFile);
749 
750     /* Return status */
751     DPRINT("Section: %p for file: %p\n", *hSection, hFile);
752     return Status;
753 }
754 
755 /*
756  * @implemented
757  */
758 BOOLEAN
759 WINAPI
760 Wow64EnableWow64FsRedirection(IN BOOLEAN Wow64EnableWow64FsRedirection)
761 {
762     NTSTATUS Status;
763     BOOL Result;
764 
765     Status = RtlWow64EnableFsRedirection(Wow64EnableWow64FsRedirection);
766     if (NT_SUCCESS(Status))
767     {
768         Result = TRUE;
769     }
770     else
771     {
772         BaseSetLastNTError(Status);
773         Result = FALSE;
774     }
775     return Result;
776 }
777 
778 /*
779  * @implemented
780  */
781 BOOL
782 WINAPI
783 Wow64DisableWow64FsRedirection(IN PVOID *OldValue)
784 {
785     NTSTATUS Status;
786     BOOL Result;
787 
788     Status = RtlWow64EnableFsRedirectionEx((PVOID)TRUE, OldValue);
789     if (NT_SUCCESS(Status))
790     {
791         Result = TRUE;
792     }
793     else
794     {
795         BaseSetLastNTError(Status);
796         Result = FALSE;
797     }
798     return Result;
799 }
800 
801 /*
802  * @implemented
803  */
804 BOOL
805 WINAPI
806 Wow64RevertWow64FsRedirection(IN PVOID OldValue)
807 {
808     NTSTATUS Status;
809     BOOL Result;
810 
811     Status = RtlWow64EnableFsRedirectionEx(OldValue, &OldValue);
812     if (NT_SUCCESS(Status))
813     {
814         Result = TRUE;
815     }
816     else
817     {
818         BaseSetLastNTError(Status);
819         Result = FALSE;
820     }
821     return Result;
822 }
823 
824 /*
825  * @implemented
826  */
827 VOID
828 WINAPI
829 SetFileApisToOEM(VOID)
830 {
831     /* Set the correct Base Api */
832     Basep8BitStringToUnicodeString = (PRTL_CONVERT_STRING)RtlOemStringToUnicodeString;
833     BasepUnicodeStringTo8BitString = RtlUnicodeStringToOemString;
834     BasepUnicodeStringTo8BitSize = BasepUnicodeStringToOemSize;
835     Basep8BitStringToUnicodeSize = BasepOemStringToUnicodeSize;
836 
837     /* FIXME: Old, deprecated way */
838     bIsFileApiAnsi = FALSE;
839 }
840 
841 
842 /*
843  * @implemented
844  */
845 VOID
846 WINAPI
847 SetFileApisToANSI(VOID)
848 {
849     /* Set the correct Base Api */
850     Basep8BitStringToUnicodeString = RtlAnsiStringToUnicodeString;
851     BasepUnicodeStringTo8BitString = RtlUnicodeStringToAnsiString;
852     BasepUnicodeStringTo8BitSize = BasepUnicodeStringToAnsiSize;
853     Basep8BitStringToUnicodeSize = BasepAnsiStringToUnicodeSize;
854 
855     /* FIXME: Old, deprecated way */
856     bIsFileApiAnsi = TRUE;
857 }
858 
859 /*
860  * @implemented
861  */
862 BOOL
863 WINAPI
864 AreFileApisANSI(VOID)
865 {
866    return Basep8BitStringToUnicodeString == RtlAnsiStringToUnicodeString;
867 }
868 
869 /*
870  * @implemented
871  */
872 VOID
873 WINAPI
874 BaseMarkFileForDelete(IN HANDLE FileHandle,
875                       IN ULONG FileAttributes)
876 {
877     IO_STATUS_BLOCK IoStatusBlock;
878     FILE_BASIC_INFORMATION FileBasicInfo;
879     FILE_DISPOSITION_INFORMATION FileDispositionInfo;
880 
881     /* If no attributes were given, get them */
882     if (!FileAttributes)
883     {
884         FileBasicInfo.FileAttributes = 0;
885         NtQueryInformationFile(FileHandle,
886                                &IoStatusBlock,
887                                &FileBasicInfo,
888                                sizeof(FileBasicInfo),
889                                FileBasicInformation);
890         FileAttributes = FileBasicInfo.FileAttributes;
891     }
892 
893     /* If file is marked as RO, reset its attributes */
894     if (FileAttributes & FILE_ATTRIBUTE_READONLY)
895     {
896         RtlZeroMemory(&FileBasicInfo, sizeof(FileBasicInfo));
897         FileBasicInfo.FileAttributes = FILE_ATTRIBUTE_NORMAL;
898         NtSetInformationFile(FileHandle,
899                              &IoStatusBlock,
900                              &FileBasicInfo,
901                              sizeof(FileBasicInfo),
902                              FileBasicInformation);
903     }
904 
905     /* Finally, mark the file for deletion */
906     FileDispositionInfo.DeleteFile = TRUE;
907     NtSetInformationFile(FileHandle,
908                          &IoStatusBlock,
909                          &FileDispositionInfo,
910                          sizeof(FileDispositionInfo),
911                          FileDispositionInformation);
912 }
913 
914 /*
915  * @unimplemented
916  */
917 NTSTATUS
918 WINAPI
919 BasepCheckWinSaferRestrictions(IN HANDLE UserToken,
920                                IN LPWSTR ApplicationName,
921                                IN HANDLE FileHandle,
922                                OUT PBOOLEAN InJob,
923                                OUT PHANDLE NewToken,
924                                OUT PHANDLE JobHandle)
925 {
926     NTSTATUS Status;
927 
928     /* Validate that there's a name */
929     if ((ApplicationName) && *(ApplicationName))
930     {
931         /* Validate that the required output parameters are there */
932         if ((InJob) && (NewToken) && (JobHandle))
933         {
934             /* Do the work (one day...) */
935             DPRINT("BasepCheckWinSaferRestrictions is UNIMPLEMENTED\n");
936             Status = STATUS_SUCCESS;
937         }
938         else
939         {
940             /* Act as if SEH hit this */
941             Status = STATUS_ACCESS_VIOLATION;
942         }
943     }
944     else
945     {
946         /* Input is invalid */
947         Status = STATUS_INVALID_PARAMETER;
948     }
949 
950     /* Return the status */
951     return Status;
952 }
953