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