Reimplement GetStringTypeA and GetStringTypeExA.
[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,
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     /* Check the type */
962
963     if (type & MEM_SYSTEM)
964     {
965         view->flags |= VFLAG_SYSTEM;
966         type &= ~MEM_SYSTEM;
967     }
968
969     if ((type != MEM_DECOMMIT) && (type != MEM_RELEASE))
970     {
971         ERR("called with wrong free type flags (%08lx) !\n", type);
972         SetLastError( ERROR_INVALID_PARAMETER );
973         return FALSE;
974     }
975
976     /* Free the pages */
977
978     if (type == MEM_RELEASE)
979     {
980         if (size || (base != view->base))
981         {
982             SetLastError( ERROR_INVALID_PARAMETER );
983             return FALSE;
984         }
985         VIRTUAL_DeleteView( view );
986         return TRUE;
987     }
988
989     /* Decommit the pages by remapping zero-pages instead */
990
991     if (wine_anon_mmap( (LPVOID)base, size, VIRTUAL_GetUnixProt(0), MAP_FIXED ) != (LPVOID)base)
992         ERR( "Could not remap pages, expect trouble\n" );
993     return VIRTUAL_SetProt( view, base, size, 0 );
994 }
995
996
997 /***********************************************************************
998  *             VirtualLock   (KERNEL32.@)
999  * Locks the specified region of virtual address space
1000  * 
1001  * NOTE
1002  *      Always returns TRUE
1003  *
1004  * RETURNS
1005  *      TRUE: Success
1006  *      FALSE: Failure
1007  */
1008 BOOL WINAPI VirtualLock(
1009               LPVOID addr, /* [in] Address of first byte of range to lock */
1010               DWORD size   /* [in] Number of bytes in range to lock */
1011 ) {
1012     return TRUE;
1013 }
1014
1015
1016 /***********************************************************************
1017  *             VirtualUnlock   (KERNEL32.@)
1018  * Unlocks a range of pages in the virtual address space
1019  *
1020  * NOTE
1021  *      Always returns TRUE
1022  *
1023  * RETURNS
1024  *      TRUE: Success
1025  *      FALSE: Failure
1026  */
1027 BOOL WINAPI VirtualUnlock(
1028               LPVOID addr, /* [in] Address of first byte of range */
1029               DWORD size   /* [in] Number of bytes in range */
1030 ) {
1031     return TRUE;
1032 }
1033
1034
1035 /***********************************************************************
1036  *             VirtualProtect   (KERNEL32.@)
1037  * Changes the access protection on a region of committed pages
1038  *
1039  * RETURNS
1040  *      TRUE: Success
1041  *      FALSE: Failure
1042  */
1043 BOOL WINAPI VirtualProtect(
1044               LPVOID addr,     /* [in] Address of region of committed pages */
1045               DWORD size,      /* [in] Size of region */
1046               DWORD new_prot,  /* [in] Desired access protection */
1047               LPDWORD old_prot /* [out] Address of variable to get old protection */
1048 ) {
1049     FILE_VIEW *view;
1050     char *base;
1051     UINT i;
1052     BYTE vprot, *p;
1053     DWORD prot;
1054
1055     TRACE("%p %08lx %08lx\n", addr, size, new_prot );
1056
1057     /* Fix the parameters */
1058
1059     size = ROUND_SIZE( addr, size );
1060     base = ROUND_ADDR( addr, page_mask );
1061
1062     if (!(view = VIRTUAL_FindView( base )) ||
1063         (base + size > (char *)view->base + view->size))
1064     {
1065         SetLastError( ERROR_INVALID_PARAMETER );
1066         return FALSE;
1067     }
1068
1069     /* Make sure all the pages are committed */
1070
1071     p = view->prot + ((base - (char *)view->base) >> page_shift);
1072     VIRTUAL_GetWin32Prot( *p, &prot, NULL );
1073     for (i = size >> page_shift; i; i--, p++)
1074     {
1075         if (!(*p & VPROT_COMMITTED))
1076         {
1077             SetLastError( ERROR_INVALID_PARAMETER );
1078             return FALSE;
1079         }
1080     }
1081
1082     if (old_prot) *old_prot = prot;
1083     vprot = VIRTUAL_GetProt( new_prot ) | VPROT_COMMITTED;
1084     return VIRTUAL_SetProt( view, base, size, vprot );
1085 }
1086
1087
1088 /***********************************************************************
1089  *             VirtualProtectEx   (KERNEL32.@)
1090  * Changes the access protection on a region of committed pages in the
1091  * virtual address space of a specified process
1092  *
1093  * RETURNS
1094  *      TRUE: Success
1095  *      FALSE: Failure
1096  */
1097 BOOL WINAPI VirtualProtectEx(
1098               HANDLE handle, /* [in]  Handle of process */
1099               LPVOID addr,     /* [in]  Address of region of committed pages */
1100               DWORD size,      /* [in]  Size of region */
1101               DWORD new_prot,  /* [in]  Desired access protection */
1102               LPDWORD old_prot /* [out] Address of variable to get old protection */ )
1103 {
1104     if (MapProcessHandle( handle ) == GetCurrentProcessId())
1105         return VirtualProtect( addr, size, new_prot, old_prot );
1106     ERR("Unsupported on other process\n");
1107     return FALSE;
1108 }
1109
1110
1111 /***********************************************************************
1112  *             VirtualQuery   (KERNEL32.@)
1113  * Provides info about a range of pages in virtual address space
1114  *
1115  * RETURNS
1116  *      Number of bytes returned in information buffer
1117  *      or 0 if addr is >= 0xc0000000 (kernel space).
1118  */
1119 DWORD WINAPI VirtualQuery(
1120              LPCVOID addr,                    /* [in]  Address of region */
1121              LPMEMORY_BASIC_INFORMATION info, /* [out] Address of info buffer */
1122              DWORD len                        /* [in]  Size of buffer */
1123 ) {
1124     FILE_VIEW *view;
1125     char *base, *alloc_base = 0;
1126     UINT size = 0;
1127
1128     if (addr >= (void*)0xc0000000) return 0;
1129
1130     base = ROUND_ADDR( addr, page_mask );
1131
1132     /* Find the view containing the address */
1133
1134     EnterCriticalSection(&csVirtual);
1135     view = VIRTUAL_FirstView;
1136     for (;;)
1137     {
1138         if (!view)
1139         {
1140             size = (char *)0xffff0000 - alloc_base;
1141             break;
1142         }
1143         if ((char *)view->base > base)
1144         {
1145             size = (char *)view->base - alloc_base;
1146             view = NULL;
1147             break;
1148         }
1149         if ((char *)view->base + view->size > base)
1150         {
1151             alloc_base = view->base;
1152             size = view->size;
1153             break;
1154         }
1155         alloc_base = (char *)view->base + view->size;
1156         view = view->next;
1157     }
1158     LeaveCriticalSection(&csVirtual);
1159
1160     /* Fill the info structure */
1161
1162     if (!view)
1163     {
1164         info->State             = MEM_FREE;
1165         info->Protect           = 0;
1166         info->AllocationProtect = 0;
1167         info->Type              = 0;
1168     }
1169     else
1170     {
1171         BYTE vprot = view->prot[(base - alloc_base) >> page_shift];
1172         VIRTUAL_GetWin32Prot( vprot, &info->Protect, &info->State );
1173         for (size = base - alloc_base; size < view->size; size += page_mask+1)
1174             if (view->prot[size >> page_shift] != vprot) break;
1175         info->AllocationProtect = view->protect;
1176         info->Type              = MEM_PRIVATE;  /* FIXME */
1177     }
1178
1179     info->BaseAddress    = (LPVOID)base;
1180     info->AllocationBase = (LPVOID)alloc_base;
1181     info->RegionSize     = size - (base - alloc_base);
1182     return sizeof(*info);
1183 }
1184
1185
1186 /***********************************************************************
1187  *             VirtualQueryEx   (KERNEL32.@)
1188  * Provides info about a range of pages in virtual address space of a
1189  * specified process
1190  *
1191  * RETURNS
1192  *      Number of bytes returned in information buffer
1193  */
1194 DWORD WINAPI VirtualQueryEx(
1195              HANDLE handle,                 /* [in] Handle of process */
1196              LPCVOID addr,                    /* [in] Address of region */
1197              LPMEMORY_BASIC_INFORMATION info, /* [out] Address of info buffer */
1198              DWORD len                        /* [in] Size of buffer */ )
1199 {
1200     if (MapProcessHandle( handle ) == GetCurrentProcessId())
1201         return VirtualQuery( addr, info, len );
1202     ERR("Unsupported on other process\n");
1203     return 0;
1204 }
1205
1206
1207 /***********************************************************************
1208  *             IsBadReadPtr   (KERNEL32.@)
1209  *
1210  * RETURNS
1211  *      FALSE: Process has read access to entire block
1212  *      TRUE: Otherwise
1213  */
1214 BOOL WINAPI IsBadReadPtr(
1215               LPCVOID ptr, /* [in] Address of memory block */
1216               UINT size )  /* [in] Size of block */
1217 {
1218     if (!size) return FALSE;  /* handle 0 size case w/o reference */
1219     __TRY
1220     {
1221         volatile const char *p = ptr;
1222         char dummy;
1223         UINT count = size;
1224
1225         while (count > page_size)
1226         {
1227             dummy = *p;
1228             p += page_size;
1229             count -= page_size;
1230         }
1231         dummy = p[0];
1232         dummy = p[count - 1];
1233     }
1234     __EXCEPT(page_fault) { return TRUE; }
1235     __ENDTRY
1236     return FALSE;
1237 }
1238
1239
1240 /***********************************************************************
1241  *             IsBadWritePtr   (KERNEL32.@)
1242  *
1243  * RETURNS
1244  *      FALSE: Process has write access to entire block
1245  *      TRUE: Otherwise
1246  */
1247 BOOL WINAPI IsBadWritePtr(
1248               LPVOID ptr, /* [in] Address of memory block */
1249               UINT size ) /* [in] Size of block in bytes */
1250 {
1251     if (!size) return FALSE;  /* handle 0 size case w/o reference */
1252     __TRY
1253     {
1254         volatile char *p = ptr;
1255         UINT count = size;
1256
1257         while (count > page_size)
1258         {
1259             *p |= 0;
1260             p += page_size;
1261             count -= page_size;
1262         }
1263         p[0] |= 0;
1264         p[count - 1] |= 0;
1265     }
1266     __EXCEPT(page_fault) { return TRUE; }
1267     __ENDTRY
1268     return FALSE;
1269 }
1270
1271
1272 /***********************************************************************
1273  *             IsBadHugeReadPtr   (KERNEL32.@)
1274  * RETURNS
1275  *      FALSE: Process has read access to entire block
1276  *      TRUE: Otherwise
1277  */
1278 BOOL WINAPI IsBadHugeReadPtr(
1279               LPCVOID ptr, /* [in] Address of memory block */
1280               UINT size  /* [in] Size of block */
1281 ) {
1282     return IsBadReadPtr( ptr, size );
1283 }
1284
1285
1286 /***********************************************************************
1287  *             IsBadHugeWritePtr   (KERNEL32.@)
1288  * RETURNS
1289  *      FALSE: Process has write access to entire block
1290  *      TRUE: Otherwise
1291  */
1292 BOOL WINAPI IsBadHugeWritePtr(
1293               LPVOID ptr, /* [in] Address of memory block */
1294               UINT size /* [in] Size of block */
1295 ) {
1296     return IsBadWritePtr( ptr, size );
1297 }
1298
1299
1300 /***********************************************************************
1301  *             IsBadCodePtr   (KERNEL32.@)
1302  *
1303  * RETURNS
1304  *      FALSE: Process has read access to specified memory
1305  *      TRUE: Otherwise
1306  */
1307 BOOL WINAPI IsBadCodePtr( FARPROC ptr ) /* [in] Address of function */
1308 {
1309     return IsBadReadPtr( ptr, 1 );
1310 }
1311
1312
1313 /***********************************************************************
1314  *             IsBadStringPtrA   (KERNEL32.@)
1315  *
1316  * RETURNS
1317  *      FALSE: Read access to all bytes in string
1318  *      TRUE: Else
1319  */
1320 BOOL WINAPI IsBadStringPtrA(
1321               LPCSTR str, /* [in] Address of string */
1322               UINT max )  /* [in] Maximum size of string */
1323 {
1324     __TRY
1325     {
1326         volatile const char *p = str;
1327         while (p != str + max) if (!*p++) break;
1328     }
1329     __EXCEPT(page_fault) { return TRUE; }
1330     __ENDTRY
1331     return FALSE;
1332 }
1333
1334
1335 /***********************************************************************
1336  *             IsBadStringPtrW   (KERNEL32.@)
1337  * See IsBadStringPtrA
1338  */
1339 BOOL WINAPI IsBadStringPtrW( LPCWSTR str, UINT max )
1340 {
1341     __TRY
1342     {
1343         volatile const WCHAR *p = str;
1344         while (p != str + max) if (!*p++) break;
1345     }
1346     __EXCEPT(page_fault) { return TRUE; }
1347     __ENDTRY
1348     return FALSE;
1349 }
1350
1351
1352 /***********************************************************************
1353  *             CreateFileMappingA   (KERNEL32.@)
1354  * Creates a named or unnamed file-mapping object for the specified file
1355  *
1356  * RETURNS
1357  *      Handle: Success
1358  *      0: Mapping object does not exist
1359  *      NULL: Failure
1360  */
1361 HANDLE WINAPI CreateFileMappingA(
1362                 HANDLE hFile,   /* [in] Handle of file to map */
1363                 SECURITY_ATTRIBUTES *sa, /* [in] Optional security attributes*/
1364                 DWORD protect,   /* [in] Protection for mapping object */
1365                 DWORD size_high, /* [in] High-order 32 bits of object size */
1366                 DWORD size_low,  /* [in] Low-order 32 bits of object size */
1367                 LPCSTR name      /* [in] Name of file-mapping object */ )
1368 {
1369     WCHAR buffer[MAX_PATH];
1370
1371     if (!name) return CreateFileMappingW( hFile, sa, protect, size_high, size_low, NULL );
1372
1373     if (!MultiByteToWideChar( CP_ACP, 0, name, -1, buffer, MAX_PATH ))
1374     {
1375         SetLastError( ERROR_FILENAME_EXCED_RANGE );
1376         return 0;
1377     }
1378     return CreateFileMappingW( hFile, sa, protect, size_high, size_low, buffer );
1379 }
1380
1381
1382 /***********************************************************************
1383  *             CreateFileMappingW   (KERNEL32.@)
1384  * See CreateFileMappingA
1385  */
1386 HANDLE WINAPI CreateFileMappingW( HANDLE hFile, LPSECURITY_ATTRIBUTES sa, 
1387                                   DWORD protect, DWORD size_high,  
1388                                   DWORD size_low, LPCWSTR name )
1389 {
1390     HANDLE ret;
1391     BYTE vprot;
1392     DWORD len = name ? strlenW(name) : 0;
1393
1394     /* Check parameters */
1395
1396     TRACE("(%x,%p,%08lx,%08lx%08lx,%s)\n",
1397           hFile, sa, protect, size_high, size_low, debugstr_w(name) );
1398
1399     if (len > MAX_PATH)
1400     {
1401         SetLastError( ERROR_FILENAME_EXCED_RANGE );
1402         return 0;
1403     }
1404
1405     vprot = VIRTUAL_GetProt( protect );
1406     if (protect & SEC_RESERVE)
1407     {
1408         if (hFile != INVALID_HANDLE_VALUE)
1409         {
1410             SetLastError( ERROR_INVALID_PARAMETER );
1411             return 0;
1412         }
1413     }
1414     else vprot |= VPROT_COMMITTED;
1415     if (protect & SEC_NOCACHE) vprot |= VPROT_NOCACHE;
1416     if (protect & SEC_IMAGE) vprot |= VPROT_IMAGE;
1417
1418     /* Create the server object */
1419
1420     if (hFile == INVALID_HANDLE_VALUE) hFile = 0;
1421     SERVER_START_REQ( create_mapping )
1422     {
1423         req->file_handle = hFile;
1424         req->size_high   = size_high;
1425         req->size_low    = size_low;
1426         req->protect     = vprot;
1427         req->inherit     = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
1428         wine_server_add_data( req, name, len * sizeof(WCHAR) );
1429         SetLastError(0);
1430         wine_server_call_err( req );
1431         ret = reply->handle;
1432     }
1433     SERVER_END_REQ;
1434     return ret;
1435 }
1436
1437
1438 /***********************************************************************
1439  *             OpenFileMappingA   (KERNEL32.@)
1440  * Opens a named file-mapping object.
1441  *
1442  * RETURNS
1443  *      Handle: Success
1444  *      NULL: Failure
1445  */
1446 HANDLE WINAPI OpenFileMappingA(
1447                 DWORD access,   /* [in] Access mode */
1448                 BOOL inherit, /* [in] Inherit flag */
1449                 LPCSTR name )   /* [in] Name of file-mapping object */
1450 {
1451     WCHAR buffer[MAX_PATH];
1452
1453     if (!name) return OpenFileMappingW( access, inherit, NULL );
1454
1455     if (!MultiByteToWideChar( CP_ACP, 0, name, -1, buffer, MAX_PATH ))
1456     {
1457         SetLastError( ERROR_FILENAME_EXCED_RANGE );
1458         return 0;
1459     }
1460     return OpenFileMappingW( access, inherit, buffer );
1461 }
1462
1463
1464 /***********************************************************************
1465  *             OpenFileMappingW   (KERNEL32.@)
1466  * See OpenFileMappingA
1467  */
1468 HANDLE WINAPI OpenFileMappingW( DWORD access, BOOL inherit, LPCWSTR name)
1469 {
1470     HANDLE ret;
1471     DWORD len = name ? strlenW(name) : 0;
1472     if (len >= MAX_PATH)
1473     {
1474         SetLastError( ERROR_FILENAME_EXCED_RANGE );
1475         return 0;
1476     }
1477     SERVER_START_REQ( open_mapping )
1478     {
1479         req->access  = access;
1480         req->inherit = inherit;
1481         wine_server_add_data( req, name, len * sizeof(WCHAR) );
1482         wine_server_call_err( req );
1483         ret = reply->handle;
1484     }
1485     SERVER_END_REQ;
1486     return ret;
1487 }
1488
1489
1490 /***********************************************************************
1491  *             MapViewOfFile   (KERNEL32.@)
1492  * Maps a view of a file into the address space
1493  *
1494  * RETURNS
1495  *      Starting address of mapped view
1496  *      NULL: Failure
1497  */
1498 LPVOID WINAPI MapViewOfFile(
1499               HANDLE mapping,  /* [in] File-mapping object to map */
1500               DWORD access,      /* [in] Access mode */
1501               DWORD offset_high, /* [in] High-order 32 bits of file offset */
1502               DWORD offset_low,  /* [in] Low-order 32 bits of file offset */
1503               DWORD count        /* [in] Number of bytes to map */
1504 ) {
1505     return MapViewOfFileEx( mapping, access, offset_high,
1506                             offset_low, count, NULL );
1507 }
1508
1509
1510 /***********************************************************************
1511  *             MapViewOfFileEx   (KERNEL32.@)
1512  * Maps a view of a file into the address space
1513  *
1514  * RETURNS
1515  *      Starting address of mapped view
1516  *      NULL: Failure
1517  */
1518 LPVOID WINAPI MapViewOfFileEx(
1519               HANDLE handle,   /* [in] File-mapping object to map */
1520               DWORD access,      /* [in] Access mode */
1521               DWORD offset_high, /* [in] High-order 32 bits of file offset */
1522               DWORD offset_low,  /* [in] Low-order 32 bits of file offset */
1523               DWORD count,       /* [in] Number of bytes to map */
1524               LPVOID addr        /* [in] Suggested starting address for mapped view */
1525 ) {
1526     FILE_VIEW *view;
1527     UINT size = 0;
1528     int flags = MAP_PRIVATE;
1529     int unix_handle = -1;
1530     int prot, res;
1531     void *base, *ptr = (void *)-1, *ret;
1532     DWORD size_low, size_high, header_size, shared_size;
1533     HANDLE shared_file;
1534     BOOL removable;
1535
1536     /* Check parameters */
1537
1538     if ((offset_low & granularity_mask) ||
1539         (addr && ((UINT_PTR)addr & granularity_mask)))
1540     {
1541         SetLastError( ERROR_INVALID_PARAMETER );
1542         return NULL;
1543     }
1544
1545     SERVER_START_REQ( get_mapping_info )
1546     {
1547         req->handle = handle;
1548         res = wine_server_call_err( req );
1549         prot        = reply->protect;
1550         base        = reply->base;
1551         size_low    = reply->size_low;
1552         size_high   = reply->size_high;
1553         header_size = reply->header_size;
1554         shared_file = reply->shared_file;
1555         shared_size = reply->shared_size;
1556         removable   = (reply->drive_type == DRIVE_REMOVABLE ||
1557                        reply->drive_type == DRIVE_CDROM);
1558     }
1559     SERVER_END_REQ;
1560     if (res) goto error;
1561
1562     if ((unix_handle = FILE_GetUnixHandle( handle, 0 )) == -1) goto error;
1563
1564     if (prot & VPROT_IMAGE)
1565         return map_image( handle, unix_handle, base, size_low, header_size,
1566                           shared_file, shared_size, removable );
1567
1568
1569     if (size_high)
1570         ERR("Sizes larger than 4Gb not supported\n");
1571
1572     if ((offset_low >= size_low) ||
1573         (count > size_low - offset_low))
1574     {
1575         SetLastError( ERROR_INVALID_PARAMETER );
1576         goto error;
1577     }
1578     if (count) size = ROUND_SIZE( offset_low, count );
1579     else size = size_low - offset_low;
1580
1581     switch(access)
1582     {
1583     case FILE_MAP_ALL_ACCESS:
1584     case FILE_MAP_WRITE:
1585     case FILE_MAP_WRITE | FILE_MAP_READ:
1586         if (!(prot & VPROT_WRITE))
1587         {
1588             SetLastError( ERROR_INVALID_PARAMETER );
1589             goto error;
1590         }
1591         flags = MAP_SHARED;
1592         /* fall through */
1593     case FILE_MAP_READ:
1594     case FILE_MAP_COPY:
1595     case FILE_MAP_COPY | FILE_MAP_READ:
1596         if (prot & VPROT_READ) break;
1597         /* fall through */
1598     default:
1599         SetLastError( ERROR_INVALID_PARAMETER );
1600         goto error;
1601     }
1602
1603     /* FIXME: If a mapping is created with SEC_RESERVE and a process,
1604      * which has a view of this mapping commits some pages, they will
1605      * appear commited in all other processes, which have the same
1606      * view created. Since we don`t support this yet, we create the
1607      * whole mapping commited.
1608      */
1609     prot |= VPROT_COMMITTED;
1610
1611     /* Reserve a properly aligned area */
1612
1613     if ((ptr = anon_mmap_aligned( addr, size, PROT_NONE, 0 )) == (void *)-1) goto error;
1614
1615     /* Map the file */
1616
1617     TRACE("handle=%x size=%x offset=%lx\n", handle, size, offset_low );
1618
1619     ret = VIRTUAL_mmap( unix_handle, ptr, size, offset_low, offset_high,
1620                         VIRTUAL_GetUnixProt( prot ), flags | MAP_FIXED, &removable );
1621     if (ret != ptr)
1622     {
1623         ERR( "VIRTUAL_mmap %p %x %lx%08lx failed\n", ptr, size, offset_high, offset_low );
1624         goto error;
1625     }
1626     if (removable) handle = 0;  /* don't keep handle open on removable media */
1627
1628     if (!(view = VIRTUAL_CreateView( ptr, size, 0, prot, handle )))
1629     {
1630         SetLastError( ERROR_OUTOFMEMORY );
1631         goto error;
1632     }
1633     if (unix_handle != -1) close( unix_handle );
1634     return ptr;
1635
1636 error:
1637     if (unix_handle != -1) close( unix_handle );
1638     if (ptr != (void *)-1) munmap( ptr, size );
1639     return NULL;
1640 }
1641
1642
1643 /***********************************************************************
1644  *             FlushViewOfFile   (KERNEL32.@)
1645  * Writes to the disk a byte range within a mapped view of a file
1646  *
1647  * RETURNS
1648  *      TRUE: Success
1649  *      FALSE: Failure
1650  */
1651 BOOL WINAPI FlushViewOfFile(
1652               LPCVOID base, /* [in] Start address of byte range to flush */
1653               DWORD cbFlush /* [in] Number of bytes in range */
1654 ) {
1655     FILE_VIEW *view;
1656     void *addr = ROUND_ADDR( base, page_mask );
1657
1658     TRACE("FlushViewOfFile at %p for %ld bytes\n",
1659                      base, cbFlush );
1660
1661     if (!(view = VIRTUAL_FindView( addr )))
1662     {
1663         SetLastError( ERROR_INVALID_PARAMETER );
1664         return FALSE;
1665     }
1666     if (!cbFlush) cbFlush = view->size;
1667     if (!msync( addr, cbFlush, MS_SYNC )) return TRUE;
1668     SetLastError( ERROR_INVALID_PARAMETER );
1669     return FALSE;
1670 }
1671
1672
1673 /***********************************************************************
1674  *             UnmapViewOfFile   (KERNEL32.@)
1675  * Unmaps a mapped view of a file.
1676  *
1677  * NOTES
1678  *      Should addr be an LPCVOID?
1679  *
1680  * RETURNS
1681  *      TRUE: Success
1682  *      FALSE: Failure
1683  */
1684 BOOL WINAPI UnmapViewOfFile(
1685               LPVOID addr /* [in] Address where mapped view begins */
1686 ) {
1687     FILE_VIEW *view;
1688     void *base = ROUND_ADDR( addr, page_mask );
1689     if (!(view = VIRTUAL_FindView( base )) || (base != view->base))
1690     {
1691         SetLastError( ERROR_INVALID_PARAMETER );
1692         return FALSE;
1693     }
1694     VIRTUAL_DeleteView( view );
1695     return TRUE;
1696 }