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