First version of DLL preloader.
[wincetools.git] / loader / ntdll_virtual.c
1 /* From wine1.2-1.1.42/dlls/ntdll/virtual.c  */\r
2 \r
3 /*\r
4  * Win32 virtual memory functions\r
5  *\r
6  * Copyright 1997, 2002 Alexandre Julliard\r
7  * Copyright 2010 g10 Code GmbH\r
8  *\r
9  * This library is free software; you can redistribute it and/or\r
10  * modify it under the terms of the GNU Lesser General Public\r
11  * License as published by the Free Software Foundation; either\r
12  * version 2.1 of the License, or (at your option) any later version.\r
13  *\r
14  * This library is distributed in the hope that it will be useful,\r
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
17  * Lesser General Public License for more details.\r
18  *\r
19  * You should have received a copy of the GNU Lesser General Public\r
20  * License along with this library; if not, write to the Free Software\r
21  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA\r
22  */\r
23 \r
24 \r
25 #include <windows.h>\r
26 #include <assert.h>\r
27 \r
28 #include "wine.h"\r
29 \r
30 /* File view */\r
31 typedef struct file_view\r
32 {\r
33     void         *base;        /* Base address */\r
34     size_t        size;        /* Size in bytes */\r
35     HANDLE        mapping;     /* Handle to the file mapping */\r
36     unsigned int  protect;     /* Protection for all pages at allocation time */\r
37 } FILE_VIEW;\r
38 \r
39 \r
40 # define page_mask  0xfff\r
41 # define page_shift 12\r
42 # define page_size  0x1000\r
43 \r
44 \r
45 #define ROUND_SIZE(addr,size) \\r
46   (((SIZE_T)(size) + ((UINT_PTR)(addr) & page_mask) + page_mask) & ~page_mask)\r
47 \r
48 \r
49 static size_t get_mask( ULONG zero_bits )\r
50 {\r
51   if (!zero_bits) return 0xffff;  /* allocations are aligned to 64K by default */\r
52   if (zero_bits < page_shift) zero_bits = page_shift;\r
53   return (1 << zero_bits) - 1;\r
54 }\r
55 \r
56 \r
57 static NTSTATUS get_vprot_flags( DWORD protect, unsigned int *vprot )\r
58 {\r
59   switch(protect & 0xff)\r
60     {\r
61     case PAGE_READONLY:\r
62       *vprot = VPROT_READ;\r
63       break;\r
64     case PAGE_READWRITE:\r
65       *vprot = VPROT_READ | VPROT_WRITE;\r
66       break;\r
67     case PAGE_WRITECOPY:\r
68       *vprot = VPROT_READ | VPROT_WRITECOPY;\r
69       break;\r
70     case PAGE_EXECUTE:\r
71       *vprot = VPROT_EXEC;\r
72       break;\r
73     case PAGE_EXECUTE_READ:\r
74       *vprot = VPROT_EXEC | VPROT_READ;\r
75       break;\r
76     case PAGE_EXECUTE_READWRITE:\r
77       *vprot = VPROT_EXEC | VPROT_READ | VPROT_WRITE;\r
78       break;\r
79     case PAGE_EXECUTE_WRITECOPY:\r
80       *vprot = VPROT_EXEC | VPROT_READ | VPROT_WRITECOPY;\r
81       break;\r
82     case PAGE_NOACCESS:\r
83       *vprot = 0;\r
84       break;\r
85     default:\r
86       return STATUS_INVALID_PARAMETER;\r
87     }\r
88   if (protect & PAGE_GUARD) *vprot |= VPROT_GUARD;\r
89   if (protect & PAGE_NOCACHE) *vprot |= VPROT_NOCACHE;\r
90   return STATUS_SUCCESS;\r
91 }\r
92 \r
93 \r
94 static void delete_view( struct file_view *view ) /* [in] View */\r
95 {\r
96   VirtualFree (view->base, view->size, MEM_RELEASE);\r
97   // if (view->mapping) NtClose( view->mapping );\r
98   free (view);\r
99 }\r
100 \r
101 \r
102 static NTSTATUS map_view( struct file_view **view_ret, void *base, size_t size, size_t mask,\r
103                           int top_down, unsigned int vprot )\r
104 {\r
105   int prot = get_prot_flags (vprot);\r
106   struct file_view *view;\r
107   void *ptr;\r
108   void *new_ptr;\r
109 \r
110   view = malloc (sizeof (struct file_view));\r
111   if (!view)\r
112     return STATUS_NO_MEMORY;\r
113   \r
114   // FIXME: Only with NOACCESS does Windows CE prefer the high mem area\r
115   // even for smaller areas.\r
116   ptr = VirtualAlloc(base, size, MEM_RESERVE, PAGE_NOACCESS /*prot*/);\r
117   if (!ptr)\r
118     {\r
119       free (view);\r
120       return GetLastError();\r
121     }\r
122   /* We have to zero map the whole thing.  */\r
123   new_ptr = VirtualAlloc (ptr, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);\r
124   if (new_ptr != ptr)\r
125     {\r
126       free (view);\r
127       return GetLastError();\r
128     }\r
129   view->base = ptr;\r
130   view->size = size;\r
131   view->protect = vprot;\r
132   view->mapping = 0;\r
133   *view_ret = view;\r
134   return STATUS_SUCCESS;\r
135 }\r
136 \r
137 \r
138 static NTSTATUS map_file_into_view( struct file_view *view, HANDLE fhandle, size_t start, size_t size,\r
139                                     off_t offset, unsigned int vprot, BOOL removable )\r
140 {\r
141   void *ptr;\r
142   int prot = get_prot_flags (vprot);\r
143   BOOL shared_write = (vprot & VPROT_WRITE) != 0;\r
144 \r
145   assert( start < view->size );\r
146   assert( start + size <= view->size );\r
147 \r
148 #if 0\r
149   /* only try mmap if media is not removable (or if we require write access) */\r
150   if (!removable || shared_write)\r
151     {\r
152       int flags = MAP_FIXED | (shared_write ? MAP_SHARED : MAP_PRIVATE);\r
153 \r
154       if (mmap( (char *)view->base + start, size, prot, flags, fd, offset ) != (void *)-1)\r
155         goto done;\r
156 \r
157       /* mmap() failed; if this is because the file offset is not    */\r
158       /* page-aligned (EINVAL), or because the underlying filesystem */\r
159       /* does not support mmap() (ENOEXEC,ENODEV), we do it by hand. */\r
160       if ((errno != ENOEXEC) && (errno != EINVAL) && (errno != ENODEV)) return FILE_GetNtStatus();\r
161       if (shared_write)  /* we cannot fake shared write mappings */\r
162         {\r
163           if (errno == EINVAL) return STATUS_INVALID_PARAMETER;\r
164           ERR( "shared writable mmap not supported, broken filesystem?\n" );\r
165           return STATUS_NOT_SUPPORTED;\r
166         }\r
167     }\r
168 #endif\r
169 \r
170 #if 0\r
171   /* Already done by map_view.  */\r
172   /* Reserve the memory with an anonymous mmap */\r
173   ptr = VirtualAlloc ((char *)view->base + start, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);\r
174   if (ptr == (void *)-1) return GetLastError();\r
175 #else\r
176   ptr = (char *)view->base + start;\r
177 #endif\r
178 \r
179   /* Now read in the file */\r
180   pread( fhandle, ptr, size, offset );\r
181   //  if (prot != (PROT_READ|PROT_WRITE)) mprotect( ptr, size, prot );  /* Set the right protection */\r
182   //done:\r
183   //  memset( view->prot + (start >> page_shift), vprot, ROUND_SIZE(start,size) >> page_shift );\r
184   return STATUS_SUCCESS;\r
185 }\r
186 \r
187 \r
188 static NTSTATUS map_image (HANDLE hmapping, HANDLE hfile, HANDLE hmap, char *base, SIZE_T total_size, SIZE_T mask,\r
189                            SIZE_T header_size, int shared_fd, HANDLE dup_mapping, PVOID *addr_ptr)\r
190 {\r
191     IMAGE_DOS_HEADER *dos;\r
192     IMAGE_NT_HEADERS *nt;\r
193     IMAGE_SECTION_HEADER *sec;\r
194     IMAGE_DATA_DIRECTORY *imports;\r
195     NTSTATUS status = STATUS_CONFLICTING_ADDRESSES;\r
196     int i;\r
197     off_t pos;\r
198     DWORD fsize;\r
199     struct file_view *view = NULL;\r
200     char *ptr, *header_end;\r
201     INT_PTR delta = 0;\r
202 \r
203 \r
204     /* zero-map the whole range */\r
205 \r
206     if (base >= (char *)0x110000)  /* make sure the DOS area remains free */\r
207       status = map_view( &view, base, total_size, mask, FALSE,\r
208                          VPROT_COMMITTED | VPROT_READ | VPROT_EXEC | VPROT_WRITECOPY | VPROT_IMAGE );\r
209 \r
210     if (status != STATUS_SUCCESS)\r
211       status = map_view( &view, NULL, total_size, mask, FALSE,\r
212                          VPROT_COMMITTED | VPROT_READ | VPROT_EXEC | VPROT_WRITECOPY | VPROT_IMAGE );\r
213 \r
214     if (status != STATUS_SUCCESS) goto error;\r
215 \r
216     ptr = view->base;\r
217     TRACE( "mapped PE file at %p-%p\n", ptr, ptr + total_size );\r
218 \r
219     /* map the header */\r
220     \r
221     fsize = GetFileSize (hfile, NULL);\r
222     if (fsize == INVALID_FILE_SIZE)\r
223       {\r
224         status = GetLastError();\r
225         goto error;\r
226       }\r
227     status = STATUS_INVALID_IMAGE_FORMAT;  /* generic error */\r
228     header_size = min( header_size, fsize );\r
229     if (map_file_into_view( view, hfile, 0, header_size, 0, VPROT_COMMITTED | VPROT_READ | VPROT_WRITECOPY,\r
230                             !dup_mapping ) != STATUS_SUCCESS) goto error;\r
231     dos = (IMAGE_DOS_HEADER *)ptr;\r
232     nt = (IMAGE_NT_HEADERS *)(ptr + dos->e_lfanew);\r
233     header_end = ptr + ROUND_SIZE( 0, header_size );\r
234     memset( ptr + header_size, 0, header_end - (ptr + header_size) );\r
235     if ((char *)(nt + 1) > header_end) goto error;\r
236     sec = (IMAGE_SECTION_HEADER*)((char*)&nt->OptionalHeader+nt->FileHeader.SizeOfOptionalHeader);\r
237     if ((char *)(sec + nt->FileHeader.NumberOfSections) > header_end) goto error;\r
238 \r
239     imports = nt->OptionalHeader.DataDirectory + IMAGE_DIRECTORY_ENTRY_IMPORT;\r
240     if (!imports->Size || !imports->VirtualAddress) imports = NULL;\r
241 \r
242     /* check the architecture */\r
243 \r
244     if (nt->FileHeader.Machine != IMAGE_FILE_MACHINE_ARM\r
245         && nt->FileHeader.Machine != IMAGE_FILE_MACHINE_THUMB)\r
246         {\r
247           TRACE("Trying to load PE image for unsupported architecture (");\r
248           switch (nt->FileHeader.Machine)\r
249             {\r
250             case IMAGE_FILE_MACHINE_UNKNOWN: TRACE("Unknown"); break;\r
251             case IMAGE_FILE_MACHINE_I386:    TRACE("I386"); break;\r
252             case IMAGE_FILE_MACHINE_R3000:   TRACE("R3000"); break;\r
253             case IMAGE_FILE_MACHINE_R4000:   TRACE("R4000"); break;\r
254             case IMAGE_FILE_MACHINE_R10000:  TRACE("R10000"); break;\r
255             case IMAGE_FILE_MACHINE_ALPHA:   TRACE("Alpha"); break;\r
256             case IMAGE_FILE_MACHINE_POWERPC: TRACE("PowerPC"); break;\r
257             case IMAGE_FILE_MACHINE_IA64:    TRACE("IA-64"); break;\r
258             case IMAGE_FILE_MACHINE_ALPHA64: TRACE("Alpha-64"); break;\r
259             case IMAGE_FILE_MACHINE_ARM:     TRACE("ARM"); break;\r
260             default: TRACE("Unknown-%04x", nt->FileHeader.Machine); break;\r
261             }\r
262           TRACE(")\n");\r
263           goto error;\r
264         }\r
265     \r
266     /* check for non page-aligned binary */\r
267 \r
268     if (nt->OptionalHeader.SectionAlignment <= page_mask)\r
269       {\r
270         /* unaligned sections, this happens for native subsystem binaries */\r
271         /* in that case Windows simply maps in the whole file */\r
272 \r
273         if (map_file_into_view( view, hfile, 0, total_size, 0, VPROT_COMMITTED | VPROT_READ,\r
274                                 !dup_mapping ) != STATUS_SUCCESS) goto error;\r
275 \r
276         /* check that all sections are loaded at the right offset */\r
277         if (nt->OptionalHeader.FileAlignment != nt->OptionalHeader.SectionAlignment) goto error;\r
278         for (i = 0; i < nt->FileHeader.NumberOfSections; i++)\r
279           {\r
280             if (sec[i].VirtualAddress != sec[i].PointerToRawData)\r
281               goto error;  /* Windows refuses to load in that case too */\r
282           }\r
283 #if 0\r
284         /* set the image protections */\r
285         VIRTUAL_SetProt( view, ptr, total_size,\r
286                          VPROT_COMMITTED | VPROT_READ | VPROT_WRITECOPY | VPROT_EXEC );\r
287 #endif\r
288 \r
289 #if 0\r
290         /* no relocations are performed on non page-aligned binaries */\r
291         goto done;\r
292 #else\r
293         goto reloc;\r
294 #endif\r
295       }\r
296 \r
297 \r
298     /* map all the sections */\r
299 \r
300     for (i = pos = 0; i < nt->FileHeader.NumberOfSections; i++, sec++)\r
301       {\r
302         static const SIZE_T sector_align = 0x1ff;\r
303         SIZE_T map_size, file_start, file_size, end;\r
304 \r
305         if (!sec->Misc.VirtualSize)\r
306           map_size = ROUND_SIZE( 0, sec->SizeOfRawData );\r
307         else\r
308           map_size = ROUND_SIZE( 0, sec->Misc.VirtualSize );\r
309 \r
310         /* file positions are rounded to sector boundaries regardless of OptionalHeader.FileAlignment */\r
311         file_start = sec->PointerToRawData & ~sector_align;\r
312         file_size = (sec->SizeOfRawData + (sec->PointerToRawData & sector_align) + sector_align) & ~sector_align;\r
313         if (file_size > map_size) file_size = map_size;\r
314 \r
315         /* a few sanity checks */\r
316         end = sec->VirtualAddress + ROUND_SIZE( sec->VirtualAddress, map_size );\r
317         if (sec->VirtualAddress > total_size || end > total_size || end < sec->VirtualAddress)\r
318           {\r
319             ERR ( "Section %.8s too large (%x+%lx/%lx)\n",\r
320                   sec->Name, sec->VirtualAddress, map_size, total_size );\r
321             goto error;\r
322           }\r
323 \r
324         if ((sec->Characteristics & IMAGE_SCN_MEM_SHARED) &&\r
325             (sec->Characteristics & IMAGE_SCN_MEM_WRITE))\r
326           {\r
327             TRACE( "mapping shared section %.8s at %p off %x (%x) size %lx (%lx) flags %x\n",\r
328                    sec->Name, ptr + sec->VirtualAddress,\r
329                    sec->PointerToRawData, (int)pos, file_size, map_size,\r
330                    sec->Characteristics );\r
331             if (map_file_into_view( view, hfile, sec->VirtualAddress, map_size, pos,\r
332                                     VPROT_COMMITTED | VPROT_READ | VPROT_WRITE,\r
333                                     FALSE ) != STATUS_SUCCESS)\r
334               {\r
335                 ERR ( "Could not map shared section %.8s\n", sec->Name );\r
336                 goto error;\r
337               }\r
338 \r
339             /* check if the import directory falls inside this section */\r
340             if (imports && imports->VirtualAddress >= sec->VirtualAddress &&\r
341                 imports->VirtualAddress < sec->VirtualAddress + map_size)\r
342               {\r
343                 UINT_PTR base = imports->VirtualAddress & ~page_mask;\r
344                 UINT_PTR end = base + ROUND_SIZE( imports->VirtualAddress, imports->Size );\r
345                 if (end > sec->VirtualAddress + map_size) end = sec->VirtualAddress + map_size;\r
346                 if (end > base)\r
347                   map_file_into_view( view, hfile, base, end - base,\r
348                                       pos + (base - sec->VirtualAddress),\r
349                                       VPROT_COMMITTED | VPROT_READ | VPROT_WRITECOPY,\r
350                                       FALSE );\r
351               }\r
352             pos += map_size;\r
353             continue;\r
354           }\r
355 \r
356         ERR( "mapping section %.8s at %p off %x size %x virt %x flags %x\n",\r
357              sec->Name, ptr + sec->VirtualAddress,\r
358              sec->PointerToRawData, sec->SizeOfRawData,\r
359              sec->Misc.VirtualSize, sec->Characteristics );\r
360         \r
361         if (!sec->PointerToRawData || !file_size) continue;\r
362 \r
363         /* Note: if the section is not aligned properly map_file_into_view will magically\r
364          *       fall back to read(), so we don't need to check anything here.\r
365          */\r
366         end = file_start + file_size;\r
367         if (sec->PointerToRawData >= fsize ||\r
368             end > ((fsize + sector_align) & ~sector_align) ||\r
369             end < file_start ||\r
370             map_file_into_view( view, hfile, sec->VirtualAddress, file_size, file_start,\r
371                                 VPROT_COMMITTED | VPROT_READ | VPROT_WRITECOPY,\r
372                                 !dup_mapping ) != STATUS_SUCCESS)\r
373           {\r
374             ERR( "Could not map section %.8s, file probably truncated\n", sec->Name );\r
375             goto error;\r
376           }\r
377 \r
378         if (file_size & page_mask)\r
379           {\r
380             end = ROUND_SIZE( 0, file_size );\r
381             if (end > map_size) end = map_size;\r
382             TRACE("clearing %p - %p\n",\r
383                   ptr + sec->VirtualAddress + file_size,\r
384                   ptr + sec->VirtualAddress + end );\r
385             memset( ptr + sec->VirtualAddress + file_size, 0, end - file_size );\r
386           }\r
387       }\r
388 \r
389  reloc:\r
390     /* perform base relocation, if necessary */\r
391 \r
392     if (ptr != base)\r
393       // &&\r
394       //        ((nt->FileHeader.Characteristics & IMAGE_FILE_DLL) ||\r
395       //         !NtCurrentTeb()->Peb->ImageBaseAddress) )\r
396       {\r
397         IMAGE_BASE_RELOCATION *rel, *end;\r
398         const IMAGE_DATA_DIRECTORY *relocs;\r
399 \r
400         if (nt->FileHeader.Characteristics & IMAGE_FILE_RELOCS_STRIPPED)\r
401           {\r
402             TRACE( "Need to relocate module from %p to %p, but there are no relocation records\n",\r
403                    base, ptr );\r
404             status = STATUS_CONFLICTING_ADDRESSES;\r
405             goto error;\r
406           }\r
407 \r
408         TRACE( "relocating from %p-%p to %p-%p\n",\r
409                base, base + total_size, ptr, ptr + total_size );\r
410 \r
411         relocs = &nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];\r
412         rel = (IMAGE_BASE_RELOCATION *)(ptr + relocs->VirtualAddress);\r
413         end = (IMAGE_BASE_RELOCATION *)(ptr + relocs->VirtualAddress + relocs->Size);\r
414         delta = ptr - base;\r
415 \r
416         while (rel < end - 1 && rel->SizeOfBlock)\r
417           {\r
418             if (rel->VirtualAddress >= total_size)\r
419               {\r
420                 TRACE( "invalid address %p in relocation %p\n", ptr + rel->VirtualAddress, rel );\r
421                 status = STATUS_ACCESS_VIOLATION;\r
422                 goto error;\r
423               }\r
424             rel = MyLdrProcessRelocationBlock( ptr + rel->VirtualAddress,\r
425                                                (rel->SizeOfBlock - sizeof(*rel)) / sizeof(USHORT),\r
426                                                (USHORT *)(rel + 1), delta );\r
427             if (!rel) goto error;\r
428           }\r
429       }\r
430 #if 0\r
431     /* set the image protections */\r
432     VIRTUAL_SetProt( view, ptr, ROUND_SIZE( 0, header_size ), VPROT_COMMITTED | VPROT_READ );\r
433 \r
434     sec = (IMAGE_SECTION_HEADER*)((char *)&nt->OptionalHeader+nt->FileHeader.SizeOfOptionalHeader);\r
435     for (i = 0; i < nt->FileHeader.NumberOfSections; i++, sec++)\r
436       {\r
437         SIZE_T size;\r
438         BYTE vprot = VPROT_COMMITTED;\r
439 \r
440         if (sec->Misc.VirtualSize)\r
441           size = ROUND_SIZE( sec->VirtualAddress, sec->Misc.VirtualSize );\r
442         else\r
443           size = ROUND_SIZE( sec->VirtualAddress, sec->SizeOfRawData );\r
444 \r
445         if (sec->Characteristics & IMAGE_SCN_MEM_READ)    vprot |= VPROT_READ;\r
446         if (sec->Characteristics & IMAGE_SCN_MEM_WRITE)   vprot |= VPROT_READ|VPROT_WRITECOPY;\r
447         if (sec->Characteristics & IMAGE_SCN_MEM_EXECUTE) vprot |= VPROT_EXEC;\r
448 \r
449         /* Dumb game crack lets the AOEP point into a data section. Adjust. */\r
450         if ((nt->OptionalHeader.AddressOfEntryPoint >= sec->VirtualAddress) &&\r
451             (nt->OptionalHeader.AddressOfEntryPoint < sec->VirtualAddress + size))\r
452           vprot |= VPROT_EXEC;\r
453 \r
454         VIRTUAL_SetProt( view, ptr + sec->VirtualAddress, size, vprot );\r
455       }\r
456 #endif\r
457 \r
458     // done:\r
459     *addr_ptr = ptr;\r
460 #ifdef VALGRIND_LOAD_PDB_DEBUGINFO\r
461     VALGRIND_LOAD_PDB_DEBUGINFO(fd, ptr, total_size, delta);\r
462 #endif\r
463     if (ptr != base) return STATUS_IMAGE_NOT_AT_BASE;\r
464     return STATUS_SUCCESS;\r
465 \r
466  error:\r
467     if (view) delete_view( view );\r
468     return status;\r
469 }\r
470 \r
471 \r
472 NTSTATUS MyNtCreateSection (HANDLE *handle, ACCESS_MASK access,\r
473                             /* const OBJECT_ATTRIBUTES *attr */ void *attr,\r
474                             const LARGE_INTEGER *size, ULONG protect,\r
475                             ULONG sec_flags, HANDLE file)\r
476 {\r
477     NTSTATUS ret;\r
478     unsigned int vprot;\r
479     \r
480     if ((ret = get_vprot_flags( protect, &vprot ))) return ret;\r
481 \r
482     assert (attr == NULL);\r
483 \r
484     if (!(sec_flags & SEC_RESERVE)) vprot |= VPROT_COMMITTED;\r
485     if (sec_flags & SEC_NOCACHE) vprot |= VPROT_NOCACHE;\r
486     if (sec_flags & SEC_IMAGE) vprot |= VPROT_IMAGE;\r
487 \r
488     ret = SERVER_create_mapping (access, attr, file, size ? size->QuadPart : 0,\r
489                                  vprot, handle);\r
490 \r
491     return ret;\r
492 }\r
493 \r
494 \r
495 NTSTATUS MyNtMapViewOfSection (HANDLE handle, HANDLE process, PVOID *addr_ptr, ULONG zero_bits,\r
496                                SIZE_T commit_size, const LARGE_INTEGER *offset_ptr, SIZE_T *size_ptr,\r
497                                SECTION_INHERIT inherit, ULONG alloc_type, ULONG protect)\r
498 {\r
499   NTSTATUS res;\r
500   mem_size_t full_size;\r
501   ACCESS_MASK access;\r
502   SIZE_T size, mask = get_mask( zero_bits );\r
503   unsigned int map_vprot;\r
504   //  unsigned int vprot;\r
505   void *base;\r
506   //  struct file_view *view;\r
507   DWORD header_size;\r
508   HANDLE fhandle;\r
509   HANDLE mhandle;\r
510   LARGE_INTEGER offset;\r
511 \r
512   offset.QuadPart = offset_ptr ? offset_ptr->QuadPart : 0;\r
513 \r
514   TRACE("handle=%p process=%p addr=%p off=%x%08x size=%lx access=%x\n",\r
515         handle, process, *addr_ptr, offset.u.HighPart, offset.u.LowPart, *size_ptr, protect );\r
516 \r
517   /* Check parameters */\r
518 \r
519   if ((offset.u.LowPart & mask) || (*addr_ptr && ((UINT_PTR)*addr_ptr & mask)))\r
520     return STATUS_INVALID_PARAMETER;\r
521 \r
522   switch(protect)\r
523     {\r
524     case PAGE_NOACCESS:\r
525       access = 0;\r
526       break;\r
527     case PAGE_READWRITE:\r
528     case PAGE_EXECUTE_READWRITE:\r
529       access = SECTION_MAP_WRITE;\r
530       break;\r
531     case PAGE_READONLY:\r
532     case PAGE_WRITECOPY:\r
533     case PAGE_EXECUTE:\r
534     case PAGE_EXECUTE_READ:\r
535     case PAGE_EXECUTE_WRITECOPY:\r
536       access = SECTION_MAP_READ;\r
537       break;\r
538     default:\r
539       return STATUS_INVALID_PARAMETER;\r
540     }\r
541 \r
542   res = SERVER_get_mapping_info (handle, access, &map_vprot, &base, &full_size, &header_size, &fhandle, &mhandle);\r
543   if (res) return res;\r
544 \r
545   if (map_vprot & VPROT_IMAGE)\r
546     {\r
547       size = full_size;\r
548       if (size != full_size)  /* truncated */\r
549         {\r
550           TRACE( "Modules larger than 4Gb not supported\n");\r
551           res = STATUS_INVALID_PARAMETER;\r
552           goto done;\r
553         }\r
554       res = map_image( handle, fhandle, mhandle, base, size, mask, header_size,\r
555                        -1, INVALID_HANDLE_VALUE, addr_ptr );\r
556       if (res >= 0) *size_ptr = size;\r
557       return res;\r
558     }\r
559 \r
560   assert (!"Not supported");\r
561 #if 0\r
562   res = STATUS_INVALID_PARAMETER;\r
563   if (offset.QuadPart >= full_size) goto done;\r
564   if (*size_ptr)\r
565     {\r
566       if (*size_ptr > full_size - offset.QuadPart) goto done;\r
567       size = ROUND_SIZE( offset.u.LowPart, *size_ptr );\r
568       if (size < *size_ptr) goto done;  /* wrap-around */\r
569     }\r
570   else\r
571     {\r
572       size = full_size - offset.QuadPart;\r
573       if (size != full_size - offset.QuadPart)  /* truncated */\r
574         {\r
575           WARN( "Files larger than 4Gb (%s) not supported on this platform\n",\r
576                 wine_dbgstr_longlong(full_size) );\r
577           goto done;\r
578         }\r
579     }\r
580 \r
581   /* Reserve a properly aligned area */\r
582 \r
583   server_enter_uninterrupted_section( &csVirtual, &sigset );\r
584 \r
585   get_vprot_flags( protect, &vprot );\r
586   vprot |= (map_vprot & VPROT_COMMITTED);\r
587   res = map_view( &view, *addr_ptr, size, mask, FALSE, vprot );\r
588   if (res)\r
589     {\r
590       server_leave_uninterrupted_section( &csVirtual, &sigset );\r
591       goto done;\r
592     }\r
593 \r
594   /* Map the file */\r
595 \r
596   TRACE("handle=%p size=%lx offset=%x%08x\n",\r
597         handle, size, offset.u.HighPart, offset.u.LowPart );\r
598 \r
599   res = map_file_into_view( view, unix_handle, 0, size, offset.QuadPart, vprot, !dup_mapping );\r
600   if (res == STATUS_SUCCESS)\r
601     {\r
602       *addr_ptr = view->base;\r
603       *size_ptr = size;\r
604       view->mapping = dup_mapping;\r
605       dup_mapping = 0;  /* don't close it */\r
606     }\r
607   else\r
608     {\r
609       ERR( "map_file_into_view %p %lx %x%08x failed\n",\r
610            view->base, size, offset.u.HighPart, offset.u.LowPart );\r
611       delete_view( view );\r
612     }\r
613   \r
614   server_leave_uninterrupted_section( &csVirtual, &sigset );\r
615 #endif\r
616 \r
617  done:\r
618   return res;\r
619 \r
620   //  *addr_ptr = MapViewOfFile (handle, \r
621   //                         protect == PAGE_READONLY ? FILE_MAP_READ : FILE_MAP_WRITE,\r
622   //                         offset_ptr ? offset_ptr->HighPart : 0,\r
623   //                         offset_ptr ? offset_ptr->LowPart : 0,\r
624   //                         size_ptr ? size_ptr->LowPart : 0);\r
625   //  if (*addr_ptr == NULL)\r
626   //    return GetLastError ();\r
627   //\r
628   //  return STATUS_SUCCESS;\r
629 }\r