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