Release 970928
[wine] / memory / virtual.c
1 /*
2  * Win32 virtual memory functions
3  *
4  * Copyright 1997 Alexandre Julliard
5  */
6
7 #include <assert.h>
8 #include <fcntl.h>
9 #include <stdio.h>
10 #include <unistd.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <sys/types.h>
14 #include <sys/mman.h>
15 #include "winbase.h"
16 #include "winerror.h"
17 #include "file.h"
18 #include "heap.h"
19 #include "process.h"
20 #include "xmalloc.h"
21 #include "stddebug.h"
22 #include "debug.h"
23
24 /* File mapping */
25 typedef struct
26 {
27     K32OBJ        header;
28     DWORD         size_high;
29     DWORD         size_low;
30     FILE_OBJECT  *file;
31     BYTE          protect;
32 } FILE_MAPPING;
33
34 /* File view */
35 typedef struct _FV
36 {
37     struct _FV   *next;     /* Next view */
38     struct _FV   *prev;     /* Prev view */
39     UINT32        base;     /* Base address */
40     UINT32        size;     /* Size in bytes */
41     UINT32        flags;    /* Allocation flags */
42     UINT32        offset;   /* Offset from start of mapped file */
43     FILE_MAPPING *mapping;  /* File mapping */
44     BYTE          protect;  /* Protection for all pages at allocation time */
45     BYTE          prot[1];  /* Protection byte for each page */
46 } FILE_VIEW;
47
48 /* Per-page protection byte values */
49 #define VPROT_READ       0x01
50 #define VPROT_WRITE      0x02
51 #define VPROT_EXEC       0x04
52 #define VPROT_WRITECOPY  0x08
53 #define VPROT_GUARD      0x10
54 #define VPROT_NOCACHE    0x20
55 #define VPROT_COMMITTED  0x40
56
57 /* Per-view flags */
58 #define VFLAG_SYSTEM     0x01
59
60 /* Conversion from VPROT_* to Win32 flags */
61 static const BYTE VIRTUAL_Win32Flags[16] =
62 {
63     PAGE_NOACCESS,              /* 0 */
64     PAGE_READONLY,              /* READ */
65     PAGE_READWRITE,             /* WRITE */
66     PAGE_READWRITE,             /* READ | WRITE */
67     PAGE_EXECUTE,               /* EXEC */
68     PAGE_EXECUTE_READ,          /* READ | EXEC */
69     PAGE_EXECUTE_READWRITE,     /* WRITE | EXEC */
70     PAGE_EXECUTE_READWRITE,     /* READ | WRITE | EXEC */
71     PAGE_WRITECOPY,             /* WRITECOPY */
72     PAGE_WRITECOPY,             /* READ | WRITECOPY */
73     PAGE_WRITECOPY,             /* WRITE | WRITECOPY */
74     PAGE_WRITECOPY,             /* READ | WRITE | WRITECOPY */
75     PAGE_EXECUTE_WRITECOPY,     /* EXEC | WRITECOPY */
76     PAGE_EXECUTE_WRITECOPY,     /* READ | EXEC | WRITECOPY */
77     PAGE_EXECUTE_WRITECOPY,     /* WRITE | EXEC | WRITECOPY */
78     PAGE_EXECUTE_WRITECOPY      /* READ | WRITE | EXEC | WRITECOPY */
79 };
80
81
82 static FILE_VIEW *VIRTUAL_FirstView;
83
84 static UINT32 page_shift;
85 static UINT32 page_mask;
86 static UINT32 granularity_mask;  /* Allocation granularity (usually 64k) */
87
88 #define ROUND_ADDR(addr) \
89    ((UINT32)(addr) & ~page_mask)
90
91 #define ROUND_SIZE(addr,size) \
92    (((UINT32)(size) + ((UINT32)(addr) & page_mask) + page_mask) & ~page_mask)
93
94
95 /***********************************************************************
96  *           VIRTUAL_GetProtStr
97  */
98 static const char *VIRTUAL_GetProtStr( BYTE prot )
99 {
100     static char buffer[6];
101     buffer[0] = (prot & VPROT_COMMITTED) ? 'c' : '-';
102     buffer[1] = (prot & VPROT_GUARD) ? 'g' : '-';
103     buffer[2] = (prot & VPROT_READ) ? 'r' : '-';
104     buffer[3] = (prot & VPROT_WRITE) ?
105                     ((prot & VPROT_WRITECOPY) ? 'w' : 'W') : '-';
106     buffer[4] = (prot & VPROT_EXEC) ? 'x' : '-';
107     buffer[5] = 0;
108     return buffer;
109 }
110
111
112 /***********************************************************************
113  *           VIRTUAL_DumpView
114  */
115 static void VIRTUAL_DumpView( FILE_VIEW *view )
116 {
117     UINT32 i, count;
118     UINT32 addr = view->base;
119     BYTE prot = view->prot[0];
120
121     dprintf_virtual( stddeb, "View: %08x - %08x%s",
122              view->base, view->base + view->size - 1,
123              (view->flags & VFLAG_SYSTEM) ? " (system)" : "" );
124     if (view->mapping && view->mapping->file)
125         dprintf_virtual( stddeb, " %s @ %08x\n",
126                  view->mapping->file->unix_name, view->offset );
127     else
128         dprintf_virtual( stddeb, " (anonymous)\n");
129
130     for (count = i = 1; i < view->size >> page_shift; i++, count++)
131     {
132         if (view->prot[i] == prot) continue;
133         dprintf_virtual( stddeb, "      %08x - %08x %s\n",
134                  addr, addr + (count << page_shift) - 1,
135                  VIRTUAL_GetProtStr(prot) );
136         addr += (count << page_shift);
137         prot = view->prot[i];
138         count = 0;
139     }
140     if (count)
141         dprintf_virtual( stddeb, "      %08x - %08x %s\n",
142                  addr, addr + (count << page_shift) - 1,
143                  VIRTUAL_GetProtStr(prot) );
144 }
145
146
147 /***********************************************************************
148  *           VIRTUAL_Dump
149  */
150 void VIRTUAL_Dump(void)
151 {
152     FILE_VIEW *view = VIRTUAL_FirstView;
153     dprintf_virtual( stddeb, "\nDump of all virtual memory views:\n\n" );
154     while (view)
155     {
156         VIRTUAL_DumpView( view );
157         view = view->next;
158     }
159 }
160
161
162 /***********************************************************************
163  *           VIRTUAL_FindView
164  *
165  * Find the view containing a given address.
166  */
167 static FILE_VIEW *VIRTUAL_FindView( UINT32 addr )
168 {
169     FILE_VIEW *view = VIRTUAL_FirstView;
170     while (view)
171     {
172         if (view->base > addr) return NULL;
173         if (view->base + view->size > addr) return view;
174         view = view->next;
175     }
176     return NULL;
177 }
178
179
180 /***********************************************************************
181  *           VIRTUAL_CreateView
182  *
183  * Create a new view and add it in the linked list.
184  */
185 static FILE_VIEW *VIRTUAL_CreateView( UINT32 base, UINT32 size, UINT32 offset,
186                                       UINT32 flags, BYTE vprot,
187                                       FILE_MAPPING *mapping )
188 {
189     FILE_VIEW *view, *prev;
190
191     /* Create the view structure */
192
193     size >>= page_shift;
194     if (!(view = (FILE_VIEW *)malloc( sizeof(*view) + size - 1 ))) return NULL;
195     view->base    = base;
196     view->size    = size << page_shift;
197     view->flags   = flags;
198     view->offset  = offset;
199     view->mapping = mapping;
200     view->protect = vprot;
201     memset( view->prot, vprot, size );
202
203     /* Insert it in the linked list */
204
205     if (!VIRTUAL_FirstView || (VIRTUAL_FirstView->base > base))
206     {
207         view->next = VIRTUAL_FirstView;
208         view->prev = NULL;
209         if (view->next) view->next->prev = view;
210         VIRTUAL_FirstView = view;
211     }
212     else
213     {
214         prev = VIRTUAL_FirstView;
215         while (prev->next && (prev->next->base < base)) prev = prev->next;
216         view->next = prev->next;
217         view->prev = prev;
218         if (view->next) view->next->prev = view;
219         prev->next  = view;
220     }
221     if (debugging_virtual) VIRTUAL_DumpView( view );
222     return view;
223 }
224
225
226 /***********************************************************************
227  *           VIRTUAL_DeleteView
228  *
229  * Delete an view.
230  */
231 static void VIRTUAL_DeleteView( FILE_VIEW *view )
232 {
233     munmap( (void *)view->base, view->size );
234     if (view->next) view->next->prev = view->prev;
235     if (view->prev) view->prev->next = view->next;
236     else VIRTUAL_FirstView = view->next;
237     if (view->mapping) K32OBJ_DecCount( &view->mapping->header );
238     free( view );
239 }
240
241
242 /***********************************************************************
243  *           VIRTUAL_GetUnixProt
244  *
245  * Convert page protections to protection for mmap/mprotect.
246  */
247 static int VIRTUAL_GetUnixProt( BYTE vprot )
248 {
249     int prot = 0;
250     if ((vprot & VPROT_COMMITTED) && !(vprot & VPROT_GUARD))
251     {
252         if (vprot & VPROT_READ) prot |= PROT_READ;
253         if (vprot & VPROT_WRITE) prot |= PROT_WRITE;
254         if (vprot & VPROT_EXEC) prot |= PROT_EXEC;
255     }
256     return prot;
257 }
258
259
260 /***********************************************************************
261  *           VIRTUAL_GetWin32Prot
262  *
263  * Convert page protections to Win32 flags.
264  */
265 static void VIRTUAL_GetWin32Prot( BYTE vprot, DWORD *protect, DWORD *state )
266 {
267     *protect = VIRTUAL_Win32Flags[vprot & 0x0f];
268     if (vprot & VPROT_GUARD) *protect |= PAGE_GUARD;
269     if (vprot & VPROT_NOCACHE) *protect |= PAGE_NOCACHE;
270
271     if (state) *state = (vprot & VPROT_COMMITTED) ? MEM_COMMIT : MEM_RESERVE;
272 }
273
274
275 /***********************************************************************
276  *           VIRTUAL_GetProt
277  *
278  * Build page protections from Win32 flags.
279  */
280 static BYTE VIRTUAL_GetProt( DWORD protect )
281 {
282     BYTE vprot;
283
284     switch(protect & 0xff)
285     {
286     case PAGE_READONLY:
287         vprot = VPROT_READ;
288         break;
289     case PAGE_READWRITE:
290         vprot = VPROT_READ | VPROT_WRITE;
291         break;
292     case PAGE_WRITECOPY:
293         vprot = VPROT_READ | VPROT_WRITE | VPROT_WRITECOPY;
294         break;
295     case PAGE_EXECUTE:
296         vprot = VPROT_EXEC;
297         break;
298     case PAGE_EXECUTE_READ:
299         vprot = VPROT_EXEC | VPROT_READ;
300         break;
301     case PAGE_EXECUTE_READWRITE:
302         vprot = VPROT_EXEC | VPROT_READ | VPROT_WRITE | VPROT_WRITECOPY;
303         break;
304     case PAGE_EXECUTE_WRITECOPY:
305         vprot = VPROT_EXEC | VPROT_READ | VPROT_WRITE;
306         break;
307     case PAGE_NOACCESS:
308     default:
309         vprot = 0;
310         break;
311     }
312     if (protect & PAGE_GUARD) vprot |= VPROT_GUARD;
313     if (protect & PAGE_NOCACHE) vprot |= VPROT_NOCACHE;
314     return vprot;
315 }
316
317
318 /***********************************************************************
319  *           VIRTUAL_SetProt
320  *
321  * Change the protection of a range of pages.
322  */
323 static BOOL32 VIRTUAL_SetProt( FILE_VIEW *view, UINT32 base,
324                                UINT32 size, BYTE vprot )
325 {
326     dprintf_virtual( stddeb, "VIRTUAL_SetProt: %08x-%08x %s\n",
327                      base, base + size - 1, VIRTUAL_GetProtStr( vprot ) );
328
329     if (mprotect( (void *)base, size, VIRTUAL_GetUnixProt(vprot) ))
330         return FALSE;  /* FIXME: last error */
331
332     memset( view->prot + ((base - view->base) >> page_shift),
333             vprot, size >> page_shift );
334     if (debugging_virtual) VIRTUAL_DumpView( view );
335     return TRUE;
336 }
337
338
339 /***********************************************************************
340  *             VIRTUAL_CheckFlags
341  *
342  * Check that all pages in a range have the given flags.
343  */
344 static BOOL32 VIRTUAL_CheckFlags( UINT32 base, UINT32 size, BYTE flags )
345 {
346     FILE_VIEW *view;
347     UINT32 page;
348
349     if (!size) return TRUE;
350     if (!(view = VIRTUAL_FindView( base ))) return FALSE;
351     if (view->base + view->size < base + size) return FALSE;
352     page = (base - view->base) >> page_shift;
353     size = ROUND_SIZE( base, size ) >> page_shift;
354     while (size--) if ((view->prot[page++] & flags) != flags) return FALSE;
355     return TRUE;
356 }
357
358
359 /***********************************************************************
360  *           VIRTUAL_Init
361  */
362 BOOL32 VIRTUAL_Init(void)
363 {
364     SYSTEM_INFO sysinfo;
365     GetSystemInfo( &sysinfo );
366
367     page_mask = sysinfo.dwPageSize - 1;
368     granularity_mask = sysinfo.dwAllocationGranularity - 1;
369     /* Make sure we have a power of 2 */
370     assert( !(sysinfo.dwPageSize & page_mask) );
371     assert( !(sysinfo.dwAllocationGranularity & granularity_mask) );
372     page_shift = 0;
373     while ((1 << page_shift) != sysinfo.dwPageSize) page_shift++;
374
375 #ifdef linux
376     {
377         /* Do not use stdio here since it may temporarily change the size
378          * of some segments (ie libc6 adds 0x1000 per open FILE)
379          */
380         int fd = open ("/proc/self/maps", O_RDONLY);
381         if (fd >= 0)
382         {
383             char buffer[80];
384
385             for (;;)
386             {
387                 int start, end, offset;
388                 char r, w, x, p;
389                 BYTE vprot = VPROT_COMMITTED;
390
391                 char * ptr = buffer;
392                 int count = sizeof(buffer);
393                 while (1 == read(fd, ptr, 1) && *ptr != '\n' && --count > 0)
394                     ptr++;
395
396                 if (*ptr != '\n') break;
397                 *ptr = '\0';
398
399                 sscanf( buffer, "%x-%x %c%c%c%c %x",
400                         &start, &end, &r, &w, &x, &p, &offset );
401                 if (r == 'r') vprot |= VPROT_READ;
402                 if (w == 'w') vprot |= VPROT_WRITE;
403                 if (x == 'x') vprot |= VPROT_EXEC;
404                 if (p == 'p') vprot |= VPROT_WRITECOPY;
405                 VIRTUAL_CreateView( start, end - start, 0,
406                                     VFLAG_SYSTEM, vprot, NULL );
407             }
408             close (fd);
409         }
410     }
411 #endif  /* linux */
412     return TRUE;
413 }
414
415
416 /***********************************************************************
417  *             VirtualAlloc   (KERNEL32.548)
418  */
419 LPVOID WINAPI VirtualAlloc( LPVOID addr, DWORD size, DWORD type, DWORD protect)
420 {
421     FILE_VIEW *view;
422     UINT32 base, ptr, view_size;
423     BYTE vprot;
424
425     dprintf_virtual( stddeb, "VirtualAlloc: %08x %08lx %lx %08lx\n",
426                      (UINT32)addr, size, type, protect );
427
428     /* Round parameters to a page boundary */
429
430     if (size > 0x7fc00000)  /* 2Gb - 4Mb */
431     {
432         SetLastError( ERROR_OUTOFMEMORY );
433         return NULL;
434     }
435     if (addr)
436     {
437         if (type & MEM_RESERVE) /* Round down to 64k boundary */
438             base = ((UINT32)addr + granularity_mask) & ~granularity_mask;
439         else
440             base = ROUND_ADDR( addr );
441         size = (((UINT32)addr + size + page_mask) & ~page_mask) - base;
442         if (base + size < base)  /* Disallow wrap-around */
443         {
444             SetLastError( ERROR_INVALID_PARAMETER );
445             return NULL;
446         }
447     }
448     else
449     {
450         base = 0;
451         size = (size + page_mask) & ~page_mask;
452     }
453
454     /* Compute the protection flags */
455
456     if (!(type & (MEM_COMMIT | MEM_RESERVE)) ||
457         (type & ~(MEM_COMMIT | MEM_RESERVE)))
458     {
459         SetLastError( ERROR_INVALID_PARAMETER );
460         return NULL;
461     }
462     if (type & MEM_COMMIT)
463         vprot = VIRTUAL_GetProt( protect ) | VPROT_COMMITTED;
464     else vprot = 0;
465
466     /* Reserve the memory */
467
468     if ((type & MEM_RESERVE) || !base)
469     {
470         view_size = size + (base ? 0 : granularity_mask + 1);
471         ptr = (UINT32)FILE_mmap( NULL, (LPVOID)base, 0, view_size, 0, 0,
472                                  VIRTUAL_GetUnixProt( vprot ), MAP_PRIVATE );
473         if (ptr == (UINT32)-1)
474         {
475             SetLastError( ERROR_OUTOFMEMORY );
476             return NULL;
477         }
478         if (!base)
479         {
480             /* Release the extra memory while keeping the range */
481             /* starting on a 64k boundary. */
482
483             if (ptr & granularity_mask)
484             {
485                 UINT32 extra = granularity_mask + 1 - (ptr & granularity_mask);
486                 munmap( (void *)ptr, extra );
487                 ptr += extra;
488                 view_size -= extra;
489             }
490             if (view_size > size)
491                 munmap( (void *)(ptr + size), view_size - size );
492         }
493         if (!(view = VIRTUAL_CreateView( ptr, size, 0, 0, vprot, NULL )))
494         {
495             munmap( (void *)ptr, size );
496             SetLastError( ERROR_OUTOFMEMORY );
497             return NULL;
498         }
499         if (debugging_virtual) VIRTUAL_DumpView( view );
500         return (LPVOID)ptr;
501     }
502
503     /* Commit the pages */
504
505     if (!(view = VIRTUAL_FindView( base )) ||
506         (base + size > view->base + view->size))
507     {
508         SetLastError( ERROR_INVALID_PARAMETER );
509         return NULL;
510     }
511
512     if (!VIRTUAL_SetProt( view, base, size, vprot )) return NULL;
513     return (LPVOID)base;
514 }
515
516
517 /***********************************************************************
518  *             VirtualFree   (KERNEL32.550)
519  */
520 BOOL32 WINAPI VirtualFree( LPVOID addr, DWORD size, DWORD type )
521 {
522     FILE_VIEW *view;
523     UINT32 base;
524
525     dprintf_virtual( stddeb, "VirtualFree: %08x %08lx %lx\n",
526                      (UINT32)addr, size, type );
527
528     /* Fix the parameters */
529
530     size = ROUND_SIZE( addr, size );
531     base = ROUND_ADDR( addr );
532
533     if (!(view = VIRTUAL_FindView( base )) ||
534         (base + size > view->base + view->size))
535     {
536         SetLastError( ERROR_INVALID_PARAMETER );
537         return FALSE;
538     }
539
540     /* Compute the protection flags */
541
542     if ((type != MEM_DECOMMIT) && (type != MEM_RELEASE))
543     {
544         SetLastError( ERROR_INVALID_PARAMETER );
545         return FALSE;
546     }
547
548     /* Free the pages */
549
550     if (type == MEM_RELEASE)
551     {
552         if (size || (base != view->base))
553         {
554             SetLastError( ERROR_INVALID_PARAMETER );
555             return FALSE;
556         }
557         VIRTUAL_DeleteView( view );
558         return TRUE;
559     }
560
561     /* Decommit the pages */
562
563     return VIRTUAL_SetProt( view, base, size, 0 );
564 }
565
566
567 /***********************************************************************
568  *             VirtualLock   (KERNEL32.551)
569  */
570 BOOL32 WINAPI VirtualLock( LPVOID addr, DWORD size )
571 {
572     return TRUE;
573 }
574
575
576 /***********************************************************************
577  *             VirtualUnlock   (KERNEL32.556)
578  */
579 BOOL32 WINAPI VirtualUnlock( LPVOID addr, DWORD size )
580 {
581     return TRUE;
582 }
583
584
585 /***********************************************************************
586  *             VirtualProtect   (KERNEL32.552)
587  */
588 BOOL32 WINAPI VirtualProtect( LPVOID addr, DWORD size, DWORD new_prot,
589                               LPDWORD old_prot )
590 {
591     FILE_VIEW *view;
592     UINT32 base, i;
593     BYTE vprot, *p;
594
595     dprintf_virtual( stddeb, "VirtualProtect: %08x %08lx %08lx\n",
596                      (UINT32)addr, size, new_prot );
597
598     /* Fix the parameters */
599
600     size = ROUND_SIZE( addr, size );
601     base = ROUND_ADDR( addr );
602
603     if (!(view = VIRTUAL_FindView( base )) ||
604         (base + size > view->base + view->size))
605     {
606         SetLastError( ERROR_INVALID_PARAMETER );
607         return FALSE;
608     }
609
610     /* Make sure all the pages are committed */
611
612     p = view->prot + ((base - view->base) >> page_shift);
613     for (i = size >> page_shift; i; i--, p++)
614     {
615         if (!(*p & VPROT_COMMITTED))
616         {
617             SetLastError( ERROR_INVALID_PARAMETER );
618             return FALSE;
619         }
620     }
621
622     VIRTUAL_GetWin32Prot( view->prot[0], old_prot, NULL );
623     vprot = VIRTUAL_GetProt( new_prot ) | VPROT_COMMITTED;
624     return VIRTUAL_SetProt( view, base, size, vprot );
625 }
626
627
628 /***********************************************************************
629  *             VirtualProtectEx   (KERNEL32.553)
630  */
631 BOOL32 WINAPI VirtualProtectEx( HANDLE32 handle, LPVOID addr, DWORD size,
632                                 DWORD new_prot, LPDWORD old_prot )
633 {
634     BOOL32 ret = FALSE;
635
636     PDB32 *pdb = (PDB32 *)PROCESS_GetObjPtr( handle, K32OBJ_PROCESS );
637     if (pdb)
638     {
639         if (pdb == pCurrentProcess)
640             ret = VirtualProtect( addr, size, new_prot, old_prot );
641         else
642             fprintf(stderr,"Unsupported: VirtualProtectEx on other process\n");
643         K32OBJ_DecCount( &pdb->header );
644     }
645     return ret;
646 }
647
648
649 /***********************************************************************
650  *             VirtualQuery   (KERNEL32.554)
651  */
652 BOOL32 WINAPI VirtualQuery( LPCVOID addr, LPMEMORY_BASIC_INFORMATION info,
653                             DWORD len )
654 {
655     FILE_VIEW *view = VIRTUAL_FirstView;
656     UINT32 base = ROUND_ADDR( addr );
657     UINT32 alloc_base = 0;
658     UINT32 size = 0;
659
660     /* Find the view containing the address */
661
662     for (;;)
663     {
664         if (!view)
665         {
666             size = 0xffff0000 - alloc_base;
667             break;
668         }
669         if (view->base > base)
670         {
671             size = view->base - alloc_base;
672             view = NULL;
673             break;
674         }
675         if (view->base + view->size > base)
676         {
677             alloc_base = view->base;
678             size = view->size;
679             break;
680         }
681         alloc_base = view->base + view->size;
682         view = view->next;
683     }
684
685     /* Fill the info structure */
686
687     if (!view)
688     {
689         info->State             = MEM_FREE;
690         info->Protect           = 0;
691         info->AllocationProtect = 0;
692         info->Type              = 0;
693     }
694     else
695     {
696         BYTE vprot = view->prot[(base - alloc_base) >> page_shift];
697         VIRTUAL_GetWin32Prot( vprot, &info->Protect, &info->State );
698         for (size = base - alloc_base; size < view->size; size += page_mask+1)
699             if (view->prot[size >> page_shift] != vprot) break;
700         info->AllocationProtect = view->protect;
701         info->Type              = MEM_PRIVATE;  /* FIXME */
702     }
703
704     info->BaseAddress    = (LPVOID)base;
705     info->AllocationBase = (LPVOID)alloc_base;
706     info->RegionSize     = size - (base - alloc_base);
707     return TRUE;
708 }
709
710
711 /***********************************************************************
712  *             VirtualQueryEx   (KERNEL32.555)
713  */
714 BOOL32 WINAPI VirtualQueryEx( HANDLE32 handle, LPCVOID addr,
715                               LPMEMORY_BASIC_INFORMATION info, DWORD len )
716 {
717     BOOL32 ret = FALSE;
718
719     PDB32 *pdb = (PDB32 *)PROCESS_GetObjPtr( handle, K32OBJ_PROCESS );
720     if (pdb)
721     {
722         if (pdb == pCurrentProcess)
723             ret = VirtualQuery( addr, info, len );
724         else
725             fprintf(stderr,"Unsupported: VirtualQueryEx on other process\n");
726         K32OBJ_DecCount( &pdb->header );
727     }
728     return ret;
729 }
730
731
732 /***********************************************************************
733  *             IsBadReadPtr32   (KERNEL32.354)
734  */
735 BOOL32 WINAPI IsBadReadPtr32( LPCVOID ptr, UINT32 size )
736 {
737     return !VIRTUAL_CheckFlags( (UINT32)ptr, size,
738                                 VPROT_READ | VPROT_COMMITTED );
739 }
740
741
742 /***********************************************************************
743  *             IsBadWritePtr32   (KERNEL32.357)
744  */
745 BOOL32 WINAPI IsBadWritePtr32( LPVOID ptr, UINT32 size )
746 {
747     return !VIRTUAL_CheckFlags( (UINT32)ptr, size,
748                                 VPROT_WRITE | VPROT_COMMITTED );
749 }
750
751
752 /***********************************************************************
753  *             IsBadHugeReadPtr32   (KERNEL32.352)
754  */
755 BOOL32 WINAPI IsBadHugeReadPtr32( LPCVOID ptr, UINT32 size )
756 {
757     return IsBadReadPtr32( ptr, size );
758 }
759
760
761 /***********************************************************************
762  *             IsBadHugeWritePtr32   (KERNEL32.353)
763  */
764 BOOL32 WINAPI IsBadHugeWritePtr32( LPVOID ptr, UINT32 size )
765 {
766     return IsBadWritePtr32( ptr, size );
767 }
768
769
770 /***********************************************************************
771  *             IsBadCodePtr32   (KERNEL32.351)
772  */
773 BOOL32 WINAPI IsBadCodePtr32( FARPROC32 ptr )
774 {
775     return !VIRTUAL_CheckFlags( (UINT32)ptr, 1, VPROT_EXEC | VPROT_COMMITTED );
776 }
777
778
779 /***********************************************************************
780  *             IsBadStringPtr32A   (KERNEL32.355)
781  */
782 BOOL32 WINAPI IsBadStringPtr32A( LPCSTR str, UINT32 max )
783 {
784     FILE_VIEW *view;
785     UINT32 page, count;
786
787     if (!max) return FALSE;
788     if (!(view = VIRTUAL_FindView( (UINT32)str ))) return TRUE;
789     page  = ((UINT32)str - view->base) >> page_shift;
790     count = page_mask + 1 - ((UINT32)str & page_mask);
791
792     while (max)
793     {
794         if ((view->prot[page] & (VPROT_READ | VPROT_COMMITTED)) != 
795                                                 (VPROT_READ | VPROT_COMMITTED))
796             return TRUE;
797         if (count > max) count = max;
798         max -= count;
799         while (count--) if (!*str++) return FALSE;
800         if (++page >= view->size >> page_shift) return TRUE;
801         count = page_mask + 1;
802     }
803     return FALSE;
804 }
805
806
807 /***********************************************************************
808  *             IsBadStringPtr32W   (KERNEL32.356)
809  */
810 BOOL32 WINAPI IsBadStringPtr32W( LPCWSTR str, UINT32 max )
811 {
812     FILE_VIEW *view;
813     UINT32 page, count;
814
815     if (!max) return FALSE;
816     if (!(view = VIRTUAL_FindView( (UINT32)str ))) return TRUE;
817     page  = ((UINT32)str - view->base) >> page_shift;
818     count = (page_mask + 1 - ((UINT32)str & page_mask)) / sizeof(WCHAR);
819
820     while (max)
821     {
822         if ((view->prot[page] & (VPROT_READ | VPROT_COMMITTED)) != 
823                                                 (VPROT_READ | VPROT_COMMITTED))
824             return TRUE;
825         if (count > max) count = max;
826         max -= count;
827         while (count--) if (!*str++) return FALSE;
828         if (++page >= view->size >> page_shift) return TRUE;
829         count = (page_mask + 1) / sizeof(WCHAR);
830     }
831     return FALSE;
832 }
833
834
835 /***********************************************************************
836  *             CreateFileMapping32A   (KERNEL32.46)
837  */
838 HANDLE32 WINAPI CreateFileMapping32A(HFILE32 hFile, LPSECURITY_ATTRIBUTES attr,
839                                      DWORD protect, DWORD size_high,
840                                      DWORD size_low, LPCSTR name )
841 {
842     FILE_MAPPING *mapping = NULL;
843     HANDLE32 handle;
844     BYTE vprot;
845
846     /* First search for an object with the same name */
847
848     K32OBJ *obj = K32OBJ_FindName( name );
849     if (obj)
850     {
851         if (obj->type == K32OBJ_MEM_MAPPED_FILE)
852         {
853             SetLastError( ERROR_ALREADY_EXISTS );
854             return PROCESS_AllocHandle( obj, 0 );
855         }
856         SetLastError( ERROR_DUP_NAME );
857         return 0;
858     }
859
860     /* Check parameters */
861
862     dprintf_virtual(stddeb,"CreateFileMapping32A(%x,%p,%08lx,%08lx%08lx,%s)\n",
863                     hFile, attr, protect, size_high, size_low, name );
864
865     vprot = VIRTUAL_GetProt( protect );
866     if (protect & SEC_RESERVE)
867     {
868         if (hFile != INVALID_HANDLE_VALUE32)
869         {
870             SetLastError( ERROR_INVALID_PARAMETER );
871             return 0;
872         }
873     }
874     else vprot |= VPROT_COMMITTED;
875     if (protect & SEC_NOCACHE) vprot |= VPROT_NOCACHE;
876
877     /* Compute the size and extend the file if necessary */
878
879     if (hFile == INVALID_HANDLE_VALUE32)
880     {
881         if (!size_high && !size_low)
882         {
883             SetLastError( ERROR_INVALID_PARAMETER );
884             return 0;
885         }
886         obj = NULL;
887     }
888     else  /* We have a file */
889     {
890         BY_HANDLE_FILE_INFORMATION info;
891         if (!(obj = PROCESS_GetObjPtr( hFile, K32OBJ_FILE ))) goto error;
892         /* FIXME: should check if the file permissions agree
893          *        with the required protection flags */
894         if (!GetFileInformationByHandle( hFile, &info )) goto error;
895         if (!size_high && !size_low)
896         {
897             size_high = info.nFileSizeHigh;
898             size_low  = info.nFileSizeLow;
899         }
900         else if ((size_high > info.nFileSizeHigh) ||
901                  ((size_high == info.nFileSizeHigh) &&
902                   (size_low > info.nFileSizeLow)))
903         {
904             /* We have to grow the file */
905             if (SetFilePointer( hFile, size_low, &size_high,
906                                 FILE_BEGIN ) == 0xffffffff) goto error;
907             if (!SetEndOfFile( hFile )) goto error;
908         }
909     }
910
911     /* Allocate the mapping object */
912
913     if (!(mapping = HeapAlloc( SystemHeap, 0, sizeof(*mapping) ))) goto error;
914     mapping->header.type = K32OBJ_MEM_MAPPED_FILE;
915     mapping->header.refcount = 1;
916     mapping->protect   = vprot;
917     mapping->size_high = size_high;
918     mapping->size_low  = ROUND_SIZE( 0, size_low );
919     mapping->file      = (FILE_OBJECT *)obj;
920
921     handle = PROCESS_AllocHandle( &mapping->header, 0 );
922     if (handle != INVALID_HANDLE_VALUE32) return handle;
923
924 error:
925     if (obj) K32OBJ_DecCount( obj );
926     if (mapping) HeapFree( SystemHeap, 0, mapping );
927     return 0;
928 }
929
930
931 /***********************************************************************
932  *             CreateFileMapping32W   (KERNEL32.47)
933  */
934 HANDLE32 WINAPI CreateFileMapping32W(HFILE32 hFile, LPSECURITY_ATTRIBUTES attr,
935                                      DWORD protect, DWORD size_high,
936                                      DWORD size_low, LPCWSTR name )
937 {
938     LPSTR nameA = HEAP_strdupWtoA( GetProcessHeap(), 0, name );
939     HANDLE32 ret = CreateFileMapping32A( hFile, attr, protect,
940                                          size_high, size_low, nameA );
941     HeapFree( GetProcessHeap(), 0, nameA );
942     return ret;
943 }
944
945
946 /***********************************************************************
947  *             OpenFileMapping32A   (KERNEL32.397)
948  */
949 HANDLE32 WINAPI OpenFileMapping32A( DWORD access, BOOL32 inherit, LPCSTR name )
950 {
951     K32OBJ *obj = K32OBJ_FindNameType( name, K32OBJ_MEM_MAPPED_FILE );
952     if (!obj) return 0;
953     return PROCESS_AllocHandle( obj, 0 );
954 }
955
956
957 /***********************************************************************
958  *             OpenFileMapping32W   (KERNEL32.398)
959  */
960 HANDLE32 WINAPI OpenFileMapping32W( DWORD access, BOOL32 inherit, LPCWSTR name)
961 {
962     LPSTR nameA = HEAP_strdupWtoA( GetProcessHeap(), 0, name );
963     HANDLE32 ret = OpenFileMapping32A( access, inherit, nameA );
964     HeapFree( GetProcessHeap(), 0, nameA );
965     return ret;
966 }
967
968
969 /***********************************************************************
970  *           VIRTUAL_DestroyMapping
971  *
972  * Destroy a FILE_MAPPING object.
973  */
974 void VIRTUAL_DestroyMapping( K32OBJ *ptr )
975 {
976     FILE_MAPPING *mapping = (FILE_MAPPING *)ptr;
977     assert( ptr->type == K32OBJ_MEM_MAPPED_FILE );
978
979     if (mapping->file) K32OBJ_DecCount( &mapping->file->header );
980     ptr->type = K32OBJ_UNKNOWN;
981     HeapFree( SystemHeap, 0, mapping );
982 }
983
984
985 /***********************************************************************
986  *             MapViewOfFile   (KERNEL32.385)
987  */
988 LPVOID WINAPI MapViewOfFile( HANDLE32 mapping, DWORD access, DWORD offset_high,
989                              DWORD offset_low, DWORD count )
990 {
991     return MapViewOfFileEx( mapping, access, offset_high,
992                             offset_low, count, NULL );
993 }
994
995
996 /***********************************************************************
997  *             MapViewOfFileEx   (KERNEL32.386)
998  */
999 LPVOID WINAPI MapViewOfFileEx(HANDLE32 handle, DWORD access, DWORD offset_high,
1000                               DWORD offset_low, DWORD count, LPVOID addr )
1001 {
1002     FILE_MAPPING *mapping;
1003     FILE_VIEW *view;
1004     UINT32 ptr = (UINT32)-1, size = 0;
1005     int flags = MAP_PRIVATE;
1006
1007     /* Check parameters */
1008
1009     if ((offset_low & granularity_mask) ||
1010         (addr && ((UINT32)addr & granularity_mask)))
1011     {
1012         SetLastError( ERROR_INVALID_PARAMETER );
1013         return NULL;
1014     }
1015
1016     if (!(mapping = (FILE_MAPPING *)PROCESS_GetObjPtr( handle,
1017                                                      K32OBJ_MEM_MAPPED_FILE )))
1018         return NULL;
1019
1020     if (mapping->size_high || offset_high)
1021         fprintf( stderr, "MapViewOfFileEx: offsets larger than 4Gb not supported\n");
1022
1023     if ((offset_low >= mapping->size_low) ||
1024         (count > mapping->size_low - offset_low))
1025     {
1026         SetLastError( ERROR_INVALID_PARAMETER );
1027         goto error;
1028     }
1029     if (count) size = ROUND_SIZE( offset_low, count );
1030     else size = mapping->size_low - offset_low;
1031
1032     switch(access)
1033     {
1034     case FILE_MAP_ALL_ACCESS:
1035     case FILE_MAP_WRITE:
1036     case FILE_MAP_WRITE | FILE_MAP_READ:
1037         if (!(mapping->protect & VPROT_WRITE))
1038         {
1039             SetLastError( ERROR_INVALID_PARAMETER );
1040             goto error;
1041         }
1042         flags = MAP_SHARED;
1043         /* fall through */
1044     case FILE_MAP_READ:
1045     case FILE_MAP_COPY:
1046     case FILE_MAP_COPY | FILE_MAP_READ:
1047         if (mapping->protect & VPROT_READ) break;
1048         /* fall through */
1049     default:
1050         SetLastError( ERROR_INVALID_PARAMETER );
1051         goto error;
1052     }
1053
1054     /* Map the file */
1055
1056     dprintf_virtual( stddeb, "MapViewOfFile: handle=%x size=%x offset=%lx\n",
1057                      handle, size, offset_low );
1058
1059     ptr = (UINT32)FILE_mmap( mapping->file, addr, 0, size, 0, offset_low,
1060                              VIRTUAL_GetUnixProt( mapping->protect ),
1061                              flags );
1062     if (ptr == (UINT32)-1)
1063     {
1064         SetLastError( ERROR_OUTOFMEMORY );
1065         goto error;
1066     }
1067
1068     if (!(view = VIRTUAL_CreateView( ptr, size, offset_low, 0,
1069                                      mapping->protect, mapping )))
1070     {
1071         SetLastError( ERROR_OUTOFMEMORY );
1072         goto error;
1073     }
1074     return (LPVOID)ptr;
1075
1076 error:
1077     if (ptr != (UINT32)-1) munmap( (void *)ptr, size );
1078     K32OBJ_DecCount( &mapping->header );
1079     return NULL;
1080 }
1081
1082
1083 /***********************************************************************
1084  *             UnmapViewOfFile   (KERNEL32.540)
1085  */
1086 BOOL32 WINAPI UnmapViewOfFile( LPVOID addr )
1087 {
1088     FILE_VIEW *view;
1089     UINT32 base = ROUND_ADDR( addr );
1090     if (!(view = VIRTUAL_FindView( base )) || (base != view->base))
1091     {
1092         SetLastError( ERROR_INVALID_PARAMETER );
1093         return FALSE;
1094     }
1095     VIRTUAL_DeleteView( view );
1096     return TRUE;
1097 }