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