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