-Fixed MESSAGE functions that were thunking down to 16 bits implementation.
[wine] / memory / virtual.c
1 /*
2  * Win32 virtual memory functions
3  *
4  * Copyright 1997 Alexandre Julliard
5  */
6
7 #include <assert.h>
8 #include <errno.h>
9 #include <sys/errno.h>
10 #include <fcntl.h>
11 #include <unistd.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <sys/types.h>
15 #include <sys/mman.h>
16 #include "winbase.h"
17 #include "winerror.h"
18 #include "file.h"
19 #include "heap.h"
20 #include "process.h"
21 #include "xmalloc.h"
22 #include "global.h"
23 #include "server.h"
24 #include "debug.h"
25
26 #ifndef MS_SYNC
27 #define MS_SYNC 0
28 #endif
29
30 /* File mapping */
31 typedef struct
32 {
33     K32OBJ        header;
34     K32OBJ       *file;
35 } FILE_MAPPING;
36
37 /* File view */
38 typedef struct _FV
39 {
40     struct _FV   *next;        /* Next view */
41     struct _FV   *prev;        /* Prev view */
42     UINT32        base;        /* Base address */
43     UINT32        size;        /* Size in bytes */
44     UINT32        flags;       /* Allocation flags */
45     UINT32        offset;      /* Offset from start of mapped file */
46     HANDLE32      mapping;     /* Handle to the file mapping */
47     HANDLERPROC   handlerProc; /* Fault handler */
48     LPVOID        handlerArg;  /* Fault handler argument */
49     BYTE          protect;     /* Protection for all pages at allocation time */
50     BYTE          prot[1];     /* Protection byte for each page */
51 } FILE_VIEW;
52
53 /* Per-view flags */
54 #define VFLAG_SYSTEM     0x01
55
56 /* Conversion from VPROT_* to Win32 flags */
57 static const BYTE VIRTUAL_Win32Flags[16] =
58 {
59     PAGE_NOACCESS,              /* 0 */
60     PAGE_READONLY,              /* READ */
61     PAGE_READWRITE,             /* WRITE */
62     PAGE_READWRITE,             /* READ | WRITE */
63     PAGE_EXECUTE,               /* EXEC */
64     PAGE_EXECUTE_READ,          /* READ | EXEC */
65     PAGE_EXECUTE_READWRITE,     /* WRITE | EXEC */
66     PAGE_EXECUTE_READWRITE,     /* READ | WRITE | EXEC */
67     PAGE_WRITECOPY,             /* WRITECOPY */
68     PAGE_WRITECOPY,             /* READ | WRITECOPY */
69     PAGE_WRITECOPY,             /* WRITE | WRITECOPY */
70     PAGE_WRITECOPY,             /* READ | WRITE | WRITECOPY */
71     PAGE_EXECUTE_WRITECOPY,     /* EXEC | WRITECOPY */
72     PAGE_EXECUTE_WRITECOPY,     /* READ | EXEC | WRITECOPY */
73     PAGE_EXECUTE_WRITECOPY,     /* WRITE | EXEC | WRITECOPY */
74     PAGE_EXECUTE_WRITECOPY      /* READ | WRITE | EXEC | WRITECOPY */
75 };
76
77
78 static FILE_VIEW *VIRTUAL_FirstView;
79
80 #ifdef __i386__
81 /* These are always the same on an i386, and it will be faster this way */
82 # define page_mask  0xfff
83 # define page_shift 12
84 # define granularity_mask 0xffff
85 #else
86 static UINT32 page_shift;
87 static UINT32 page_mask;
88 static UINT32 granularity_mask;  /* Allocation granularity (usually 64k) */
89 #endif  /* __i386__ */
90
91 #define ROUND_ADDR(addr) \
92    ((UINT32)(addr) & ~page_mask)
93
94 #define ROUND_SIZE(addr,size) \
95    (((UINT32)(size) + ((UINT32)(addr) & page_mask) + page_mask) & ~page_mask)
96
97 static void VIRTUAL_DestroyMapping( K32OBJ *obj );
98
99 const K32OBJ_OPS MEM_MAPPED_FILE_Ops =
100 {
101     VIRTUAL_DestroyMapping     /* destroy */
102 };
103
104 #define VIRTUAL_DEBUG_DUMP_VIEW(view) \
105    if (!TRACE_ON(virtual)); else VIRTUAL_DumpView(view)
106
107 /***********************************************************************
108  *           VIRTUAL_GetProtStr
109  */
110 static const char *VIRTUAL_GetProtStr( BYTE prot )
111 {
112     static char buffer[6];
113     buffer[0] = (prot & VPROT_COMMITTED) ? 'c' : '-';
114     buffer[1] = (prot & VPROT_GUARD) ? 'g' : '-';
115     buffer[2] = (prot & VPROT_READ) ? 'r' : '-';
116     buffer[3] = (prot & VPROT_WRITE) ?
117                     ((prot & VPROT_WRITECOPY) ? 'w' : 'W') : '-';
118     buffer[4] = (prot & VPROT_EXEC) ? 'x' : '-';
119     buffer[5] = 0;
120     return buffer;
121 }
122
123
124 /***********************************************************************
125  *           VIRTUAL_DumpView
126  */
127 static void VIRTUAL_DumpView( FILE_VIEW *view )
128 {
129     UINT32 i, count;
130     UINT32 addr = view->base;
131     BYTE prot = view->prot[0];
132
133     DUMP( "View: %08x - %08x%s",
134           view->base, view->base + view->size - 1,
135           (view->flags & VFLAG_SYSTEM) ? " (system)" : "" );
136     if (view->mapping)
137         DUMP( " %d @ %08x\n", view->mapping, view->offset );
138     else
139         DUMP( " (anonymous)\n");
140
141     for (count = i = 1; i < view->size >> page_shift; i++, count++)
142     {
143         if (view->prot[i] == prot) continue;
144         DUMP( "      %08x - %08x %s\n",
145               addr, addr + (count << page_shift) - 1,
146               VIRTUAL_GetProtStr(prot) );
147         addr += (count << page_shift);
148         prot = view->prot[i];
149         count = 0;
150     }
151     if (count)
152         DUMP( "      %08x - %08x %s\n",
153               addr, addr + (count << page_shift) - 1,
154               VIRTUAL_GetProtStr(prot) );
155 }
156
157
158 /***********************************************************************
159  *           VIRTUAL_Dump
160  */
161 void VIRTUAL_Dump(void)
162 {
163     FILE_VIEW *view = VIRTUAL_FirstView;
164     DUMP( "\nDump of all virtual memory views:\n\n" );
165     while (view)
166     {
167         VIRTUAL_DumpView( view );
168         view = view->next;
169     }
170 }
171
172
173 /***********************************************************************
174  *           VIRTUAL_FindView
175  *
176  * Find the view containing a given address.
177  *
178  * RETURNS
179  *      View: Success
180  *      NULL: Failure
181  */
182 static FILE_VIEW *VIRTUAL_FindView(
183                   UINT32 addr /* [in] Address */
184 ) {
185     FILE_VIEW *view = VIRTUAL_FirstView;
186     while (view)
187     {
188         if (view->base > addr) return NULL;
189         if (view->base + view->size > addr) return view;
190         view = view->next;
191     }
192     return NULL;
193 }
194
195
196 /***********************************************************************
197  *           VIRTUAL_CreateView
198  *
199  * Create a new view and add it in the linked list.
200  */
201 static FILE_VIEW *VIRTUAL_CreateView( UINT32 base, UINT32 size, UINT32 offset,
202                                       UINT32 flags, BYTE vprot,
203                                       HANDLE32 mapping )
204 {
205     FILE_VIEW *view, *prev;
206
207     /* Create the view structure */
208
209     assert( !(base & page_mask) );
210     assert( !(size & page_mask) );
211     size >>= page_shift;
212     if (!(view = (FILE_VIEW *)malloc( sizeof(*view) + size - 1 ))) return NULL;
213     view->base    = base;
214     view->size    = size << page_shift;
215     view->flags   = flags;
216     view->offset  = offset;
217     view->mapping = mapping;
218     view->protect = vprot;
219     view->handlerProc = NULL;
220     memset( view->prot, vprot, size );
221
222     /* Duplicate the mapping handle */
223
224     if ((view->mapping != -1) &&
225         !DuplicateHandle( GetCurrentProcess(), view->mapping,
226                           GetCurrentProcess(), &view->mapping,
227                           0, FALSE, DUPLICATE_SAME_ACCESS ))
228     {
229         free( view );
230         return NULL;
231     }
232
233     /* Insert it in the linked list */
234
235     if (!VIRTUAL_FirstView || (VIRTUAL_FirstView->base > base))
236     {
237         view->next = VIRTUAL_FirstView;
238         view->prev = NULL;
239         if (view->next) view->next->prev = view;
240         VIRTUAL_FirstView = view;
241     }
242     else
243     {
244         prev = VIRTUAL_FirstView;
245         while (prev->next && (prev->next->base < base)) prev = prev->next;
246         view->next = prev->next;
247         view->prev = prev;
248         if (view->next) view->next->prev = view;
249         prev->next  = view;
250     }
251     VIRTUAL_DEBUG_DUMP_VIEW( view );
252     return view;
253 }
254
255
256 /***********************************************************************
257  *           VIRTUAL_DeleteView
258  * Deletes a view.
259  *
260  * RETURNS
261  *      None
262  */
263 static void VIRTUAL_DeleteView(
264             FILE_VIEW *view /* [in] View */
265 ) {
266     FILE_munmap( (void *)view->base, 0, view->size );
267     if (view->next) view->next->prev = view->prev;
268     if (view->prev) view->prev->next = view->next;
269     else VIRTUAL_FirstView = view->next;
270     if (view->mapping) CloseHandle( view->mapping );
271     free( view );
272 }
273
274
275 /***********************************************************************
276  *           VIRTUAL_GetUnixProt
277  *
278  * Convert page protections to protection for mmap/mprotect.
279  */
280 static int VIRTUAL_GetUnixProt( BYTE vprot )
281 {
282     int prot = 0;
283     if ((vprot & VPROT_COMMITTED) && !(vprot & VPROT_GUARD))
284     {
285         if (vprot & VPROT_READ) prot |= PROT_READ;
286         if (vprot & VPROT_WRITE) prot |= PROT_WRITE;
287         if (vprot & VPROT_EXEC) prot |= PROT_EXEC;
288     }
289     return prot;
290 }
291
292
293 /***********************************************************************
294  *           VIRTUAL_GetWin32Prot
295  *
296  * Convert page protections to Win32 flags.
297  *
298  * RETURNS
299  *      None
300  */
301 static void VIRTUAL_GetWin32Prot(
302             BYTE vprot,     /* [in] Page protection flags */
303             DWORD *protect, /* [out] Location to store Win32 protection flags */
304             DWORD *state    /* [out] Location to store mem state flag */
305 ) {
306     if (protect) {
307         *protect = VIRTUAL_Win32Flags[vprot & 0x0f];
308 /*      if (vprot & VPROT_GUARD) *protect |= PAGE_GUARD;*/
309         if (vprot & VPROT_NOCACHE) *protect |= PAGE_NOCACHE;
310
311         if (vprot & VPROT_GUARD) *protect = PAGE_NOACCESS;
312     }
313
314     if (state) *state = (vprot & VPROT_COMMITTED) ? MEM_COMMIT : MEM_RESERVE;
315 }
316
317
318 /***********************************************************************
319  *           VIRTUAL_GetProt
320  *
321  * Build page protections from Win32 flags.
322  *
323  * RETURNS
324  *      Value of page protection flags
325  */
326 static BYTE VIRTUAL_GetProt(
327             DWORD protect  /* [in] Win32 protection flags */
328 ) {
329     BYTE vprot;
330
331     switch(protect & 0xff)
332     {
333     case PAGE_READONLY:
334         vprot = VPROT_READ;
335         break;
336     case PAGE_READWRITE:
337         vprot = VPROT_READ | VPROT_WRITE;
338         break;
339     case PAGE_WRITECOPY:
340         vprot = VPROT_READ | VPROT_WRITE | VPROT_WRITECOPY;
341         break;
342     case PAGE_EXECUTE:
343         vprot = VPROT_EXEC;
344         break;
345     case PAGE_EXECUTE_READ:
346         vprot = VPROT_EXEC | VPROT_READ;
347         break;
348     case PAGE_EXECUTE_READWRITE:
349         vprot = VPROT_EXEC | VPROT_READ | VPROT_WRITE | VPROT_WRITECOPY;
350         break;
351     case PAGE_EXECUTE_WRITECOPY:
352         vprot = VPROT_EXEC | VPROT_READ | VPROT_WRITE;
353         break;
354     case PAGE_NOACCESS:
355     default:
356         vprot = 0;
357         break;
358     }
359     if (protect & PAGE_GUARD) vprot |= VPROT_GUARD;
360     if (protect & PAGE_NOCACHE) vprot |= VPROT_NOCACHE;
361     return vprot;
362 }
363
364
365 /***********************************************************************
366  *           VIRTUAL_SetProt
367  *
368  * Change the protection of a range of pages.
369  *
370  * RETURNS
371  *      TRUE: Success
372  *      FALSE: Failure
373  */
374 static BOOL32 VIRTUAL_SetProt(
375               FILE_VIEW *view, /* [in] Pointer to view */
376               UINT32 base,     /* [in] Starting address */
377               UINT32 size,     /* [in] Size in bytes */
378               BYTE vprot       /* [in] Protections to use */
379 ) {
380     TRACE(virtual, "%08x-%08x %s\n",
381                      base, base + size - 1, VIRTUAL_GetProtStr( vprot ) );
382
383     if (mprotect( (void *)base, size, VIRTUAL_GetUnixProt(vprot) ))
384         return FALSE;  /* FIXME: last error */
385
386     memset( view->prot + ((base - view->base) >> page_shift),
387             vprot, size >> page_shift );
388     VIRTUAL_DEBUG_DUMP_VIEW( view );
389     return TRUE;
390 }
391
392
393 /***********************************************************************
394  *             VIRTUAL_CheckFlags
395  *
396  * Check that all pages in a range have the given flags.
397  *
398  * RETURNS
399  *      TRUE: They do
400  *      FALSE: They do not
401  */
402 static BOOL32 VIRTUAL_CheckFlags(
403               UINT32 base, /* [in] Starting address */
404               UINT32 size, /* [in] Size in bytes */
405               BYTE flags   /* [in] Flags to check for */
406 ) {
407     FILE_VIEW *view;
408     UINT32 page;
409
410     if (!size) return TRUE;
411     if (!(view = VIRTUAL_FindView( base ))) return FALSE;
412     if (view->base + view->size < base + size) return FALSE;
413     page = (base - view->base) >> page_shift;
414     size = ROUND_SIZE( base, size ) >> page_shift;
415     while (size--) if ((view->prot[page++] & flags) != flags) return FALSE;
416     return TRUE;
417 }
418
419
420 /***********************************************************************
421  *           VIRTUAL_Init
422  */
423 BOOL32 VIRTUAL_Init(void)
424 {
425 #ifndef __i386__
426     DWORD page_size;
427
428 # ifdef HAVE_GETPAGESIZE
429     page_size = getpagesize();
430 # else
431 #  ifdef __svr4__
432     page_size = sysconf(_SC_PAGESIZE);
433 #  else
434 #   error Cannot get the page size on this platform
435 #  endif
436 # endif
437     page_mask = page_size - 1;
438     granularity_mask = 0xffff;  /* hard-coded for now */
439     /* Make sure we have a power of 2 */
440     assert( !(page_size & page_mask) );
441     page_shift = 0;
442     while ((1 << page_shift) != page_size) page_shift++;
443 #endif  /* !__i386__ */
444
445 #ifdef linux
446     {
447         /* Do not use stdio here since it may temporarily change the size
448          * of some segments (ie libc6 adds 0x1000 per open FILE)
449          */
450         int fd = open ("/proc/self/maps", O_RDONLY);
451         if (fd >= 0)
452         {
453             char buffer[512]; /* line might be rather long in 2.1 */
454
455             for (;;)
456             {
457                 int start, end, offset;
458                 char r, w, x, p;
459                 BYTE vprot = VPROT_COMMITTED;
460
461                 char * ptr = buffer;
462                 int count = sizeof(buffer);
463                 while (1 == read(fd, ptr, 1) && *ptr != '\n' && --count > 0)
464                     ptr++;
465
466                 if (*ptr != '\n') break;
467                 *ptr = '\0';
468
469                 sscanf( buffer, "%x-%x %c%c%c%c %x",
470                         &start, &end, &r, &w, &x, &p, &offset );
471                 if (r == 'r') vprot |= VPROT_READ;
472                 if (w == 'w') vprot |= VPROT_WRITE;
473                 if (x == 'x') vprot |= VPROT_EXEC;
474                 if (p == 'p') vprot |= VPROT_WRITECOPY;
475                 VIRTUAL_CreateView( start, end - start, 0,
476                                     VFLAG_SYSTEM, vprot, -1 );
477             }
478             close (fd);
479         }
480     }
481 #endif  /* linux */
482     return TRUE;
483 }
484
485
486 /***********************************************************************
487  *           VIRTUAL_GetPageSize
488  */
489 DWORD VIRTUAL_GetPageSize(void)
490 {
491     return 1 << page_shift;
492 }
493
494
495 /***********************************************************************
496  *           VIRTUAL_GetGranularity
497  */
498 DWORD VIRTUAL_GetGranularity(void)
499 {
500     return granularity_mask + 1;
501 }
502
503
504 /***********************************************************************
505  *           VIRTUAL_SetFaultHandler
506  */
507 BOOL32 VIRTUAL_SetFaultHandler( LPCVOID addr, HANDLERPROC proc, LPVOID arg )
508 {
509     FILE_VIEW *view;
510
511     if (!(view = VIRTUAL_FindView((UINT32)addr))) return FALSE;
512     view->handlerProc = proc;
513     view->handlerArg  = arg;
514     return TRUE;
515 }
516
517 /***********************************************************************
518  *           VIRTUAL_HandleFault
519  */
520 BOOL32 VIRTUAL_HandleFault( LPCVOID addr )
521 {
522     FILE_VIEW *view = VIRTUAL_FindView((UINT32)addr);
523
524     if (view && view->handlerProc)
525         return view->handlerProc(view->handlerArg, addr);
526     return FALSE;
527 }
528
529
530 /***********************************************************************
531  *             VirtualAlloc   (KERNEL32.548)
532  * Reserves or commits a region of pages in virtual address space
533  *
534  * RETURNS
535  *      Base address of allocated region of pages
536  *      NULL: Failure
537  */
538 LPVOID WINAPI VirtualAlloc(
539               LPVOID addr,  /* [in] Address of region to reserve or commit */
540               DWORD size,   /* [in] Size of region */
541               DWORD type,   /* [in] Type of allocation */
542               DWORD protect /* [in] Type of access protection */
543 ) {
544     FILE_VIEW *view;
545     UINT32 base, ptr, view_size;
546     BYTE vprot;
547
548     TRACE(virtual, "%08x %08lx %lx %08lx\n",
549                      (UINT32)addr, size, type, protect );
550
551     /* Round parameters to a page boundary */
552
553     if (size > 0x7fc00000)  /* 2Gb - 4Mb */
554     {
555         SetLastError( ERROR_OUTOFMEMORY );
556         return NULL;
557     }
558     if (addr)
559     {
560         if (type & MEM_RESERVE) /* Round down to 64k boundary */
561             base = ((UINT32)addr + granularity_mask) & ~granularity_mask;
562         else
563             base = ROUND_ADDR( addr );
564         size = (((UINT32)addr + size + page_mask) & ~page_mask) - base;
565         if (base + size < base)  /* Disallow wrap-around */
566         {
567             SetLastError( ERROR_INVALID_PARAMETER );
568             return NULL;
569         }
570     }
571     else
572     {
573         base = 0;
574         size = (size + page_mask) & ~page_mask;
575     }
576
577     if (type & MEM_TOP_DOWN) {
578         /* FIXME: MEM_TOP_DOWN allocates the largest possible address.
579          *        Is there _ANY_ way to do it with UNIX mmap()?
580          */
581         WARN(virtual,"MEM_TOP_DOWN ignored\n");
582         type &= ~MEM_TOP_DOWN;
583     }
584     /* Compute the protection flags */
585
586     if (!(type & (MEM_COMMIT | MEM_RESERVE)) ||
587         (type & ~(MEM_COMMIT | MEM_RESERVE)))
588     {
589         SetLastError( ERROR_INVALID_PARAMETER );
590         return NULL;
591     }
592     if (type & MEM_COMMIT)
593         vprot = VIRTUAL_GetProt( protect ) | VPROT_COMMITTED;
594     else vprot = 0;
595
596     /* Reserve the memory */
597
598     if ((type & MEM_RESERVE) || !base)
599     {
600         view_size = size + (base ? 0 : granularity_mask + 1);
601         ptr = (UINT32)FILE_dommap( -1, (LPVOID)base, 0, view_size, 0, 0,
602                                    VIRTUAL_GetUnixProt( vprot ), MAP_PRIVATE );
603         if (ptr == (UINT32)-1)
604         {
605             SetLastError( ERROR_OUTOFMEMORY );
606             return NULL;
607         }
608         if (!base)
609         {
610             /* Release the extra memory while keeping the range */
611             /* starting on a 64k boundary. */
612
613             if (ptr & granularity_mask)
614             {
615                 UINT32 extra = granularity_mask + 1 - (ptr & granularity_mask);
616                 FILE_munmap( (void *)ptr, 0, extra );
617                 ptr += extra;
618                 view_size -= extra;
619             }
620             if (view_size > size)
621                 FILE_munmap( (void *)(ptr + size), 0, view_size - size );
622         }
623         else if (ptr != base)
624         {
625             /* We couldn't get the address we wanted */
626             FILE_munmap( (void *)ptr, 0, view_size );
627             SetLastError( ERROR_INVALID_ADDRESS );
628             return NULL;
629         }
630         if (!(view = VIRTUAL_CreateView( ptr, size, 0, 0, vprot, -1 )))
631         {
632             FILE_munmap( (void *)ptr, 0, size );
633             SetLastError( ERROR_OUTOFMEMORY );
634             return NULL;
635         }
636         VIRTUAL_DEBUG_DUMP_VIEW( view );
637         return (LPVOID)ptr;
638     }
639
640     /* Commit the pages */
641
642     if (!(view = VIRTUAL_FindView( base )) ||
643         (base + size > view->base + view->size))
644     {
645         SetLastError( ERROR_INVALID_PARAMETER );
646         return NULL;
647     }
648
649     if (!VIRTUAL_SetProt( view, base, size, vprot )) return NULL;
650     return (LPVOID)base;
651 }
652
653
654 /***********************************************************************
655  *             VirtualFree   (KERNEL32.550)
656  * Release or decommits a region of pages in virtual address space.
657  * 
658  * RETURNS
659  *      TRUE: Success
660  *      FALSE: Failure
661  */
662 BOOL32 WINAPI VirtualFree(
663               LPVOID addr, /* [in] Address of region of committed pages */
664               DWORD size,  /* [in] Size of region */
665               DWORD type   /* [in] Type of operation */
666 ) {
667     FILE_VIEW *view;
668     UINT32 base;
669
670     TRACE(virtual, "%08x %08lx %lx\n",
671                      (UINT32)addr, size, type );
672
673     /* Fix the parameters */
674
675     size = ROUND_SIZE( addr, size );
676     base = ROUND_ADDR( addr );
677
678     if (!(view = VIRTUAL_FindView( base )) ||
679         (base + size > view->base + view->size))
680     {
681         SetLastError( ERROR_INVALID_PARAMETER );
682         return FALSE;
683     }
684
685     /* Compute the protection flags */
686
687     if ((type != MEM_DECOMMIT) && (type != MEM_RELEASE))
688     {
689         SetLastError( ERROR_INVALID_PARAMETER );
690         return FALSE;
691     }
692
693     /* Free the pages */
694
695     if (type == MEM_RELEASE)
696     {
697         if (size || (base != view->base))
698         {
699             SetLastError( ERROR_INVALID_PARAMETER );
700             return FALSE;
701         }
702         VIRTUAL_DeleteView( view );
703         return TRUE;
704     }
705
706     /* Decommit the pages */
707     return VIRTUAL_SetProt( view, base, size, 0 );
708 }
709
710
711 /***********************************************************************
712  *             VirtualLock   (KERNEL32.551)
713  * Locks the specified region of virtual address space
714  * 
715  * NOTE
716  *      Always returns TRUE
717  *
718  * RETURNS
719  *      TRUE: Success
720  *      FALSE: Failure
721  */
722 BOOL32 WINAPI VirtualLock(
723               LPVOID addr, /* [in] Address of first byte of range to lock */
724               DWORD size   /* [in] Number of bytes in range to lock */
725 ) {
726     return TRUE;
727 }
728
729
730 /***********************************************************************
731  *             VirtualUnlock   (KERNEL32.556)
732  * Unlocks a range of pages in the virtual address space
733  *
734  * NOTE
735  *      Always returns TRUE
736  *
737  * RETURNS
738  *      TRUE: Success
739  *      FALSE: Failure
740  */
741 BOOL32 WINAPI VirtualUnlock(
742               LPVOID addr, /* [in] Address of first byte of range */
743               DWORD size   /* [in] Number of bytes in range */
744 ) {
745     return TRUE;
746 }
747
748
749 /***********************************************************************
750  *             VirtualProtect   (KERNEL32.552)
751  * Changes the access protection on a region of committed pages
752  *
753  * RETURNS
754  *      TRUE: Success
755  *      FALSE: Failure
756  */
757 BOOL32 WINAPI VirtualProtect(
758               LPVOID addr,     /* [in] Address of region of committed pages */
759               DWORD size,      /* [in] Size of region */
760               DWORD new_prot,  /* [in] Desired access protection */
761               LPDWORD old_prot /* [out] Address of variable to get old protection */
762 ) {
763     FILE_VIEW *view;
764     UINT32 base, i;
765     BYTE vprot, *p;
766
767     TRACE(virtual, "%08x %08lx %08lx\n",
768                      (UINT32)addr, size, new_prot );
769
770     /* Fix the parameters */
771
772     size = ROUND_SIZE( addr, size );
773     base = ROUND_ADDR( addr );
774
775     if (!(view = VIRTUAL_FindView( base )) ||
776         (base + size > view->base + view->size))
777     {
778         SetLastError( ERROR_INVALID_PARAMETER );
779         return FALSE;
780     }
781
782     /* Make sure all the pages are committed */
783
784     p = view->prot + ((base - view->base) >> page_shift);
785     for (i = size >> page_shift; i; i--, p++)
786     {
787         if (!(*p & VPROT_COMMITTED))
788         {
789             SetLastError( ERROR_INVALID_PARAMETER );
790             return FALSE;
791         }
792     }
793
794     VIRTUAL_GetWin32Prot( view->prot[0], old_prot, NULL );
795     vprot = VIRTUAL_GetProt( new_prot ) | VPROT_COMMITTED;
796     return VIRTUAL_SetProt( view, base, size, vprot );
797 }
798
799
800 /***********************************************************************
801  *             VirtualProtectEx   (KERNEL32.553)
802  * Changes the access protection on a region of committed pages in the
803  * virtual address space of a specified process
804  *
805  * RETURNS
806  *      TRUE: Success
807  *      FALSE: Failure
808  */
809 BOOL32 WINAPI VirtualProtectEx(
810               HANDLE32 handle, /* [in]  Handle of process */
811               LPVOID addr,     /* [in]  Address of region of committed pages */
812               DWORD size,      /* [in]  Size of region */
813               DWORD new_prot,  /* [in]  Desired access protection */
814               LPDWORD old_prot /* [out] Address of variable to get old protection */ )
815 {
816     if (PROCESS_IsCurrent( handle ))
817         return VirtualProtect( addr, size, new_prot, old_prot );
818     ERR(virtual,"Unsupported on other process\n");
819     return FALSE;
820 }
821
822
823 /***********************************************************************
824  *             VirtualQuery   (KERNEL32.554)
825  * Provides info about a range of pages in virtual address space
826  *
827  * RETURNS
828  *      Number of bytes returned in information buffer
829  */
830 DWORD WINAPI VirtualQuery(
831              LPCVOID addr,                    /* [in]  Address of region */
832              LPMEMORY_BASIC_INFORMATION info, /* [out] Address of info buffer */
833              DWORD len                        /* [in]  Size of buffer */
834 ) {
835     FILE_VIEW *view = VIRTUAL_FirstView;
836     UINT32 base = ROUND_ADDR( addr );
837     UINT32 alloc_base = 0;
838     UINT32 size = 0;
839
840     /* Find the view containing the address */
841
842     for (;;)
843     {
844         if (!view)
845         {
846             size = 0xffff0000 - alloc_base;
847             break;
848         }
849         if (view->base > base)
850         {
851             size = view->base - alloc_base;
852             view = NULL;
853             break;
854         }
855         if (view->base + view->size > base)
856         {
857             alloc_base = view->base;
858             size = view->size;
859             break;
860         }
861         alloc_base = view->base + view->size;
862         view = view->next;
863     }
864
865     /* Fill the info structure */
866
867     if (!view)
868     {
869         info->State             = MEM_FREE;
870         info->Protect           = 0;
871         info->AllocationProtect = 0;
872         info->Type              = 0;
873     }
874     else
875     {
876         BYTE vprot = view->prot[(base - alloc_base) >> page_shift];
877         VIRTUAL_GetWin32Prot( vprot, &info->Protect, &info->State );
878         for (size = base - alloc_base; size < view->size; size += page_mask+1)
879             if (view->prot[size >> page_shift] != vprot) break;
880         info->AllocationProtect = view->protect;
881         info->Type              = MEM_PRIVATE;  /* FIXME */
882     }
883
884     info->BaseAddress    = (LPVOID)base;
885     info->AllocationBase = (LPVOID)alloc_base;
886     info->RegionSize     = size - (base - alloc_base);
887     return sizeof(*info);
888 }
889
890
891 /***********************************************************************
892  *             VirtualQueryEx   (KERNEL32.555)
893  * Provides info about a range of pages in virtual address space of a
894  * specified process
895  *
896  * RETURNS
897  *      Number of bytes returned in information buffer
898  */
899 DWORD WINAPI VirtualQueryEx(
900              HANDLE32 handle,                 /* [in] Handle of process */
901              LPCVOID addr,                    /* [in] Address of region */
902              LPMEMORY_BASIC_INFORMATION info, /* [out] Address of info buffer */
903              DWORD len                        /* [in] Size of buffer */ )
904 {
905     if (PROCESS_IsCurrent( handle ))
906         return VirtualQuery( addr, info, len );
907     ERR(virtual,"Unsupported on other process\n");
908     return 0;
909 }
910
911
912 /***********************************************************************
913  *             IsBadReadPtr32   (KERNEL32.354)
914  *
915  * RETURNS
916  *      FALSE: Process has read access to entire block
917  *      TRUE: Otherwise
918  */
919 BOOL32 WINAPI IsBadReadPtr32(
920               LPCVOID ptr, /* Address of memory block */
921               UINT32 size  /* Size of block */
922 ) {
923     return !VIRTUAL_CheckFlags( (UINT32)ptr, size,
924                                 VPROT_READ | VPROT_COMMITTED );
925 }
926
927
928 /***********************************************************************
929  *             IsBadWritePtr32   (KERNEL32.357)
930  *
931  * RETURNS
932  *      FALSE: Process has write access to entire block
933  *      TRUE: Otherwise
934  */
935 BOOL32 WINAPI IsBadWritePtr32(
936               LPVOID ptr, /* [in] Address of memory block */
937               UINT32 size /* [in] Size of block in bytes */
938 ) {
939     return !VIRTUAL_CheckFlags( (UINT32)ptr, size,
940                                 VPROT_WRITE | VPROT_COMMITTED );
941 }
942
943
944 /***********************************************************************
945  *             IsBadHugeReadPtr32   (KERNEL32.352)
946  * RETURNS
947  *      FALSE: Process has read access to entire block
948  *      TRUE: Otherwise
949  */
950 BOOL32 WINAPI IsBadHugeReadPtr32(
951               LPCVOID ptr, /* [in] Address of memory block */
952               UINT32 size  /* [in] Size of block */
953 ) {
954     return IsBadReadPtr32( ptr, size );
955 }
956
957
958 /***********************************************************************
959  *             IsBadHugeWritePtr32   (KERNEL32.353)
960  * RETURNS
961  *      FALSE: Process has write access to entire block
962  *      TRUE: Otherwise
963  */
964 BOOL32 WINAPI IsBadHugeWritePtr32(
965               LPVOID ptr, /* [in] Address of memory block */
966               UINT32 size /* [in] Size of block */
967 ) {
968     return IsBadWritePtr32( ptr, size );
969 }
970
971
972 /***********************************************************************
973  *             IsBadCodePtr32   (KERNEL32.351)
974  *
975  * RETURNS
976  *      FALSE: Process has read access to specified memory
977  *      TRUE: Otherwise
978  */
979 BOOL32 WINAPI IsBadCodePtr32(
980               FARPROC32 ptr /* [in] Address of function */
981 ) {
982     return !VIRTUAL_CheckFlags( (UINT32)ptr, 1, VPROT_EXEC | VPROT_COMMITTED );
983 }
984
985
986 /***********************************************************************
987  *             IsBadStringPtr32A   (KERNEL32.355)
988  *
989  * RETURNS
990  *      FALSE: Read access to all bytes in string
991  *      TRUE: Else
992  */
993 BOOL32 WINAPI IsBadStringPtr32A(
994               LPCSTR str, /* [in] Address of string */
995               UINT32 max  /* [in] Maximum size of string */
996 ) {
997     FILE_VIEW *view;
998     UINT32 page, count;
999
1000     if (!max) return FALSE;
1001     if (!(view = VIRTUAL_FindView( (UINT32)str ))) return TRUE;
1002     page  = ((UINT32)str - view->base) >> page_shift;
1003     count = page_mask + 1 - ((UINT32)str & page_mask);
1004
1005     while (max)
1006     {
1007         if ((view->prot[page] & (VPROT_READ | VPROT_COMMITTED)) != 
1008                                                 (VPROT_READ | VPROT_COMMITTED))
1009             return TRUE;
1010         if (count > max) count = max;
1011         max -= count;
1012         while (count--) if (!*str++) return FALSE;
1013         if (++page >= view->size >> page_shift) return TRUE;
1014         count = page_mask + 1;
1015     }
1016     return FALSE;
1017 }
1018
1019
1020 /***********************************************************************
1021  *             IsBadStringPtr32W   (KERNEL32.356)
1022  * See IsBadStringPtr32A
1023  */
1024 BOOL32 WINAPI IsBadStringPtr32W( LPCWSTR str, UINT32 max )
1025 {
1026     FILE_VIEW *view;
1027     UINT32 page, count;
1028
1029     if (!max) return FALSE;
1030     if (!(view = VIRTUAL_FindView( (UINT32)str ))) return TRUE;
1031     page  = ((UINT32)str - view->base) >> page_shift;
1032     count = (page_mask + 1 - ((UINT32)str & page_mask)) / sizeof(WCHAR);
1033
1034     while (max)
1035     {
1036         if ((view->prot[page] & (VPROT_READ | VPROT_COMMITTED)) != 
1037                                                 (VPROT_READ | VPROT_COMMITTED))
1038             return TRUE;
1039         if (count > max) count = max;
1040         max -= count;
1041         while (count--) if (!*str++) return FALSE;
1042         if (++page >= view->size >> page_shift) return TRUE;
1043         count = (page_mask + 1) / sizeof(WCHAR);
1044     }
1045     return FALSE;
1046 }
1047
1048
1049 /***********************************************************************
1050  *             CreateFileMapping32A   (KERNEL32.46)
1051  * Creates a named or unnamed file-mapping object for the specified file
1052  *
1053  * RETURNS
1054  *      Handle: Success
1055  *      0: Mapping object does not exist
1056  *      NULL: Failure
1057  */
1058 HANDLE32 WINAPI CreateFileMapping32A(
1059                 HFILE32 hFile,   /* [in] Handle of file to map */
1060                 SECURITY_ATTRIBUTES *sa, /* [in] Optional security attributes*/
1061                 DWORD protect,   /* [in] Protection for mapping object */
1062                 DWORD size_high, /* [in] High-order 32 bits of object size */
1063                 DWORD size_low,  /* [in] Low-order 32 bits of object size */
1064                 LPCSTR name      /* [in] Name of file-mapping object */ )
1065 {
1066     FILE_MAPPING *mapping = NULL;
1067     K32OBJ *file;
1068     struct create_mapping_request req;
1069     struct create_mapping_reply reply = { -1 };
1070     HANDLE32 handle;
1071     BYTE vprot;
1072     BOOL32 inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
1073
1074     /* First search for an object with the same name */
1075
1076     K32OBJ *obj = K32OBJ_FindName( name );
1077
1078     if (obj)
1079     {
1080         if (obj->type == K32OBJ_MEM_MAPPED_FILE)
1081         {
1082             req.handle = -1;
1083             CLIENT_SendRequest( REQ_CREATE_MAPPING, -1, 2,
1084                                 &req, sizeof(req),
1085                                 name, name ? strlen(name) + 1 : 0 );
1086             CLIENT_WaitSimpleReply( &reply, sizeof(reply), NULL );
1087             if (reply.handle == -1) return 0;
1088             if (GetLastError() != ERROR_ALREADY_EXISTS)
1089                 return 0;  /* not supposed to happen */
1090             handle = HANDLE_Alloc( PROCESS_Current(), obj,
1091                                    FILE_MAP_ALL_ACCESS /*FIXME*/, inherit, reply.handle );
1092         }
1093         else
1094         {
1095             SetLastError( ERROR_DUP_NAME );
1096             handle = 0;
1097         }
1098         K32OBJ_DecCount( obj );
1099         return handle;
1100     }
1101
1102     /* Check parameters */
1103
1104     TRACE(virtual,"(%x,%p,%08lx,%08lx%08lx,%s)\n",
1105           hFile, sa, protect, size_high, size_low, debugstr_a(name) );
1106
1107     vprot = VIRTUAL_GetProt( protect );
1108     if (protect & SEC_RESERVE)
1109     {
1110         if (hFile != INVALID_HANDLE_VALUE32)
1111         {
1112             SetLastError( ERROR_INVALID_PARAMETER );
1113             return 0;
1114         }
1115     }
1116     else vprot |= VPROT_COMMITTED;
1117     if (protect & SEC_NOCACHE) vprot |= VPROT_NOCACHE;
1118
1119     /* Compute the size and extend the file if necessary */
1120
1121     if (hFile == INVALID_HANDLE_VALUE32)
1122     {
1123         if (!size_high && !size_low)
1124         {
1125             SetLastError( ERROR_INVALID_PARAMETER );
1126             return 0;
1127         }
1128         file = NULL;
1129         if (name)
1130         {
1131             CHAR        buf[260];
1132
1133             GetTempPath32A(260,buf);
1134             GetTempFileName32A(buf,"wine",0,buf);
1135             hFile = CreateFile32A(
1136                 buf,
1137                 GENERIC_READ|GENERIC_WRITE,
1138                 FILE_SHARE_READ|FILE_SHARE_WRITE,/* so we can reuse the tmpfn */
1139                 NULL,
1140                 OPEN_ALWAYS,
1141                 0,
1142                 0
1143             );
1144             /* FIXME: bad hack to avoid lots of leftover tempfiles */
1145             DeleteFile32A(buf); 
1146             if (hFile == INVALID_HANDLE_VALUE32)
1147                 FIXME(virtual,"could not create temp. file for anon shared mapping: reason was 0x%08lx\n",GetLastError());
1148         }
1149     }
1150     if (hFile != INVALID_HANDLE_VALUE32) /* We have a file */
1151     {
1152         BY_HANDLE_FILE_INFORMATION info;
1153         DWORD access = GENERIC_READ;
1154
1155         if (((protect & 0xff) == PAGE_READWRITE) ||
1156             ((protect & 0xff) == PAGE_WRITECOPY) ||
1157             ((protect & 0xff) == PAGE_EXECUTE_READWRITE) ||
1158             ((protect & 0xff) == PAGE_EXECUTE_WRITECOPY))
1159                 access |= GENERIC_WRITE;
1160
1161         if (!(file = HANDLE_GetObjPtr( PROCESS_Current(), hFile, K32OBJ_FILE,
1162                                        access, &req.handle ))) goto error;
1163         if (!GetFileInformationByHandle( hFile, &info )) goto error;
1164         if (!size_high && !size_low)
1165         {
1166             size_high = info.nFileSizeHigh;
1167             size_low  = info.nFileSizeLow;
1168         }
1169         else if ((size_high > info.nFileSizeHigh) ||
1170                  ((size_high == info.nFileSizeHigh) &&
1171                   (size_low > info.nFileSizeLow)))
1172         {
1173             /* We have to grow the file */
1174             if (SetFilePointer( hFile, size_low, &size_high,
1175                                 FILE_BEGIN ) == 0xffffffff) goto error;
1176             if (!SetEndOfFile( hFile )) goto error;
1177         }
1178     }
1179     else req.handle = -1;
1180
1181     /* Create the server object */
1182
1183     req.size_high = size_high;
1184     req.size_low  = ROUND_SIZE( 0, size_low );
1185     req.protect   = vprot;
1186     CLIENT_SendRequest( REQ_CREATE_MAPPING, -1, 2,
1187                         &req, sizeof(req),
1188                         name, name ? strlen(name) + 1 : 0 );
1189     if (CLIENT_WaitSimpleReply( &reply, sizeof(reply), NULL ))
1190         goto error;
1191
1192     /* Allocate the mapping object */
1193
1194     if (!(mapping = HeapAlloc( SystemHeap, 0, sizeof(*mapping) ))) goto error;
1195     mapping->header.type     = K32OBJ_MEM_MAPPED_FILE;
1196     mapping->header.refcount = 1;
1197     mapping->file            = file;
1198
1199     if (!K32OBJ_AddName( &mapping->header, name )) handle = 0;
1200     else handle = HANDLE_Alloc( PROCESS_Current(), &mapping->header,
1201                                 FILE_MAP_ALL_ACCESS /*FIXME*/, inherit, reply.handle );
1202     K32OBJ_DecCount( &mapping->header );
1203     SetLastError(0); /* Last error value is relevant. (see the start of fun) */
1204     return handle;
1205
1206 error:
1207     if (reply.handle != -1) CLIENT_CloseHandle( reply.handle );
1208     if (file) K32OBJ_DecCount( file );
1209     if (mapping) HeapFree( SystemHeap, 0, mapping );
1210     return 0;
1211 }
1212
1213
1214 /***********************************************************************
1215  *             CreateFileMapping32W   (KERNEL32.47)
1216  * See CreateFileMapping32A
1217  */
1218 HANDLE32 WINAPI CreateFileMapping32W( HFILE32 hFile, LPSECURITY_ATTRIBUTES attr, 
1219                                       DWORD protect, DWORD size_high,  
1220                                       DWORD size_low, LPCWSTR name )
1221 {
1222     LPSTR nameA = HEAP_strdupWtoA( GetProcessHeap(), 0, name );
1223     HANDLE32 ret = CreateFileMapping32A( hFile, attr, protect,
1224                                          size_high, size_low, nameA );
1225     HeapFree( GetProcessHeap(), 0, nameA );
1226     return ret;
1227 }
1228
1229
1230 /***********************************************************************
1231  *             OpenFileMapping32A   (KERNEL32.397)
1232  * Opens a named file-mapping object.
1233  *
1234  * RETURNS
1235  *      Handle: Success
1236  *      NULL: Failure
1237  */
1238 HANDLE32 WINAPI OpenFileMapping32A(
1239                 DWORD access,   /* [in] Access mode */
1240                 BOOL32 inherit, /* [in] Inherit flag */
1241                 LPCSTR name )   /* [in] Name of file-mapping object */
1242 {
1243     HANDLE32 handle = 0;
1244     K32OBJ *obj;
1245     struct open_named_obj_request req;
1246     struct open_named_obj_reply reply;
1247     int len = name ? strlen(name) + 1 : 0;
1248
1249     req.type    = OPEN_MAPPING;
1250     req.access  = access;
1251     req.inherit = inherit;
1252     CLIENT_SendRequest( REQ_OPEN_NAMED_OBJ, -1, 2, &req, sizeof(req), name, len );
1253     CLIENT_WaitSimpleReply( &reply, sizeof(reply), NULL );
1254
1255     if (reply.handle != -1)
1256     {
1257         SYSTEM_LOCK();
1258         if ((obj = K32OBJ_FindNameType( name, K32OBJ_MEM_MAPPED_FILE )))
1259         {
1260             handle = HANDLE_Alloc( PROCESS_Current(), obj, access, inherit, reply.handle );
1261             K32OBJ_DecCount( obj );
1262             if (handle == INVALID_HANDLE_VALUE32)
1263                 handle = 0; /* must return 0 on failure, not -1 */
1264         }
1265         else CLIENT_CloseHandle( reply.handle );
1266         SYSTEM_UNLOCK();
1267     }
1268     return handle;
1269 }
1270
1271
1272 /***********************************************************************
1273  *             OpenFileMapping32W   (KERNEL32.398)
1274  * See OpenFileMapping32A
1275  */
1276 HANDLE32 WINAPI OpenFileMapping32W( DWORD access, BOOL32 inherit, LPCWSTR name)
1277 {
1278     LPSTR nameA = HEAP_strdupWtoA( GetProcessHeap(), 0, name );
1279     HANDLE32 ret = OpenFileMapping32A( access, inherit, nameA );
1280     HeapFree( GetProcessHeap(), 0, nameA );
1281     return ret;
1282 }
1283
1284
1285 /***********************************************************************
1286  *           VIRTUAL_DestroyMapping
1287  *
1288  * Destroy a FILE_MAPPING object.
1289  */
1290 static void VIRTUAL_DestroyMapping( K32OBJ *ptr )
1291 {
1292     FILE_MAPPING *mapping = (FILE_MAPPING *)ptr;
1293     assert( ptr->type == K32OBJ_MEM_MAPPED_FILE );
1294
1295     if (mapping->file) K32OBJ_DecCount( mapping->file );
1296     ptr->type = K32OBJ_UNKNOWN;
1297     HeapFree( SystemHeap, 0, mapping );
1298 }
1299
1300
1301 /***********************************************************************
1302  *             MapViewOfFile   (KERNEL32.385)
1303  * Maps a view of a file into the address space
1304  *
1305  * RETURNS
1306  *      Starting address of mapped view
1307  *      NULL: Failure
1308  */
1309 LPVOID WINAPI MapViewOfFile(
1310               HANDLE32 mapping,  /* [in] File-mapping object to map */
1311               DWORD access,      /* [in] Access mode */
1312               DWORD offset_high, /* [in] High-order 32 bits of file offset */
1313               DWORD offset_low,  /* [in] Low-order 32 bits of file offset */
1314               DWORD count        /* [in] Number of bytes to map */
1315 ) {
1316     return MapViewOfFileEx( mapping, access, offset_high,
1317                             offset_low, count, NULL );
1318 }
1319
1320
1321 /***********************************************************************
1322  *             MapViewOfFileEx   (KERNEL32.386)
1323  * Maps a view of a file into the address space
1324  *
1325  * RETURNS
1326  *      Starting address of mapped view
1327  *      NULL: Failure
1328  */
1329 LPVOID WINAPI MapViewOfFileEx(
1330               HANDLE32 handle,   /* [in] File-mapping object to map */
1331               DWORD access,      /* [in] Access mode */
1332               DWORD offset_high, /* [in] High-order 32 bits of file offset */
1333               DWORD offset_low,  /* [in] Low-order 32 bits of file offset */
1334               DWORD count,       /* [in] Number of bytes to map */
1335               LPVOID addr        /* [in] Suggested starting address for mapped view */
1336 ) {
1337     FILE_VIEW *view;
1338     UINT32 ptr = (UINT32)-1, size = 0;
1339     int flags = MAP_PRIVATE;
1340     int unix_handle = -1;
1341     struct get_mapping_info_request req;
1342     struct get_mapping_info_reply info;
1343
1344     /* Check parameters */
1345
1346     if ((offset_low & granularity_mask) ||
1347         (addr && ((UINT32)addr & granularity_mask)))
1348     {
1349         SetLastError( ERROR_INVALID_PARAMETER );
1350         return NULL;
1351     }
1352
1353     req.handle = HANDLE_GetServerHandle( PROCESS_Current(), handle,
1354                                          K32OBJ_MEM_MAPPED_FILE, 0 /* FIXME */ );
1355     CLIENT_SendRequest( REQ_GET_MAPPING_INFO, -1, 1, &req, sizeof(req) );
1356     if (CLIENT_WaitSimpleReply( &info, sizeof(info), &unix_handle ))
1357         goto error;
1358
1359     if (info.size_high || offset_high)
1360         ERR(virtual, "Offsets larger than 4Gb not supported\n");
1361
1362     if ((offset_low >= info.size_low) ||
1363         (count > info.size_low - offset_low))
1364     {
1365         SetLastError( ERROR_INVALID_PARAMETER );
1366         goto error;
1367     }
1368     if (count) size = ROUND_SIZE( offset_low, count );
1369     else size = info.size_low - offset_low;
1370
1371     switch(access)
1372     {
1373     case FILE_MAP_ALL_ACCESS:
1374     case FILE_MAP_WRITE:
1375     case FILE_MAP_WRITE | FILE_MAP_READ:
1376         if (!(info.protect & VPROT_WRITE))
1377         {
1378             SetLastError( ERROR_INVALID_PARAMETER );
1379             goto error;
1380         }
1381         flags = MAP_SHARED;
1382         /* fall through */
1383     case FILE_MAP_READ:
1384     case FILE_MAP_COPY:
1385     case FILE_MAP_COPY | FILE_MAP_READ:
1386         if (info.protect & VPROT_READ) break;
1387         /* fall through */
1388     default:
1389         SetLastError( ERROR_INVALID_PARAMETER );
1390         goto error;
1391     }
1392
1393     /* Map the file */
1394
1395     TRACE(virtual, "handle=%x size=%x offset=%lx\n",
1396                      handle, size, offset_low );
1397
1398     ptr = (UINT32)FILE_dommap( unix_handle,
1399                                addr, 0, size, 0, offset_low,
1400                                VIRTUAL_GetUnixProt( info.protect ),
1401                                flags );
1402     if (ptr == (UINT32)-1) {
1403         /* KB: Q125713, 25-SEP-1995, "Common File Mapping Problems and
1404          * Platform Differences": 
1405          * Windows NT: ERROR_INVALID_PARAMETER
1406          * Windows 95: ERROR_INVALID_ADDRESS.
1407          * FIXME: So should we add a module dependend check here? -MM
1408          */
1409         if (errno==ENOMEM)
1410             SetLastError( ERROR_OUTOFMEMORY );
1411         else
1412             SetLastError( ERROR_INVALID_PARAMETER );
1413         goto error;
1414     }
1415
1416     if (!(view = VIRTUAL_CreateView( ptr, size, offset_low, 0,
1417                                      info.protect, handle )))
1418     {
1419         SetLastError( ERROR_OUTOFMEMORY );
1420         goto error;
1421     }
1422     if (unix_handle != -1) close( unix_handle );
1423     return (LPVOID)ptr;
1424
1425 error:
1426     if (unix_handle != -1) close( unix_handle );
1427     if (ptr != (UINT32)-1) FILE_munmap( (void *)ptr, 0, size );
1428     return NULL;
1429 }
1430
1431
1432 /***********************************************************************
1433  *             FlushViewOfFile   (KERNEL32.262)
1434  * Writes to the disk a byte range within a mapped view of a file
1435  *
1436  * RETURNS
1437  *      TRUE: Success
1438  *      FALSE: Failure
1439  */
1440 BOOL32 WINAPI FlushViewOfFile(
1441               LPCVOID base, /* [in] Start address of byte range to flush */
1442               DWORD cbFlush /* [in] Number of bytes in range */
1443 ) {
1444     FILE_VIEW *view;
1445     UINT32 addr = ROUND_ADDR( base );
1446
1447     TRACE(virtual, "FlushViewOfFile at %p for %ld bytes\n",
1448                      base, cbFlush );
1449
1450     if (!(view = VIRTUAL_FindView( addr )))
1451     {
1452         SetLastError( ERROR_INVALID_PARAMETER );
1453         return FALSE;
1454     }
1455     if (!cbFlush) cbFlush = view->size;
1456     if (!msync( (void *)addr, cbFlush, MS_SYNC )) return TRUE;
1457     SetLastError( ERROR_INVALID_PARAMETER );
1458     return FALSE;
1459 }
1460
1461
1462 /***********************************************************************
1463  *             UnmapViewOfFile   (KERNEL32.540)
1464  * Unmaps a mapped view of a file.
1465  *
1466  * NOTES
1467  *      Should addr be an LPCVOID?
1468  *
1469  * RETURNS
1470  *      TRUE: Success
1471  *      FALSE: Failure
1472  */
1473 BOOL32 WINAPI UnmapViewOfFile(
1474               LPVOID addr /* [in] Address where mapped view begins */
1475 ) {
1476     FILE_VIEW *view;
1477     UINT32 base = ROUND_ADDR( addr );
1478     if (!(view = VIRTUAL_FindView( base )) || (base != view->base))
1479     {
1480         SetLastError( ERROR_INVALID_PARAMETER );
1481         return FALSE;
1482     }
1483     VIRTUAL_DeleteView( view );
1484     return TRUE;
1485 }
1486
1487 /***********************************************************************
1488  *             VIRTUAL_MapFileW
1489  *
1490  * Helper function to map a file to memory:
1491  *  name                        -       file name 
1492  *  [RETURN] ptr                -       pointer to mapped file
1493  */
1494 LPVOID VIRTUAL_MapFileW( LPCWSTR name )
1495 {
1496     HANDLE32 hFile, hMapping;
1497     LPVOID ptr = NULL;
1498
1499     hFile = CreateFile32W( name, GENERIC_READ, FILE_SHARE_READ, NULL, 
1500                            OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS, 0);
1501     if (hFile != INVALID_HANDLE_VALUE32)
1502     {
1503         hMapping = CreateFileMapping32A( hFile, NULL, PAGE_READONLY, 0, 0, NULL );
1504         CloseHandle( hFile );
1505         if (hMapping)
1506         {
1507             ptr = MapViewOfFile( hMapping, FILE_MAP_READ, 0, 0, 0 );
1508             CloseHandle( hMapping );
1509         }
1510     }
1511     return ptr;
1512 }