+FSCTL_DISMOUNT_VOLUME define
[reactos.git] / ntoskrnl / ldr / rtl.c
1 /* $Id$
2  *
3  * COPYRIGHT:       See COPYING in the top level directory
4  * PROJECT:         ReactOS kernel
5  * FILE:            ntoskrnl/ldr/loader.c
6  * PURPOSE:         Loader utilities
7  * PROGRAMMERS:     Jean Michault
8  *                  Rex Jolliff (rex@lvcablemodem.com)
9  */
10
11 /* INCLUDES *****************************************************************/
12
13 #include <ddk/ntddk.h>
14 #include <internal/module.h>
15 #include <internal/ntoskrnl.h>
16 #include <internal/ob.h>
17 #include <internal/ps.h>
18 #include <internal/ldr.h>
19
20 #define NDEBUG
21 #include <internal/debug.h>
22
23 /* FUNCTIONS ****************************************************************/
24
25
26 PIMAGE_NT_HEADERS STDCALL 
27 RtlImageNtHeader (IN PVOID BaseAddress)
28 {
29    PIMAGE_DOS_HEADER DosHeader;
30    PIMAGE_NT_HEADERS NTHeaders;
31    
32    DosHeader = (PIMAGE_DOS_HEADER)BaseAddress;
33    NTHeaders = (PIMAGE_NT_HEADERS)(BaseAddress + DosHeader->e_lfanew);
34    if ((DosHeader->e_magic != IMAGE_DOS_MAGIC)
35        || (DosHeader->e_lfanew == 0L)
36        || (*(PULONG) NTHeaders != IMAGE_PE_MAGIC))
37      {
38         return(NULL);
39      }
40    return(NTHeaders);
41 }
42
43
44 PVOID STDCALL
45 RtlImageDirectoryEntryToData (IN PVOID  BaseAddress,
46                               IN BOOLEAN        ImageLoaded,
47                               IN ULONG  Directory,
48                               OUT PULONG        Size)
49 {
50         PIMAGE_NT_HEADERS NtHeader;
51         PIMAGE_SECTION_HEADER SectionHeader;
52         ULONG Va;
53         ULONG Count;
54
55         NtHeader = RtlImageNtHeader (BaseAddress);
56         if (NtHeader == NULL)
57                 return NULL;
58
59         if (Directory >= NtHeader->OptionalHeader.NumberOfRvaAndSizes)
60                 return NULL;
61
62         Va = NtHeader->OptionalHeader.DataDirectory[Directory].VirtualAddress;
63         if (Va == 0)
64                 return NULL;
65
66         if (Size)
67                 *Size = NtHeader->OptionalHeader.DataDirectory[Directory].Size;
68
69         if (ImageLoaded)
70                 return (PVOID)(BaseAddress + Va);
71
72         /* image mapped as ordinary file, we must find raw pointer */
73         SectionHeader = (PIMAGE_SECTION_HEADER)(NtHeader + 1);
74         Count = NtHeader->FileHeader.NumberOfSections;
75         while (Count--)
76         {
77                 if (SectionHeader->VirtualAddress == Va)
78                         return (PVOID)(BaseAddress + SectionHeader->PointerToRawData);
79                 SectionHeader++;
80         }
81
82         return NULL;
83 }
84
85 #ifndef LIBCAPTIVE
86
87 PIMAGE_SECTION_HEADER
88 STDCALL
89 RtlImageRvaToSection (
90         PIMAGE_NT_HEADERS       NtHeader,
91         PVOID                   BaseAddress,
92         ULONG                   Rva
93         )
94 {
95         PIMAGE_SECTION_HEADER Section;
96         ULONG Va;
97         ULONG Count;
98
99         Count = NtHeader->FileHeader.NumberOfSections;
100         Section = (PIMAGE_SECTION_HEADER)((ULONG)&NtHeader->OptionalHeader +
101                                           NtHeader->FileHeader.SizeOfOptionalHeader);
102         while (Count)
103         {
104                 Va = Section->VirtualAddress;
105                 if ((Va <= Rva) &&
106                     (Rva < Va + Section->SizeOfRawData))
107                         return Section;
108                 Section++;
109         }
110         return NULL;
111 }
112
113
114 ULONG
115 STDCALL
116 RtlImageRvaToVa (
117         PIMAGE_NT_HEADERS       NtHeader,
118         PVOID                   BaseAddress,
119         ULONG                   Rva,
120         PIMAGE_SECTION_HEADER   *SectionHeader
121         )
122 {
123         PIMAGE_SECTION_HEADER Section = NULL;
124
125         if (SectionHeader)
126                 Section = *SectionHeader;
127
128         if (Section == NULL ||
129             Rva < Section->VirtualAddress ||
130             Rva >= Section->VirtualAddress + Section->SizeOfRawData)
131         {
132                 Section = RtlImageRvaToSection (NtHeader, BaseAddress, Rva);
133                 if (Section == NULL)
134                         return 0;
135
136                 if (SectionHeader)
137                         *SectionHeader = Section;
138         }
139
140         return (ULONG)(BaseAddress +
141                        Rva +
142                        Section->PointerToRawData -
143                        Section->VirtualAddress);
144 }
145
146 #define RVA(m, b) ((ULONG)b + m)
147
148 NTSTATUS STDCALL
149 LdrGetProcedureAddress (IN PVOID BaseAddress,
150                         IN PANSI_STRING Name,
151                         IN ULONG Ordinal,
152                         OUT PVOID *ProcedureAddress)
153 {
154    PIMAGE_EXPORT_DIRECTORY ExportDir;
155    PUSHORT OrdinalPtr;
156    PULONG NamePtr;
157    PULONG AddressPtr;
158    ULONG i = 0;
159
160    /* get the pointer to the export directory */
161    ExportDir = (PIMAGE_EXPORT_DIRECTORY)
162         RtlImageDirectoryEntryToData (BaseAddress, TRUE, 
163                                       IMAGE_DIRECTORY_ENTRY_EXPORT, &i);
164
165    if (!ExportDir || !i || !ProcedureAddress)
166      {
167         return(STATUS_INVALID_PARAMETER);
168      }
169    
170    AddressPtr = (PULONG)RVA(BaseAddress, ExportDir->AddressOfFunctions);
171    if (Name && Name->Length)
172      {
173        ULONG minn, maxn;
174
175         /* by name */
176        OrdinalPtr = 
177          (PUSHORT)RVA(BaseAddress, ExportDir->AddressOfNameOrdinals);
178        NamePtr = (PULONG)RVA(BaseAddress, ExportDir->AddressOfNames);
179
180         minn = 0; maxn = ExportDir->NumberOfNames;
181         while (minn <= maxn)
182           {
183             ULONG mid;
184             LONG res;
185
186             mid = (minn + maxn) / 2;
187             res = _strnicmp(Name->Buffer, (PCH)RVA(BaseAddress, NamePtr[mid]),
188                             Name->Length);
189             if (res == 0)
190               {
191                 *ProcedureAddress = 
192                   (PVOID)RVA(BaseAddress, AddressPtr[OrdinalPtr[mid]]);
193                 return(STATUS_SUCCESS);
194               }
195             else if (res > 0)
196               {
197                 maxn = mid - 1;
198               }
199             else
200               {
201                 minn = mid + 1;
202               }
203           }
204
205         for (i = 0; i < ExportDir->NumberOfNames; i++, NamePtr++, OrdinalPtr++)
206           {
207              if (!_strnicmp(Name->Buffer, 
208                             (char*)(BaseAddress + *NamePtr), Name->Length))
209                {
210                   *ProcedureAddress = 
211                     (PVOID)((ULONG)BaseAddress + 
212                             (ULONG)AddressPtr[*OrdinalPtr]);
213                   return STATUS_SUCCESS;
214                }
215           }
216         CPRINT("LdrGetProcedureAddress: Can't resolve symbol '%Z'\n", Name);
217      }
218    else
219      {
220         /* by ordinal */
221         Ordinal &= 0x0000FFFF;
222         if (Ordinal - ExportDir->Base < ExportDir->NumberOfFunctions)
223           {
224              *ProcedureAddress = 
225                (PVOID)((ULONG)BaseAddress + 
226                        (ULONG)AddressPtr[Ordinal - ExportDir->Base]);
227              return STATUS_SUCCESS;
228           }
229         CPRINT("LdrGetProcedureAddress: Can't resolve symbol @%d\n",
230                  Ordinal);
231   }
232
233    return STATUS_PROCEDURE_NOT_FOUND;
234 }
235
236 #endif /* LIBCAPTIVE */
237
238 /* EOF */