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