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