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