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