Change the callback declarations to a safer format.
[wine] / memory / virtual.c
1 /*
2  * Win32 virtual memory functions
3  *
4  * Copyright 1997 Alexandre Julliard
5  */
6
7 #include "config.h"
8
9 #include <assert.h>
10 #include <errno.h>
11 #ifdef HAVE_SYS_ERRNO_H
12 #include <sys/errno.h>
13 #endif
14 #include <fcntl.h>
15 #include <unistd.h>
16 #include <stdlib.h>
17 #include <stdio.h>
18 #include <string.h>
19 #include <sys/types.h>
20 #ifdef HAVE_SYS_MMAN_H
21 #include <sys/mman.h>
22 #endif
23 #include "winnls.h"
24 #include "winbase.h"
25 #include "wine/exception.h"
26 #include "wine/unicode.h"
27 #include "wine/library.h"
28 #include "wine/port.h"
29 #include "winerror.h"
30 #include "file.h"
31 #include "global.h"
32 #include "server.h"
33 #include "debugtools.h"
34
35 DEFAULT_DEBUG_CHANNEL(virtual);
36 DECLARE_DEBUG_CHANNEL(module);
37
38 #ifndef MS_SYNC
39 #define MS_SYNC 0
40 #endif
41
42 /* File view */
43 typedef struct _FV
44 {
45     struct _FV   *next;        /* Next view */
46     struct _FV   *prev;        /* Prev view */
47     UINT        base;        /* Base address */
48     UINT        size;        /* Size in bytes */
49     UINT        flags;       /* Allocation flags */
50     HANDLE      mapping;     /* Handle to the file mapping */
51     HANDLERPROC   handlerProc; /* Fault handler */
52     LPVOID        handlerArg;  /* Fault handler argument */
53     BYTE          protect;     /* Protection for all pages at allocation time */
54     BYTE          prot[1];     /* Protection byte for each page */
55 } FILE_VIEW;
56
57 /* Per-view flags */
58 #define VFLAG_SYSTEM     0x01
59 #define VFLAG_VALLOC     0x02  /* allocated by VirtualAlloc */
60
61 /* Conversion from VPROT_* to Win32 flags */
62 static const BYTE VIRTUAL_Win32Flags[16] =
63 {
64     PAGE_NOACCESS,              /* 0 */
65     PAGE_READONLY,              /* READ */
66     PAGE_READWRITE,             /* WRITE */
67     PAGE_READWRITE,             /* READ | WRITE */
68     PAGE_EXECUTE,               /* EXEC */
69     PAGE_EXECUTE_READ,          /* READ | EXEC */
70     PAGE_EXECUTE_READWRITE,     /* WRITE | EXEC */
71     PAGE_EXECUTE_READWRITE,     /* READ | WRITE | EXEC */
72     PAGE_WRITECOPY,             /* WRITECOPY */
73     PAGE_WRITECOPY,             /* READ | WRITECOPY */
74     PAGE_WRITECOPY,             /* WRITE | WRITECOPY */
75     PAGE_WRITECOPY,             /* READ | WRITE | WRITECOPY */
76     PAGE_EXECUTE_WRITECOPY,     /* EXEC | WRITECOPY */
77     PAGE_EXECUTE_WRITECOPY,     /* READ | EXEC | WRITECOPY */
78     PAGE_EXECUTE_WRITECOPY,     /* WRITE | EXEC | WRITECOPY */
79     PAGE_EXECUTE_WRITECOPY      /* READ | WRITE | EXEC | WRITECOPY */
80 };
81
82
83 static FILE_VIEW *VIRTUAL_FirstView;
84 static CRITICAL_SECTION csVirtual = CRITICAL_SECTION_INIT;
85
86 #ifdef __i386__
87 /* These are always the same on an i386, and it will be faster this way */
88 # define page_mask  0xfff
89 # define page_shift 12
90 # define page_size  0x1000
91 #else
92 static UINT page_shift;
93 static UINT page_mask;
94 static UINT page_size;
95 #endif  /* __i386__ */
96 #define granularity_mask 0xffff  /* Allocation granularity (usually 64k) */
97
98 #define ROUND_ADDR(addr) \
99    ((UINT)(addr) & ~page_mask)
100
101 #define ROUND_SIZE(addr,size) \
102    (((UINT)(size) + ((UINT)(addr) & page_mask) + page_mask) & ~page_mask)
103
104 #define VIRTUAL_DEBUG_DUMP_VIEW(view) \
105    if (!TRACE_ON(virtual)); else VIRTUAL_DumpView(view)
106
107 static LPVOID VIRTUAL_mmap( int fd, LPVOID start, DWORD size, DWORD offset, int prot, int flags );
108
109 /* filter for page-fault exceptions */
110 static WINE_EXCEPTION_FILTER(page_fault)
111 {
112     if (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION)
113         return EXCEPTION_EXECUTE_HANDLER;
114     return EXCEPTION_CONTINUE_SEARCH;
115 }
116
117 /***********************************************************************
118  *           VIRTUAL_GetProtStr
119  */
120 static const char *VIRTUAL_GetProtStr( BYTE prot )
121 {
122     static char buffer[6];
123     buffer[0] = (prot & VPROT_COMMITTED) ? 'c' : '-';
124     buffer[1] = (prot & VPROT_GUARD) ? 'g' : '-';
125     buffer[2] = (prot & VPROT_READ) ? 'r' : '-';
126     buffer[3] = (prot & VPROT_WRITE) ?
127                     ((prot & VPROT_WRITECOPY) ? 'w' : 'W') : '-';
128     buffer[4] = (prot & VPROT_EXEC) ? 'x' : '-';
129     buffer[5] = 0;
130     return buffer;
131 }
132
133
134 /***********************************************************************
135  *           VIRTUAL_DumpView
136  */
137 static void VIRTUAL_DumpView( FILE_VIEW *view )
138 {
139     UINT i, count;
140     UINT addr = view->base;
141     BYTE prot = view->prot[0];
142
143     DPRINTF( "View: %08x - %08x",
144              view->base, view->base + view->size - 1 );
145     if (view->flags & VFLAG_SYSTEM)
146         DPRINTF( " (system)\n" );
147     else if (view->flags & VFLAG_VALLOC)
148         DPRINTF( " (valloc)\n" );
149     else if (view->mapping)
150         DPRINTF( " %d\n", view->mapping );
151     else
152         DPRINTF( " (anonymous)\n");
153
154     for (count = i = 1; i < view->size >> page_shift; i++, count++)
155     {
156         if (view->prot[i] == prot) continue;
157         DPRINTF( "      %08x - %08x %s\n",
158               addr, addr + (count << page_shift) - 1,
159               VIRTUAL_GetProtStr(prot) );
160         addr += (count << page_shift);
161         prot = view->prot[i];
162         count = 0;
163     }
164     if (count)
165         DPRINTF( "      %08x - %08x %s\n",
166               addr, addr + (count << page_shift) - 1,
167               VIRTUAL_GetProtStr(prot) );
168 }
169
170
171 /***********************************************************************
172  *           VIRTUAL_Dump
173  */
174 void VIRTUAL_Dump(void)
175 {
176     FILE_VIEW *view;
177     DPRINTF( "\nDump of all virtual memory views:\n\n" );
178     EnterCriticalSection(&csVirtual);
179     view = VIRTUAL_FirstView;
180     while (view)
181     {
182         VIRTUAL_DumpView( view );
183         view = view->next;
184     }
185     LeaveCriticalSection(&csVirtual);
186 }
187
188
189 /***********************************************************************
190  *           VIRTUAL_FindView
191  *
192  * Find the view containing a given address.
193  *
194  * RETURNS
195  *      View: Success
196  *      NULL: Failure
197  */
198 static FILE_VIEW *VIRTUAL_FindView(
199                   UINT addr /* [in] Address */
200 ) {
201     FILE_VIEW *view;
202
203     EnterCriticalSection(&csVirtual);
204     view = VIRTUAL_FirstView;
205     while (view)
206     {
207         if (view->base > addr)
208         {
209             view = NULL;
210             break;
211         }
212         if (view->base + view->size > addr) break;
213         view = view->next;
214     }
215     LeaveCriticalSection(&csVirtual);
216     return view;
217 }
218
219
220 /***********************************************************************
221  *           VIRTUAL_CreateView
222  *
223  * Create a new view and add it in the linked list.
224  */
225 static FILE_VIEW *VIRTUAL_CreateView( UINT base, UINT size, UINT flags,
226                                       BYTE vprot, HANDLE mapping )
227 {
228     FILE_VIEW *view, *prev;
229
230     /* Create the view structure */
231
232     assert( !(base & page_mask) );
233     assert( !(size & page_mask) );
234     size >>= page_shift;
235     if (!(view = (FILE_VIEW *)malloc( sizeof(*view) + size - 1 ))) return NULL;
236     view->base    = base;
237     view->size    = size << page_shift;
238     view->flags   = flags;
239     view->mapping = mapping;
240     view->protect = vprot;
241     view->handlerProc = NULL;
242     memset( view->prot, vprot, size );
243
244     /* Duplicate the mapping handle */
245
246     if (view->mapping &&
247         !DuplicateHandle( GetCurrentProcess(), view->mapping,
248                           GetCurrentProcess(), &view->mapping,
249                           0, FALSE, DUPLICATE_SAME_ACCESS ))
250     {
251         free( view );
252         return NULL;
253     }
254
255     /* Insert it in the linked list */
256
257     EnterCriticalSection(&csVirtual);
258     if (!VIRTUAL_FirstView || (VIRTUAL_FirstView->base > base))
259     {
260         view->next = VIRTUAL_FirstView;
261         view->prev = NULL;
262         if (view->next) view->next->prev = view;
263         VIRTUAL_FirstView = view;
264     }
265     else
266     {
267         prev = VIRTUAL_FirstView;
268         while (prev->next && (prev->next->base < base)) prev = prev->next;
269         view->next = prev->next;
270         view->prev = prev;
271         if (view->next) view->next->prev = view;
272         prev->next  = view;
273     }
274     LeaveCriticalSection(&csVirtual);
275     VIRTUAL_DEBUG_DUMP_VIEW( view );
276     return view;
277 }
278
279
280 /***********************************************************************
281  *           VIRTUAL_DeleteView
282  * Deletes a view.
283  *
284  * RETURNS
285  *      None
286  */
287 static void VIRTUAL_DeleteView(
288             FILE_VIEW *view /* [in] View */
289 ) {
290     if (!(view->flags & VFLAG_SYSTEM))
291         munmap( (void *)view->base, view->size );
292     EnterCriticalSection(&csVirtual);
293     if (view->next) view->next->prev = view->prev;
294     if (view->prev) view->prev->next = view->next;
295     else VIRTUAL_FirstView = view->next;
296     LeaveCriticalSection(&csVirtual);
297     if (view->mapping) NtClose( view->mapping );
298     free( view );
299 }
300
301
302 /***********************************************************************
303  *           VIRTUAL_GetUnixProt
304  *
305  * Convert page protections to protection for mmap/mprotect.
306  */
307 static int VIRTUAL_GetUnixProt( BYTE vprot )
308 {
309     int prot = 0;
310     if ((vprot & VPROT_COMMITTED) && !(vprot & VPROT_GUARD))
311     {
312         if (vprot & VPROT_READ) prot |= PROT_READ;
313         if (vprot & VPROT_WRITE) prot |= PROT_WRITE;
314         if (vprot & VPROT_WRITECOPY) prot |= PROT_WRITE;
315         if (vprot & VPROT_EXEC) prot |= PROT_EXEC;
316     }
317     return prot;
318 }
319
320
321 /***********************************************************************
322  *           VIRTUAL_GetWin32Prot
323  *
324  * Convert page protections to Win32 flags.
325  *
326  * RETURNS
327  *      None
328  */
329 static void VIRTUAL_GetWin32Prot(
330             BYTE vprot,     /* [in] Page protection flags */
331             DWORD *protect, /* [out] Location to store Win32 protection flags */
332             DWORD *state    /* [out] Location to store mem state flag */
333 ) {
334     if (protect) {
335         *protect = VIRTUAL_Win32Flags[vprot & 0x0f];
336 /*      if (vprot & VPROT_GUARD) *protect |= PAGE_GUARD;*/
337         if (vprot & VPROT_NOCACHE) *protect |= PAGE_NOCACHE;
338
339         if (vprot & VPROT_GUARD) *protect = PAGE_NOACCESS;
340     }
341
342     if (state) *state = (vprot & VPROT_COMMITTED) ? MEM_COMMIT : MEM_RESERVE;
343 }
344
345
346 /***********************************************************************
347  *           VIRTUAL_GetProt
348  *
349  * Build page protections from Win32 flags.
350  *
351  * RETURNS
352  *      Value of page protection flags
353  */
354 static BYTE VIRTUAL_GetProt(
355             DWORD protect  /* [in] Win32 protection flags */
356 ) {
357     BYTE vprot;
358
359     switch(protect & 0xff)
360     {
361     case PAGE_READONLY:
362         vprot = VPROT_READ;
363         break;
364     case PAGE_READWRITE:
365         vprot = VPROT_READ | VPROT_WRITE;
366         break;
367     case PAGE_WRITECOPY:
368         vprot = VPROT_READ | VPROT_WRITE | VPROT_WRITECOPY;
369         break;
370     case PAGE_EXECUTE:
371         vprot = VPROT_EXEC;
372         break;
373     case PAGE_EXECUTE_READ:
374         vprot = VPROT_EXEC | VPROT_READ;
375         break;
376     case PAGE_EXECUTE_READWRITE:
377         vprot = VPROT_EXEC | VPROT_READ | VPROT_WRITE;
378         break;
379     case PAGE_EXECUTE_WRITECOPY:
380         vprot = VPROT_EXEC | VPROT_READ | VPROT_WRITE | VPROT_WRITECOPY;
381         break;
382     case PAGE_NOACCESS:
383     default:
384         vprot = 0;
385         break;
386     }
387     if (protect & PAGE_GUARD) vprot |= VPROT_GUARD;
388     if (protect & PAGE_NOCACHE) vprot |= VPROT_NOCACHE;
389     return vprot;
390 }
391
392
393 /***********************************************************************
394  *           VIRTUAL_SetProt
395  *
396  * Change the protection of a range of pages.
397  *
398  * RETURNS
399  *      TRUE: Success
400  *      FALSE: Failure
401  */
402 static BOOL VIRTUAL_SetProt(
403               FILE_VIEW *view, /* [in] Pointer to view */
404               UINT base,     /* [in] Starting address */
405               UINT size,     /* [in] Size in bytes */
406               BYTE vprot       /* [in] Protections to use */
407 ) {
408     TRACE("%08x-%08x %s\n",
409                      base, base + size - 1, VIRTUAL_GetProtStr( vprot ) );
410
411     if (mprotect( (void *)base, size, VIRTUAL_GetUnixProt(vprot) ))
412         return FALSE;  /* FIXME: last error */
413
414     memset( view->prot + ((base - view->base) >> page_shift),
415             vprot, size >> page_shift );
416     VIRTUAL_DEBUG_DUMP_VIEW( view );
417     return TRUE;
418 }
419
420
421 /***********************************************************************
422  *           map_image
423  *
424  * Map an executable (PE format) image into memory.
425  */
426 static LPVOID map_image( HANDLE hmapping, int fd, char *base, DWORD total_size,
427                          DWORD header_size, HANDLE shared_file, DWORD shared_size )
428 {
429     IMAGE_DOS_HEADER *dos;
430     IMAGE_NT_HEADERS *nt;
431     IMAGE_SECTION_HEADER *sec;
432     int i, pos;
433     DWORD err = GetLastError();
434     FILE_VIEW *view = NULL;
435     char *ptr;
436     int shared_fd = -1;
437
438     SetLastError( ERROR_BAD_EXE_FORMAT );  /* generic error */
439
440     /* zero-map the whole range */
441
442     if ((ptr = wine_anon_mmap( base, total_size,
443                              PROT_READ | PROT_WRITE | PROT_EXEC, 0 )) == (char *)-1)
444     {
445         ptr = wine_anon_mmap( NULL, total_size,
446                             PROT_READ | PROT_WRITE | PROT_EXEC, 0 );
447         if (ptr == (char *)-1)
448         {
449             ERR_(module)("Not enough memory for module (%ld bytes)\n", total_size);
450             goto error;
451         }
452     }
453     TRACE_(module)( "mapped PE file at %p-%p\n", ptr, ptr + total_size );
454
455     if (!(view = VIRTUAL_CreateView( (UINT)ptr, total_size, 0,
456                                      VPROT_COMMITTED|VPROT_READ|VPROT_WRITE|VPROT_WRITECOPY,
457                                      hmapping )))
458     {
459         munmap( ptr, total_size );
460         SetLastError( ERROR_OUTOFMEMORY );
461         goto error;
462     }
463
464     /* map the header */
465
466     if (VIRTUAL_mmap( fd, ptr, header_size, 0, PROT_READ | PROT_WRITE,
467                       MAP_PRIVATE | MAP_FIXED ) == (char *)-1) goto error;
468     dos = (IMAGE_DOS_HEADER *)ptr;
469     nt = (IMAGE_NT_HEADERS *)(ptr + dos->e_lfanew);
470     if ((char *)(nt + 1) > ptr + header_size) goto error;
471
472     sec = (IMAGE_SECTION_HEADER*)((char*)&nt->OptionalHeader+nt->FileHeader.SizeOfOptionalHeader);
473     if ((char *)(sec + nt->FileHeader.NumberOfSections) > ptr + header_size) goto error;
474
475     /* check the architecture */
476
477     if (nt->FileHeader.Machine != IMAGE_FILE_MACHINE_I386)
478     {
479         MESSAGE("Trying to load PE image for unsupported architecture (");
480         switch (nt->FileHeader.Machine)
481         {
482         case IMAGE_FILE_MACHINE_UNKNOWN: MESSAGE("Unknown"); break;
483         case IMAGE_FILE_MACHINE_I860:    MESSAGE("I860"); break;
484         case IMAGE_FILE_MACHINE_R3000:   MESSAGE("R3000"); break;
485         case IMAGE_FILE_MACHINE_R4000:   MESSAGE("R4000"); break;
486         case IMAGE_FILE_MACHINE_R10000:  MESSAGE("R10000"); break;
487         case IMAGE_FILE_MACHINE_ALPHA:   MESSAGE("Alpha"); break;
488         case IMAGE_FILE_MACHINE_POWERPC: MESSAGE("PowerPC"); break;
489         default: MESSAGE("Unknown-%04x", nt->FileHeader.Machine); break;
490         }
491         MESSAGE(")\n");
492         goto error;
493     }
494     
495     /* retrieve the shared sections file */
496
497     if (shared_size)
498     {
499         if ((shared_fd = FILE_GetUnixHandle( shared_file, GENERIC_READ )) == -1) goto error;
500         CloseHandle( shared_file );  /* we no longer need it */
501         shared_file = 0;
502     }
503
504     /* map all the sections */
505
506     for (i = pos = 0; i < nt->FileHeader.NumberOfSections; i++, sec++)
507     {
508         DWORD size;
509
510         /* a few sanity checks */
511         size = sec->VirtualAddress + ROUND_SIZE( sec->VirtualAddress, sec->Misc.VirtualSize );
512         if (sec->VirtualAddress > total_size || size > total_size || size < sec->VirtualAddress)
513         {
514             ERR_(module)( "Section %.8s too large (%lx+%lx/%lx)\n",
515                           sec->Name, sec->VirtualAddress, sec->Misc.VirtualSize, total_size );
516             goto error;
517         }
518
519         if ((sec->Characteristics & IMAGE_SCN_MEM_SHARED) &&
520             (sec->Characteristics & IMAGE_SCN_MEM_WRITE))
521         {
522             size = ROUND_SIZE( 0, sec->Misc.VirtualSize );
523             TRACE_(module)( "mapping shared section %.8s at %p off %lx (%x) size %lx (%lx) flags %lx\n",
524                           sec->Name, (char *)ptr + sec->VirtualAddress,
525                           sec->PointerToRawData, pos, sec->SizeOfRawData,
526                           size, sec->Characteristics );
527             if (VIRTUAL_mmap( shared_fd, (char *)ptr + sec->VirtualAddress, size,
528                               pos, PROT_READ|PROT_WRITE|PROT_EXEC,
529                               MAP_SHARED|MAP_FIXED ) == (void *)-1)
530             {
531                 ERR_(module)( "Could not map shared section %.8s\n", sec->Name );
532                 goto error;
533             }
534             pos += size;
535             continue;
536         }
537
538         if (sec->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA) continue;
539         if (!sec->PointerToRawData || !sec->SizeOfRawData) continue;
540
541         TRACE_(module)( "mapping section %.8s at %p off %lx size %lx flags %lx\n",
542                         sec->Name, (char *)ptr + sec->VirtualAddress,
543                         sec->PointerToRawData, sec->SizeOfRawData,
544                         sec->Characteristics );
545
546         /* Note: if the section is not aligned properly VIRTUAL_mmap will magically
547          *       fall back to read(), so we don't need to check anything here.
548          */
549         if (VIRTUAL_mmap( fd, (char *)ptr + sec->VirtualAddress, sec->SizeOfRawData,
550                           sec->PointerToRawData, PROT_READ|PROT_WRITE|PROT_EXEC,
551                           MAP_PRIVATE | MAP_FIXED ) == (void *)-1)
552         {
553             ERR_(module)( "Could not map section %.8s, file probably truncated\n", sec->Name );
554             goto error;
555         }
556
557         if ((sec->SizeOfRawData < sec->Misc.VirtualSize) && (sec->SizeOfRawData & page_mask))
558         {
559             DWORD end = ROUND_SIZE( 0, sec->SizeOfRawData );
560             if (end > sec->Misc.VirtualSize) end = sec->Misc.VirtualSize;
561             TRACE_(module)("clearing %p - %p\n",
562                            (char *)ptr + sec->VirtualAddress + sec->SizeOfRawData,
563                            (char *)ptr + sec->VirtualAddress + end );
564             memset( (char *)ptr + sec->VirtualAddress + sec->SizeOfRawData, 0,
565                     end - sec->SizeOfRawData );
566         }
567     }
568
569     SetLastError( err );  /* restore last error */
570     close( fd );
571     if (shared_fd != -1) close( shared_fd );
572     return ptr;
573
574  error:
575     if (view) VIRTUAL_DeleteView( view );
576     close( fd );
577     if (shared_fd != -1) close( shared_fd );
578     if (shared_file) CloseHandle( shared_file );
579     return NULL;
580 }
581
582
583 /***********************************************************************
584  *           VIRTUAL_Init
585  */
586 #ifndef page_mask
587 DECL_GLOBAL_CONSTRUCTOR(VIRTUAL_Init)
588 {
589     page_size = getpagesize();
590     page_mask = page_size - 1;
591     /* Make sure we have a power of 2 */
592     assert( !(page_size & page_mask) );
593     page_shift = 0;
594     while ((1 << page_shift) != page_size) page_shift++;
595 }
596 #endif  /* page_mask */
597
598
599 /***********************************************************************
600  *           VIRTUAL_SetFaultHandler
601  */
602 BOOL VIRTUAL_SetFaultHandler( LPCVOID addr, HANDLERPROC proc, LPVOID arg )
603 {
604     FILE_VIEW *view;
605
606     if (!(view = VIRTUAL_FindView((UINT)addr))) return FALSE;
607     view->handlerProc = proc;
608     view->handlerArg  = arg;
609     return TRUE;
610 }
611
612 /***********************************************************************
613  *           VIRTUAL_HandleFault
614  */
615 DWORD VIRTUAL_HandleFault( LPCVOID addr )
616 {
617     FILE_VIEW *view = VIRTUAL_FindView((UINT)addr);
618     DWORD ret = EXCEPTION_ACCESS_VIOLATION;
619
620     if (view)
621     {
622         if (view->handlerProc)
623         {
624             if (view->handlerProc(view->handlerArg, addr)) ret = 0;  /* handled */
625         }
626         else
627         {
628             BYTE vprot = view->prot[((UINT)addr - view->base) >> page_shift];
629             UINT page = (UINT)addr & ~page_mask;
630             char *stack = (char *)NtCurrentTeb()->stack_base + SIGNAL_STACK_SIZE + page_mask + 1;
631             if (vprot & VPROT_GUARD)
632             {
633                 VIRTUAL_SetProt( view, page, page_mask + 1, vprot & ~VPROT_GUARD );
634                 ret = STATUS_GUARD_PAGE_VIOLATION;
635             }
636             /* is it inside the stack guard pages? */
637             if (((char *)addr >= stack) && ((char *)addr < stack + 2*(page_mask+1)))
638                 ret = STATUS_STACK_OVERFLOW;
639         }
640     }
641     return ret;
642 }
643
644
645 /***********************************************************************
646  *           VIRTUAL_mmap
647  *
648  * Wrapper for mmap() that handles anonymous mappings portably,
649  * and falls back to read if mmap of a file fails.
650  */
651 static LPVOID VIRTUAL_mmap( int fd, LPVOID start, DWORD size,
652                             DWORD offset, int prot, int flags )
653 {
654     int pos;
655     LPVOID ret;
656
657     if (fd == -1) return wine_anon_mmap( start, size, prot, flags );
658
659     if ((ret = mmap( start, size, prot, flags, fd, offset )) != (LPVOID)-1)
660         return ret;
661
662     /* mmap() failed; if this is because the file offset is not    */
663     /* page-aligned (EINVAL), or because the underlying filesystem */
664     /* does not support mmap() (ENOEXEC,ENODEV), we do it by hand. */
665
666     if ((errno != ENOEXEC) && (errno != EINVAL) && (errno != ENODEV)) return ret;
667     if (prot & PROT_WRITE)
668     {
669         /* We cannot fake shared write mappings */
670 #ifdef MAP_SHARED
671         if (flags & MAP_SHARED) return ret;
672 #endif
673 #ifdef MAP_PRIVATE
674         if (!(flags & MAP_PRIVATE)) return ret;
675 #endif
676     }
677
678     /* Reserve the memory with an anonymous mmap */
679     ret = wine_anon_mmap( start, size, PROT_READ | PROT_WRITE, flags );
680     if (ret == (LPVOID)-1) return ret;
681     /* Now read in the file */
682     if ((pos = lseek( fd, offset, SEEK_SET )) == -1)
683     {
684         munmap( ret, size );
685         return (LPVOID)-1;
686     }
687     read( fd, ret, size );
688     lseek( fd, pos, SEEK_SET );  /* Restore the file pointer */
689     mprotect( ret, size, prot );  /* Set the right protection */
690     return ret;
691 }
692
693
694 /***********************************************************************
695  *             VirtualAlloc   (KERNEL32.548)
696  * Reserves or commits a region of pages in virtual address space
697  *
698  * RETURNS
699  *      Base address of allocated region of pages
700  *      NULL: Failure
701  */
702 LPVOID WINAPI VirtualAlloc(
703               LPVOID addr,  /* [in] Address of region to reserve or commit */
704               DWORD size,   /* [in] Size of region */
705               DWORD type,   /* [in] Type of allocation */
706               DWORD protect /* [in] Type of access protection */
707 ) {
708     FILE_VIEW *view;
709     UINT base, ptr, view_size;
710     BYTE vprot;
711
712     TRACE("%08x %08lx %lx %08lx\n",
713                      (UINT)addr, size, type, protect );
714
715     /* Round parameters to a page boundary */
716
717     if (size > 0x7fc00000)  /* 2Gb - 4Mb */
718     {
719         SetLastError( ERROR_OUTOFMEMORY );
720         return NULL;
721     }
722     if (addr)
723     {
724         if (type & MEM_RESERVE) /* Round down to 64k boundary */
725             base = (UINT)addr & ~granularity_mask;
726         else
727             base = ROUND_ADDR( addr );
728         size = (((UINT)addr + size + page_mask) & ~page_mask) - base;
729         if ((base <= granularity_mask) || (base + size < base))
730         {
731             /* disallow low 64k and wrap-around */
732             SetLastError( ERROR_INVALID_PARAMETER );
733             return NULL;
734         }
735     }
736     else
737     {
738         base = 0;
739         size = (size + page_mask) & ~page_mask;
740     }
741
742     if (type & MEM_TOP_DOWN) {
743         /* FIXME: MEM_TOP_DOWN allocates the largest possible address.
744          *        Is there _ANY_ way to do it with UNIX mmap()?
745          */
746         WARN("MEM_TOP_DOWN ignored\n");
747         type &= ~MEM_TOP_DOWN;
748     }
749     /* Compute the alloc type flags */
750
751     if (!(type & (MEM_COMMIT | MEM_RESERVE | MEM_SYSTEM)) ||
752         (type & ~(MEM_COMMIT | MEM_RESERVE | MEM_SYSTEM)))
753     {
754         ERR("called with wrong alloc type flags (%08lx) !\n", type);
755         SetLastError( ERROR_INVALID_PARAMETER );
756         return NULL;
757     }
758     if (type & (MEM_COMMIT | MEM_SYSTEM))
759         vprot = VIRTUAL_GetProt( protect ) | VPROT_COMMITTED;
760     else vprot = 0;
761
762     /* Reserve the memory */
763
764     if ((type & MEM_RESERVE) || !base)
765     {
766         view_size = size + (base ? 0 : granularity_mask + 1);
767         if (type & MEM_SYSTEM)
768              ptr = base;
769         else
770             ptr = (UINT)wine_anon_mmap( (LPVOID)base, view_size, VIRTUAL_GetUnixProt( vprot ), 0 );
771         if (ptr == (UINT)-1)
772         {
773             SetLastError( ERROR_OUTOFMEMORY );
774             return NULL;
775         }
776         if (!base)
777         {
778             /* Release the extra memory while keeping the range */
779             /* starting on a 64k boundary. */
780
781             if (ptr & granularity_mask)
782             {
783                 UINT extra = granularity_mask + 1 - (ptr & granularity_mask);
784                 munmap( (void *)ptr, extra );
785                 ptr += extra;
786                 view_size -= extra;
787             }
788             if (view_size > size)
789                 munmap( (void *)(ptr + size), view_size - size );
790         }
791         else if (ptr != base)
792         {
793             /* We couldn't get the address we wanted */
794             munmap( (void *)ptr, view_size );
795             SetLastError( ERROR_INVALID_ADDRESS );
796             return NULL;
797         }
798         if (!(view = VIRTUAL_CreateView( ptr, size,
799                                          VFLAG_VALLOC | ((type & MEM_SYSTEM) ? VFLAG_SYSTEM : 0),
800                                          vprot, 0 )))
801         {
802             munmap( (void *)ptr, size );
803             SetLastError( ERROR_OUTOFMEMORY );
804             return NULL;
805         }
806         return (LPVOID)ptr;
807     }
808
809     /* Commit the pages */
810
811     if (!(view = VIRTUAL_FindView( base )) ||
812         (base + size > view->base + view->size))
813     {
814         SetLastError( ERROR_INVALID_ADDRESS );
815         return NULL;
816     }
817
818     if (!VIRTUAL_SetProt( view, base, size, vprot )) return NULL;
819     return (LPVOID)base;
820 }
821
822
823 /***********************************************************************
824  *             VirtualAllocEx   (KERNEL32.548)
825  *
826  * Seems to be just as VirtualAlloc, but with process handle.
827  */
828 LPVOID WINAPI VirtualAllocEx(
829               HANDLE hProcess, /* [in] Handle of process to do mem operation */
830               LPVOID addr,  /* [in] Address of region to reserve or commit */
831               DWORD size,   /* [in] Size of region */
832               DWORD type,   /* [in] Type of allocation */
833               DWORD protect /* [in] Type of access protection */
834 ) {
835     if (MapProcessHandle( hProcess ) == GetCurrentProcessId())
836         return VirtualAlloc( addr, size, type, protect );
837     ERR("Unsupported on other process\n");
838     return NULL;
839 }
840
841
842 /***********************************************************************
843  *             VirtualFree   (KERNEL32.550)
844  * Release or decommits a region of pages in virtual address space.
845  * 
846  * RETURNS
847  *      TRUE: Success
848  *      FALSE: Failure
849  */
850 BOOL WINAPI VirtualFree(
851               LPVOID addr, /* [in] Address of region of committed pages */
852               DWORD size,  /* [in] Size of region */
853               DWORD type   /* [in] Type of operation */
854 ) {
855     FILE_VIEW *view;
856     UINT base;
857
858     TRACE("%08x %08lx %lx\n",
859                      (UINT)addr, size, type );
860
861     /* Fix the parameters */
862
863     size = ROUND_SIZE( addr, size );
864     base = ROUND_ADDR( addr );
865
866     if (!(view = VIRTUAL_FindView( base )) ||
867         (base + size > view->base + view->size) ||
868         !(view->flags & VFLAG_VALLOC))
869     {
870         SetLastError( ERROR_INVALID_PARAMETER );
871         return FALSE;
872     }
873
874     /* Compute the protection flags */
875
876     if ((type != MEM_DECOMMIT) && (type != MEM_RELEASE))
877     {
878         ERR("called with wrong free type flags (%08lx) !\n", type);
879         SetLastError( ERROR_INVALID_PARAMETER );
880         return FALSE;
881     }
882
883     /* Free the pages */
884
885     if (type == MEM_RELEASE)
886     {
887         if (size || (base != view->base))
888         {
889             SetLastError( ERROR_INVALID_PARAMETER );
890             return FALSE;
891         }
892         VIRTUAL_DeleteView( view );
893         return TRUE;
894     }
895
896     /* Decommit the pages by remapping zero-pages instead */
897
898     if (wine_anon_mmap( (LPVOID)base, size, VIRTUAL_GetUnixProt(0), MAP_FIXED ) != (LPVOID)base)
899         ERR( "Could not remap pages, expect trouble\n" );
900     return VIRTUAL_SetProt( view, base, size, 0 );
901 }
902
903
904 /***********************************************************************
905  *             VirtualLock   (KERNEL32.551)
906  * Locks the specified region of virtual address space
907  * 
908  * NOTE
909  *      Always returns TRUE
910  *
911  * RETURNS
912  *      TRUE: Success
913  *      FALSE: Failure
914  */
915 BOOL WINAPI VirtualLock(
916               LPVOID addr, /* [in] Address of first byte of range to lock */
917               DWORD size   /* [in] Number of bytes in range to lock */
918 ) {
919     return TRUE;
920 }
921
922
923 /***********************************************************************
924  *             VirtualUnlock   (KERNEL32.556)
925  * Unlocks a range of pages in the virtual address space
926  *
927  * NOTE
928  *      Always returns TRUE
929  *
930  * RETURNS
931  *      TRUE: Success
932  *      FALSE: Failure
933  */
934 BOOL WINAPI VirtualUnlock(
935               LPVOID addr, /* [in] Address of first byte of range */
936               DWORD size   /* [in] Number of bytes in range */
937 ) {
938     return TRUE;
939 }
940
941
942 /***********************************************************************
943  *             VirtualProtect   (KERNEL32.552)
944  * Changes the access protection on a region of committed pages
945  *
946  * RETURNS
947  *      TRUE: Success
948  *      FALSE: Failure
949  */
950 BOOL WINAPI VirtualProtect(
951               LPVOID addr,     /* [in] Address of region of committed pages */
952               DWORD size,      /* [in] Size of region */
953               DWORD new_prot,  /* [in] Desired access protection */
954               LPDWORD old_prot /* [out] Address of variable to get old protection */
955 ) {
956     FILE_VIEW *view;
957     UINT base, i;
958     BYTE vprot, *p;
959
960     TRACE("%08x %08lx %08lx\n",
961                      (UINT)addr, size, new_prot );
962
963     /* Fix the parameters */
964
965     size = ROUND_SIZE( addr, size );
966     base = ROUND_ADDR( addr );
967
968     if (!(view = VIRTUAL_FindView( base )) ||
969         (base + size > view->base + view->size))
970     {
971         SetLastError( ERROR_INVALID_PARAMETER );
972         return FALSE;
973     }
974
975     /* Make sure all the pages are committed */
976
977     p = view->prot + ((base - view->base) >> page_shift);
978     for (i = size >> page_shift; i; i--, p++)
979     {
980         if (!(*p & VPROT_COMMITTED))
981         {
982             SetLastError( ERROR_INVALID_PARAMETER );
983             return FALSE;
984         }
985     }
986
987     if (old_prot) VIRTUAL_GetWin32Prot( view->prot[0], old_prot, NULL );
988     vprot = VIRTUAL_GetProt( new_prot ) | VPROT_COMMITTED;
989     return VIRTUAL_SetProt( view, base, size, vprot );
990 }
991
992
993 /***********************************************************************
994  *             VirtualProtectEx   (KERNEL32.553)
995  * Changes the access protection on a region of committed pages in the
996  * virtual address space of a specified process
997  *
998  * RETURNS
999  *      TRUE: Success
1000  *      FALSE: Failure
1001  */
1002 BOOL WINAPI VirtualProtectEx(
1003               HANDLE handle, /* [in]  Handle of process */
1004               LPVOID addr,     /* [in]  Address of region of committed pages */
1005               DWORD size,      /* [in]  Size of region */
1006               DWORD new_prot,  /* [in]  Desired access protection */
1007               LPDWORD old_prot /* [out] Address of variable to get old protection */ )
1008 {
1009     if (MapProcessHandle( handle ) == GetCurrentProcessId())
1010         return VirtualProtect( addr, size, new_prot, old_prot );
1011     ERR("Unsupported on other process\n");
1012     return FALSE;
1013 }
1014
1015
1016 /***********************************************************************
1017  *             VirtualQuery   (KERNEL32.554)
1018  * Provides info about a range of pages in virtual address space
1019  *
1020  * RETURNS
1021  *      Number of bytes returned in information buffer
1022  *      or 0 if addr is >= 0xc0000000 (kernel space).
1023  */
1024 DWORD WINAPI VirtualQuery(
1025              LPCVOID addr,                    /* [in]  Address of region */
1026              LPMEMORY_BASIC_INFORMATION info, /* [out] Address of info buffer */
1027              DWORD len                        /* [in]  Size of buffer */
1028 ) {
1029     FILE_VIEW *view;
1030     UINT base;
1031     UINT alloc_base = 0;
1032     UINT size = 0;
1033
1034     if (addr >= (void*)0xc0000000) return 0;
1035
1036     base = ROUND_ADDR( addr );
1037
1038     /* Find the view containing the address */
1039
1040     EnterCriticalSection(&csVirtual);
1041     view = VIRTUAL_FirstView;
1042     for (;;)
1043     {
1044         if (!view)
1045         {
1046             size = 0xffff0000 - alloc_base;
1047             break;
1048         }
1049         if (view->base > base)
1050         {
1051             size = view->base - alloc_base;
1052             view = NULL;
1053             break;
1054         }
1055         if (view->base + view->size > base)
1056         {
1057             alloc_base = view->base;
1058             size = view->size;
1059             break;
1060         }
1061         alloc_base = view->base + view->size;
1062         view = view->next;
1063     }
1064     LeaveCriticalSection(&csVirtual);
1065
1066     /* Fill the info structure */
1067
1068     if (!view)
1069     {
1070         info->State             = MEM_FREE;
1071         info->Protect           = 0;
1072         info->AllocationProtect = 0;
1073         info->Type              = 0;
1074     }
1075     else
1076     {
1077         BYTE vprot = view->prot[(base - alloc_base) >> page_shift];
1078         VIRTUAL_GetWin32Prot( vprot, &info->Protect, &info->State );
1079         for (size = base - alloc_base; size < view->size; size += page_mask+1)
1080             if (view->prot[size >> page_shift] != vprot) break;
1081         info->AllocationProtect = view->protect;
1082         info->Type              = MEM_PRIVATE;  /* FIXME */
1083     }
1084
1085     info->BaseAddress    = (LPVOID)base;
1086     info->AllocationBase = (LPVOID)alloc_base;
1087     info->RegionSize     = size - (base - alloc_base);
1088     return sizeof(*info);
1089 }
1090
1091
1092 /***********************************************************************
1093  *             VirtualQueryEx   (KERNEL32.555)
1094  * Provides info about a range of pages in virtual address space of a
1095  * specified process
1096  *
1097  * RETURNS
1098  *      Number of bytes returned in information buffer
1099  */
1100 DWORD WINAPI VirtualQueryEx(
1101              HANDLE handle,                 /* [in] Handle of process */
1102              LPCVOID addr,                    /* [in] Address of region */
1103              LPMEMORY_BASIC_INFORMATION info, /* [out] Address of info buffer */
1104              DWORD len                        /* [in] Size of buffer */ )
1105 {
1106     if (MapProcessHandle( handle ) == GetCurrentProcessId())
1107         return VirtualQuery( addr, info, len );
1108     ERR("Unsupported on other process\n");
1109     return 0;
1110 }
1111
1112
1113 /***********************************************************************
1114  *             IsBadReadPtr   (KERNEL32.354)
1115  *
1116  * RETURNS
1117  *      FALSE: Process has read access to entire block
1118  *      TRUE: Otherwise
1119  */
1120 BOOL WINAPI IsBadReadPtr(
1121               LPCVOID ptr, /* [in] Address of memory block */
1122               UINT size )  /* [in] Size of block */
1123 {
1124     if (!size) return FALSE;  /* handle 0 size case w/o reference */
1125     __TRY
1126     {
1127         volatile const char *p = ptr;
1128         char dummy;
1129         UINT count = size;
1130
1131         while (count > page_size)
1132         {
1133             dummy = *p;
1134             p += page_size;
1135             count -= page_size;
1136         }
1137         dummy = p[0];
1138         dummy = p[count - 1];
1139     }
1140     __EXCEPT(page_fault) { return TRUE; }
1141     __ENDTRY
1142     return FALSE;
1143 }
1144
1145
1146 /***********************************************************************
1147  *             IsBadWritePtr   (KERNEL32.357)
1148  *
1149  * RETURNS
1150  *      FALSE: Process has write access to entire block
1151  *      TRUE: Otherwise
1152  */
1153 BOOL WINAPI IsBadWritePtr(
1154               LPVOID ptr, /* [in] Address of memory block */
1155               UINT size ) /* [in] Size of block in bytes */
1156 {
1157     if (!size) return FALSE;  /* handle 0 size case w/o reference */
1158     __TRY
1159     {
1160         volatile char *p = ptr;
1161         UINT count = size;
1162
1163         while (count > page_size)
1164         {
1165             *p |= 0;
1166             p += page_size;
1167             count -= page_size;
1168         }
1169         p[0] |= 0;
1170         p[count - 1] |= 0;
1171     }
1172     __EXCEPT(page_fault) { return TRUE; }
1173     __ENDTRY
1174     return FALSE;
1175 }
1176
1177
1178 /***********************************************************************
1179  *             IsBadHugeReadPtr   (KERNEL32.352)
1180  * RETURNS
1181  *      FALSE: Process has read access to entire block
1182  *      TRUE: Otherwise
1183  */
1184 BOOL WINAPI IsBadHugeReadPtr(
1185               LPCVOID ptr, /* [in] Address of memory block */
1186               UINT size  /* [in] Size of block */
1187 ) {
1188     return IsBadReadPtr( ptr, size );
1189 }
1190
1191
1192 /***********************************************************************
1193  *             IsBadHugeWritePtr   (KERNEL32.353)
1194  * RETURNS
1195  *      FALSE: Process has write access to entire block
1196  *      TRUE: Otherwise
1197  */
1198 BOOL WINAPI IsBadHugeWritePtr(
1199               LPVOID ptr, /* [in] Address of memory block */
1200               UINT size /* [in] Size of block */
1201 ) {
1202     return IsBadWritePtr( ptr, size );
1203 }
1204
1205
1206 /***********************************************************************
1207  *             IsBadCodePtr   (KERNEL32.351)
1208  *
1209  * RETURNS
1210  *      FALSE: Process has read access to specified memory
1211  *      TRUE: Otherwise
1212  */
1213 BOOL WINAPI IsBadCodePtr( FARPROC ptr ) /* [in] Address of function */
1214 {
1215     return IsBadReadPtr( ptr, 1 );
1216 }
1217
1218
1219 /***********************************************************************
1220  *             IsBadStringPtrA   (KERNEL32.355)
1221  *
1222  * RETURNS
1223  *      FALSE: Read access to all bytes in string
1224  *      TRUE: Else
1225  */
1226 BOOL WINAPI IsBadStringPtrA(
1227               LPCSTR str, /* [in] Address of string */
1228               UINT max )  /* [in] Maximum size of string */
1229 {
1230     __TRY
1231     {
1232         volatile const char *p = str;
1233         while (p != str + max) if (!*p++) break;
1234     }
1235     __EXCEPT(page_fault) { return TRUE; }
1236     __ENDTRY
1237     return FALSE;
1238 }
1239
1240
1241 /***********************************************************************
1242  *             IsBadStringPtrW   (KERNEL32.356)
1243  * See IsBadStringPtrA
1244  */
1245 BOOL WINAPI IsBadStringPtrW( LPCWSTR str, UINT max )
1246 {
1247     __TRY
1248     {
1249         volatile const WCHAR *p = str;
1250         while (p != str + max) if (!*p++) break;
1251     }
1252     __EXCEPT(page_fault) { return TRUE; }
1253     __ENDTRY
1254     return FALSE;
1255 }
1256
1257
1258 /***********************************************************************
1259  *             CreateFileMappingA   (KERNEL32.46)
1260  * Creates a named or unnamed file-mapping object for the specified file
1261  *
1262  * RETURNS
1263  *      Handle: Success
1264  *      0: Mapping object does not exist
1265  *      NULL: Failure
1266  */
1267 HANDLE WINAPI CreateFileMappingA(
1268                 HANDLE hFile,   /* [in] Handle of file to map */
1269                 SECURITY_ATTRIBUTES *sa, /* [in] Optional security attributes*/
1270                 DWORD protect,   /* [in] Protection for mapping object */
1271                 DWORD size_high, /* [in] High-order 32 bits of object size */
1272                 DWORD size_low,  /* [in] Low-order 32 bits of object size */
1273                 LPCSTR name      /* [in] Name of file-mapping object */ )
1274 {
1275     HANDLE ret;
1276     BYTE vprot;
1277     DWORD len = name ? MultiByteToWideChar( CP_ACP, 0, name, strlen(name), NULL, 0 ) : 0;
1278
1279     /* Check parameters */
1280
1281     TRACE("(%x,%p,%08lx,%08lx%08lx,%s)\n",
1282           hFile, sa, protect, size_high, size_low, debugstr_a(name) );
1283
1284     if (len > MAX_PATH)
1285     {
1286         SetLastError( ERROR_FILENAME_EXCED_RANGE );
1287         return 0;
1288     }
1289     vprot = VIRTUAL_GetProt( protect );
1290     if (protect & SEC_RESERVE)
1291     {
1292         if (hFile != INVALID_HANDLE_VALUE)
1293         {
1294             SetLastError( ERROR_INVALID_PARAMETER );
1295             return 0;
1296         }
1297     }
1298     else vprot |= VPROT_COMMITTED;
1299     if (protect & SEC_NOCACHE) vprot |= VPROT_NOCACHE;
1300     if (protect & SEC_IMAGE) vprot |= VPROT_IMAGE;
1301
1302     /* Create the server object */
1303
1304     if (hFile == INVALID_HANDLE_VALUE) hFile = 0;
1305     SERVER_START_REQ
1306     {
1307         struct create_mapping_request *req = server_alloc_req( sizeof(*req),
1308                                                                len * sizeof(WCHAR) );
1309         req->file_handle = hFile;
1310         req->size_high   = size_high;
1311         req->size_low    = size_low;
1312         req->protect     = vprot;
1313         req->inherit     = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
1314         if (len) MultiByteToWideChar( CP_ACP, 0, name, strlen(name), server_data_ptr(req), len );
1315         SetLastError(0);
1316         server_call( REQ_CREATE_MAPPING );
1317         ret = req->handle;
1318     }
1319     SERVER_END_REQ;
1320     return ret;
1321 }
1322
1323
1324 /***********************************************************************
1325  *             CreateFileMappingW   (KERNEL32.47)
1326  * See CreateFileMappingA
1327  */
1328 HANDLE WINAPI CreateFileMappingW( HANDLE hFile, LPSECURITY_ATTRIBUTES sa, 
1329                                   DWORD protect, DWORD size_high,  
1330                                   DWORD size_low, LPCWSTR name )
1331 {
1332     HANDLE ret;
1333     BYTE vprot;
1334     DWORD len = name ? strlenW(name) : 0;
1335
1336     /* Check parameters */
1337
1338     TRACE("(%x,%p,%08lx,%08lx%08lx,%s)\n",
1339           hFile, sa, protect, size_high, size_low, debugstr_w(name) );
1340
1341     if (len > MAX_PATH)
1342     {
1343         SetLastError( ERROR_FILENAME_EXCED_RANGE );
1344         return 0;
1345     }
1346
1347     vprot = VIRTUAL_GetProt( protect );
1348     if (protect & SEC_RESERVE)
1349     {
1350         if (hFile != INVALID_HANDLE_VALUE)
1351         {
1352             SetLastError( ERROR_INVALID_PARAMETER );
1353             return 0;
1354         }
1355     }
1356     else vprot |= VPROT_COMMITTED;
1357     if (protect & SEC_NOCACHE) vprot |= VPROT_NOCACHE;
1358     if (protect & SEC_IMAGE) vprot |= VPROT_IMAGE;
1359
1360     /* Create the server object */
1361
1362     if (hFile == INVALID_HANDLE_VALUE) hFile = 0;
1363     SERVER_START_REQ
1364     {
1365         struct create_mapping_request *req = server_alloc_req( sizeof(*req),
1366                                                                len * sizeof(WCHAR) );
1367         req->file_handle = hFile;
1368         req->size_high   = size_high;
1369         req->size_low    = size_low;
1370         req->protect     = vprot;
1371         req->inherit     = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
1372         memcpy( server_data_ptr(req), name, len * sizeof(WCHAR) );
1373         SetLastError(0);
1374         server_call( REQ_CREATE_MAPPING );
1375         ret = req->handle;
1376     }
1377     SERVER_END_REQ;
1378     return ret;
1379 }
1380
1381
1382 /***********************************************************************
1383  *             OpenFileMappingA   (KERNEL32.397)
1384  * Opens a named file-mapping object.
1385  *
1386  * RETURNS
1387  *      Handle: Success
1388  *      NULL: Failure
1389  */
1390 HANDLE WINAPI OpenFileMappingA(
1391                 DWORD access,   /* [in] Access mode */
1392                 BOOL inherit, /* [in] Inherit flag */
1393                 LPCSTR name )   /* [in] Name of file-mapping object */
1394 {
1395     HANDLE ret;
1396     DWORD len = name ? MultiByteToWideChar( CP_ACP, 0, name, strlen(name), NULL, 0 ) : 0;
1397     if (len > MAX_PATH)
1398     {
1399         SetLastError( ERROR_FILENAME_EXCED_RANGE );
1400         return 0;
1401     }
1402     SERVER_START_REQ
1403     {
1404         struct open_mapping_request *req = server_alloc_req( sizeof(*req), len * sizeof(WCHAR) );
1405
1406         req->access  = access;
1407         req->inherit = inherit;
1408         if (len) MultiByteToWideChar( CP_ACP, 0, name, strlen(name), server_data_ptr(req), len );
1409         server_call( REQ_OPEN_MAPPING );
1410         ret = req->handle;
1411     }
1412     SERVER_END_REQ;
1413     return ret;
1414 }
1415
1416
1417 /***********************************************************************
1418  *             OpenFileMappingW   (KERNEL32.398)
1419  * See OpenFileMappingA
1420  */
1421 HANDLE WINAPI OpenFileMappingW( DWORD access, BOOL inherit, LPCWSTR name)
1422 {
1423     HANDLE ret;
1424     DWORD len = name ? strlenW(name) : 0;
1425     if (len > MAX_PATH)
1426     {
1427         SetLastError( ERROR_FILENAME_EXCED_RANGE );
1428         return 0;
1429     }
1430     SERVER_START_REQ
1431     {
1432         struct open_mapping_request *req = server_alloc_req( sizeof(*req), len * sizeof(WCHAR) );
1433
1434         req->access  = access;
1435         req->inherit = inherit;
1436         memcpy( server_data_ptr(req), name, len * sizeof(WCHAR) );
1437         server_call( REQ_OPEN_MAPPING );
1438         ret = req->handle;
1439     }
1440     SERVER_END_REQ;
1441     return ret;
1442 }
1443
1444
1445 /***********************************************************************
1446  *             MapViewOfFile   (KERNEL32.385)
1447  * Maps a view of a file into the address space
1448  *
1449  * RETURNS
1450  *      Starting address of mapped view
1451  *      NULL: Failure
1452  */
1453 LPVOID WINAPI MapViewOfFile(
1454               HANDLE mapping,  /* [in] File-mapping object to map */
1455               DWORD access,      /* [in] Access mode */
1456               DWORD offset_high, /* [in] High-order 32 bits of file offset */
1457               DWORD offset_low,  /* [in] Low-order 32 bits of file offset */
1458               DWORD count        /* [in] Number of bytes to map */
1459 ) {
1460     return MapViewOfFileEx( mapping, access, offset_high,
1461                             offset_low, count, NULL );
1462 }
1463
1464
1465 /***********************************************************************
1466  *             MapViewOfFileEx   (KERNEL32.386)
1467  * Maps a view of a file into the address space
1468  *
1469  * RETURNS
1470  *      Starting address of mapped view
1471  *      NULL: Failure
1472  */
1473 LPVOID WINAPI MapViewOfFileEx(
1474               HANDLE handle,   /* [in] File-mapping object to map */
1475               DWORD access,      /* [in] Access mode */
1476               DWORD offset_high, /* [in] High-order 32 bits of file offset */
1477               DWORD offset_low,  /* [in] Low-order 32 bits of file offset */
1478               DWORD count,       /* [in] Number of bytes to map */
1479               LPVOID addr        /* [in] Suggested starting address for mapped view */
1480 ) {
1481     FILE_VIEW *view;
1482     UINT ptr = (UINT)-1, size = 0;
1483     int flags = MAP_PRIVATE;
1484     int unix_handle = -1;
1485     int prot, anonymous, res;
1486     void *base;
1487     DWORD size_low, size_high, header_size, shared_size;
1488     HANDLE shared_file;
1489
1490     /* Check parameters */
1491
1492     if ((offset_low & granularity_mask) ||
1493         (addr && ((UINT)addr & granularity_mask)))
1494     {
1495         SetLastError( ERROR_INVALID_PARAMETER );
1496         return NULL;
1497     }
1498
1499     SERVER_START_REQ
1500     {
1501         struct get_mapping_info_request *req = server_alloc_req( sizeof(*req), 0 );
1502         req->handle = handle;
1503         res = server_call( REQ_GET_MAPPING_INFO );
1504         prot        = req->protect;
1505         base        = req->base;
1506         size_low    = req->size_low;
1507         size_high   = req->size_high;
1508         header_size = req->header_size;
1509         shared_file = req->shared_file;
1510         shared_size = req->shared_size;
1511         anonymous   = req->anonymous;
1512     }
1513     SERVER_END_REQ;
1514     if (res) goto error;
1515
1516     if (!anonymous)
1517     {
1518         if ((unix_handle = FILE_GetUnixHandle( handle, 0 )) == -1) goto error;
1519     }
1520
1521     if (prot & VPROT_IMAGE)
1522         return map_image( handle, unix_handle, base, size_low, header_size,
1523                           shared_file, shared_size );
1524
1525
1526     if (size_high || offset_high)
1527         ERR("Offsets larger than 4Gb not supported\n");
1528
1529     if ((offset_low >= size_low) ||
1530         (count > size_low - offset_low))
1531     {
1532         SetLastError( ERROR_INVALID_PARAMETER );
1533         goto error;
1534     }
1535     if (count) size = ROUND_SIZE( offset_low, count );
1536     else size = size_low - offset_low;
1537
1538     switch(access)
1539     {
1540     case FILE_MAP_ALL_ACCESS:
1541     case FILE_MAP_WRITE:
1542     case FILE_MAP_WRITE | FILE_MAP_READ:
1543         if (!(prot & VPROT_WRITE))
1544         {
1545             SetLastError( ERROR_INVALID_PARAMETER );
1546             goto error;
1547         }
1548         flags = MAP_SHARED;
1549         /* fall through */
1550     case FILE_MAP_READ:
1551     case FILE_MAP_COPY:
1552     case FILE_MAP_COPY | FILE_MAP_READ:
1553         if (prot & VPROT_READ) break;
1554         /* fall through */
1555     default:
1556         SetLastError( ERROR_INVALID_PARAMETER );
1557         goto error;
1558     }
1559
1560     /* FIXME: If a mapping is created with SEC_RESERVE and a process,
1561      * which has a view of this mapping commits some pages, they will
1562      * appear commited in all other processes, which have the same
1563      * view created. Since we don`t support this yet, we create the
1564      * whole mapping commited.
1565      */
1566     prot |= VPROT_COMMITTED;
1567
1568     /* Map the file */
1569
1570     TRACE("handle=%x size=%x offset=%lx\n", handle, size, offset_low );
1571
1572     ptr = (UINT)VIRTUAL_mmap( unix_handle, addr, size, offset_low,
1573                               VIRTUAL_GetUnixProt( prot ), flags );
1574     if (ptr == (UINT)-1) {
1575         /* KB: Q125713, 25-SEP-1995, "Common File Mapping Problems and
1576          * Platform Differences": 
1577          * Windows NT: ERROR_INVALID_PARAMETER
1578          * Windows 95: ERROR_INVALID_ADDRESS.
1579          */
1580         if (errno==ENOMEM)
1581             SetLastError( ERROR_OUTOFMEMORY );
1582         else
1583         {
1584             if (GetVersion() & 0x80000000)  /* win95 */
1585             {
1586                 TRACE("setting ERROR_INVALID_ADDRESS for WinXX\n");
1587                 SetLastError( ERROR_INVALID_ADDRESS );
1588             }
1589             else
1590             {
1591                 TRACE("setting ERROR_INVALID_PARAMETER for NTXX\n");
1592                 SetLastError( ERROR_INVALID_PARAMETER );
1593             }
1594         }
1595         goto error;
1596     }
1597
1598     if (!(view = VIRTUAL_CreateView( ptr, size, 0, prot, handle )))
1599     {
1600         SetLastError( ERROR_OUTOFMEMORY );
1601         goto error;
1602     }
1603     if (unix_handle != -1) close( unix_handle );
1604     return (LPVOID)ptr;
1605
1606 error:
1607     if (unix_handle != -1) close( unix_handle );
1608     if (ptr != (UINT)-1) munmap( (void *)ptr, size );
1609     return NULL;
1610 }
1611
1612
1613 /***********************************************************************
1614  *             FlushViewOfFile   (KERNEL32.262)
1615  * Writes to the disk a byte range within a mapped view of a file
1616  *
1617  * RETURNS
1618  *      TRUE: Success
1619  *      FALSE: Failure
1620  */
1621 BOOL WINAPI FlushViewOfFile(
1622               LPCVOID base, /* [in] Start address of byte range to flush */
1623               DWORD cbFlush /* [in] Number of bytes in range */
1624 ) {
1625     FILE_VIEW *view;
1626     UINT addr = ROUND_ADDR( base );
1627
1628     TRACE("FlushViewOfFile at %p for %ld bytes\n",
1629                      base, cbFlush );
1630
1631     if (!(view = VIRTUAL_FindView( addr )))
1632     {
1633         SetLastError( ERROR_INVALID_PARAMETER );
1634         return FALSE;
1635     }
1636     if (!cbFlush) cbFlush = view->size;
1637     if (!msync( (void *)addr, cbFlush, MS_SYNC )) return TRUE;
1638     SetLastError( ERROR_INVALID_PARAMETER );
1639     return FALSE;
1640 }
1641
1642
1643 /***********************************************************************
1644  *             UnmapViewOfFile   (KERNEL32.540)
1645  * Unmaps a mapped view of a file.
1646  *
1647  * NOTES
1648  *      Should addr be an LPCVOID?
1649  *
1650  * RETURNS
1651  *      TRUE: Success
1652  *      FALSE: Failure
1653  */
1654 BOOL WINAPI UnmapViewOfFile(
1655               LPVOID addr /* [in] Address where mapped view begins */
1656 ) {
1657     FILE_VIEW *view;
1658     UINT base = ROUND_ADDR( addr );
1659     if (!(view = VIRTUAL_FindView( base )) || (base != view->base))
1660     {
1661         SetLastError( ERROR_INVALID_PARAMETER );
1662         return FALSE;
1663     }
1664     VIRTUAL_DeleteView( view );
1665     return TRUE;
1666 }