Release 970509
[wine/multimedia.git] / memory / virtual.c
blob2e3a6c016d266141749a8cce285b7b5770ab32df
1 /*
2 * Win32 virtual memory functions
4 * Copyright 1997 Alexandre Julliard
5 */
7 #include <assert.h>
8 #include <fcntl.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <sys/types.h>
13 #include <sys/mman.h>
14 #include "winbase.h"
15 #include "winerror.h"
16 #include "file.h"
17 #include "heap.h"
18 #include "process.h"
19 #include "xmalloc.h"
20 #include "stddebug.h"
21 #include "debug.h"
23 /* File mapping */
24 typedef struct
26 K32OBJ header;
27 DWORD size_high;
28 DWORD size_low;
29 FILE_OBJECT *file;
30 BYTE protect;
31 } FILE_MAPPING;
33 /* File view */
34 typedef struct _FV
36 struct _FV *next; /* Next view */
37 struct _FV *prev; /* Prev view */
38 UINT32 base; /* Base address */
39 UINT32 size; /* Size in bytes */
40 UINT32 flags; /* Allocation flags */
41 UINT32 offset; /* Offset from start of mapped file */
42 FILE_MAPPING *mapping; /* File mapping */
43 BYTE protect; /* Protection for all pages at allocation time */
44 BYTE prot[1]; /* Protection byte for each page */
45 } FILE_VIEW;
47 /* Per-page protection byte values */
48 #define VPROT_READ 0x01
49 #define VPROT_WRITE 0x02
50 #define VPROT_EXEC 0x04
51 #define VPROT_WRITECOPY 0x08
52 #define VPROT_GUARD 0x10
53 #define VPROT_NOCACHE 0x20
54 #define VPROT_COMMITTED 0x40
56 /* Per-view flags */
57 #define VFLAG_SYSTEM 0x01
59 /* Conversion from VPROT_* to Win32 flags */
60 static const BYTE VIRTUAL_Win32Flags[16] =
62 PAGE_NOACCESS, /* 0 */
63 PAGE_READONLY, /* READ */
64 PAGE_READWRITE, /* WRITE */
65 PAGE_READWRITE, /* READ | WRITE */
66 PAGE_EXECUTE, /* EXEC */
67 PAGE_EXECUTE_READ, /* READ | EXEC */
68 PAGE_EXECUTE_READWRITE, /* WRITE | EXEC */
69 PAGE_EXECUTE_READWRITE, /* READ | WRITE | EXEC */
70 PAGE_WRITECOPY, /* WRITECOPY */
71 PAGE_WRITECOPY, /* READ | WRITECOPY */
72 PAGE_WRITECOPY, /* WRITE | WRITECOPY */
73 PAGE_WRITECOPY, /* READ | WRITE | WRITECOPY */
74 PAGE_EXECUTE_WRITECOPY, /* EXEC | WRITECOPY */
75 PAGE_EXECUTE_WRITECOPY, /* READ | EXEC | WRITECOPY */
76 PAGE_EXECUTE_WRITECOPY, /* WRITE | EXEC | WRITECOPY */
77 PAGE_EXECUTE_WRITECOPY /* READ | WRITE | EXEC | WRITECOPY */
81 static FILE_VIEW *VIRTUAL_FirstView;
83 static UINT32 page_shift;
84 static UINT32 page_mask;
85 static UINT32 granularity_mask; /* Allocation granularity (usually 64k) */
87 #define ROUND_ADDR(addr) \
88 ((UINT32)(addr) & ~page_mask)
90 #define ROUND_SIZE(addr,size) \
91 (((UINT32)(size) + ((UINT32)(addr) & page_mask) + page_mask) & ~page_mask)
94 /***********************************************************************
95 * VIRTUAL_GetProtStr
97 static const char *VIRTUAL_GetProtStr( BYTE prot )
99 static char buffer[6];
100 buffer[0] = (prot & VPROT_COMMITTED) ? 'c' : '-';
101 buffer[1] = (prot & VPROT_GUARD) ? 'g' : '-';
102 buffer[2] = (prot & VPROT_READ) ? 'r' : '-';
103 buffer[3] = (prot & VPROT_WRITE) ?
104 ((prot & VPROT_WRITECOPY) ? 'w' : 'W') : '-';
105 buffer[4] = (prot & VPROT_EXEC) ? 'x' : '-';
106 buffer[5] = 0;
107 return buffer;
111 /***********************************************************************
112 * VIRTUAL_DumpView
114 static void VIRTUAL_DumpView( FILE_VIEW *view )
116 UINT32 i, count;
117 UINT32 addr = view->base;
118 BYTE prot = view->prot[0];
120 fprintf( stderr, "View: %08x - %08x%s",
121 view->base, view->base + view->size - 1,
122 (view->flags & VFLAG_SYSTEM) ? " (system)" : "" );
123 if (view->mapping && view->mapping->file)
124 fprintf( stderr, " %s @ %08x\n",
125 view->mapping->file->unix_name, view->offset );
126 else
127 fprintf( stderr, " (anonymous)\n");
129 for (count = i = 1; i < view->size >> page_shift; i++, count++)
131 if (view->prot[i] == prot) continue;
132 fprintf( stderr, " %08x - %08x %s\n",
133 addr, addr + (count << page_shift) - 1,
134 VIRTUAL_GetProtStr(prot) );
135 addr += (count << page_shift);
136 prot = view->prot[i];
137 count = 0;
139 if (count)
140 fprintf( stderr, " %08x - %08x %s\n",
141 addr, addr + (count << page_shift) - 1,
142 VIRTUAL_GetProtStr(prot) );
146 /***********************************************************************
147 * VIRTUAL_Dump
149 void VIRTUAL_Dump(void)
151 FILE_VIEW *view = VIRTUAL_FirstView;
152 fprintf( stderr, "\nDump of all virtual memory views:\n\n" );
153 while (view)
155 VIRTUAL_DumpView( view );
156 view = view->next;
161 /***********************************************************************
162 * VIRTUAL_FindView
164 * Find the view containing a given address.
166 static FILE_VIEW *VIRTUAL_FindView( UINT32 addr )
168 FILE_VIEW *view = VIRTUAL_FirstView;
169 while (view)
171 if (view->base > addr) return NULL;
172 if (view->base + view->size > addr) return view;
173 view = view->next;
175 return NULL;
179 /***********************************************************************
180 * VIRTUAL_CreateView
182 * Create a new view and add it in the linked list.
184 static FILE_VIEW *VIRTUAL_CreateView( UINT32 base, UINT32 size, UINT32 offset,
185 UINT32 flags, BYTE vprot,
186 FILE_MAPPING *mapping )
188 FILE_VIEW *view, *prev;
190 /* Create the view structure */
192 size >>= page_shift;
193 if (!(view = (FILE_VIEW *)malloc( sizeof(*view) + size - 1 ))) return NULL;
194 view->base = base;
195 view->size = size << page_shift;
196 view->flags = flags;
197 view->offset = offset;
198 view->mapping = mapping;
199 view->protect = vprot;
200 memset( view->prot, vprot, size );
202 /* Insert it in the linked list */
204 if (!VIRTUAL_FirstView || (VIRTUAL_FirstView->base > base))
206 view->next = VIRTUAL_FirstView;
207 view->prev = NULL;
208 if (view->next) view->next->prev = view;
209 VIRTUAL_FirstView = view;
211 else
213 prev = VIRTUAL_FirstView;
214 while (prev->next && (prev->next->base < base)) prev = prev->next;
215 view->next = prev->next;
216 view->prev = prev;
217 if (view->next) view->next->prev = view;
218 prev->next = view;
220 if (debugging_virtual) VIRTUAL_DumpView( view );
221 return view;
225 /***********************************************************************
226 * VIRTUAL_DeleteView
228 * Delete an view.
230 static void VIRTUAL_DeleteView( FILE_VIEW *view )
232 munmap( (void *)view->base, view->size );
233 if (view->next) view->next->prev = view->prev;
234 if (view->prev) view->prev->next = view->next;
235 else VIRTUAL_FirstView = view->next;
236 if (view->mapping) K32OBJ_DecCount( &view->mapping->header );
237 free( view );
241 /***********************************************************************
242 * VIRTUAL_GetUnixProt
244 * Convert page protections to protection for mmap/mprotect.
246 static int VIRTUAL_GetUnixProt( BYTE vprot )
248 int prot = 0;
249 if ((vprot & VPROT_COMMITTED) && !(vprot & VPROT_GUARD))
251 if (vprot & VPROT_READ) prot |= PROT_READ;
252 if (vprot & VPROT_WRITE) prot |= PROT_WRITE;
253 if (vprot & VPROT_EXEC) prot |= PROT_EXEC;
255 return prot;
259 /***********************************************************************
260 * VIRTUAL_GetWin32Prot
262 * Convert page protections to Win32 flags.
264 static void VIRTUAL_GetWin32Prot( BYTE vprot, DWORD *protect, DWORD *state )
266 *protect = VIRTUAL_Win32Flags[vprot & 0x0f];
267 if (vprot & VPROT_GUARD) *protect |= PAGE_GUARD;
268 if (vprot & VPROT_NOCACHE) *protect |= PAGE_NOCACHE;
270 if (state) *state = (vprot & VPROT_COMMITTED) ? MEM_COMMIT : MEM_RESERVE;
274 /***********************************************************************
275 * VIRTUAL_GetProt
277 * Build page protections from Win32 flags.
279 static BYTE VIRTUAL_GetProt( DWORD protect )
281 BYTE vprot;
283 switch(protect & 0xff)
285 case PAGE_READONLY:
286 vprot = VPROT_READ;
287 break;
288 case PAGE_READWRITE:
289 vprot = VPROT_READ | VPROT_WRITE;
290 break;
291 case PAGE_WRITECOPY:
292 vprot = VPROT_READ | VPROT_WRITE | VPROT_WRITECOPY;
293 break;
294 case PAGE_EXECUTE:
295 vprot = VPROT_EXEC;
296 break;
297 case PAGE_EXECUTE_READ:
298 vprot = VPROT_EXEC | VPROT_READ;
299 break;
300 case PAGE_EXECUTE_READWRITE:
301 vprot = VPROT_EXEC | VPROT_READ | VPROT_WRITE | VPROT_WRITECOPY;
302 break;
303 case PAGE_EXECUTE_WRITECOPY:
304 vprot = VPROT_EXEC | VPROT_READ | VPROT_WRITE;
305 break;
306 case PAGE_NOACCESS:
307 default:
308 vprot = 0;
309 break;
311 if (protect & PAGE_GUARD) vprot |= VPROT_GUARD;
312 if (protect & PAGE_NOCACHE) vprot |= VPROT_NOCACHE;
313 return vprot;
317 /***********************************************************************
318 * VIRTUAL_SetProt
320 * Change the protection of a range of pages.
322 static BOOL32 VIRTUAL_SetProt( FILE_VIEW *view, UINT32 base,
323 UINT32 size, BYTE vprot )
325 dprintf_virtual( stddeb, "VIRTUAL_SetProt: %08x-%08x %s\n",
326 base, base + size - 1, VIRTUAL_GetProtStr( vprot ) );
328 if (mprotect( (void *)base, size, VIRTUAL_GetUnixProt(vprot) ))
329 return FALSE; /* FIXME: last error */
331 memset( view->prot + ((base - view->base) >> page_shift),
332 vprot, size >> page_shift );
333 if (debugging_virtual) VIRTUAL_DumpView( view );
334 return TRUE;
338 /***********************************************************************
339 * VIRTUAL_CheckFlags
341 * Check that all pages in a range have the given flags.
343 static BOOL32 VIRTUAL_CheckFlags( UINT32 base, UINT32 size, BYTE flags )
345 FILE_VIEW *view;
346 UINT32 page;
348 if (!size) return TRUE;
349 if (!(view = VIRTUAL_FindView( base ))) return FALSE;
350 if (view->base + view->size < base + size) return FALSE;
351 page = (base - view->base) >> page_shift;
352 size = ROUND_SIZE( base, size ) >> page_shift;
353 while (size--) if ((view->prot[page++] & flags) != flags) return FALSE;
354 return TRUE;
358 /***********************************************************************
359 * VIRTUAL_Init
361 BOOL32 VIRTUAL_Init(void)
363 SYSTEM_INFO sysinfo;
364 GetSystemInfo( &sysinfo );
366 page_mask = sysinfo.dwPageSize - 1;
367 granularity_mask = sysinfo.dwAllocationGranularity - 1;
368 /* Make sure we have a power of 2 */
369 assert( !(sysinfo.dwPageSize & page_mask) );
370 assert( !(sysinfo.dwAllocationGranularity & granularity_mask) );
371 page_shift = 0;
372 while ((1 << page_shift) != sysinfo.dwPageSize) page_shift++;
374 #ifdef linux
376 FILE *f = fopen( "/proc/self/maps", "r" );
377 if (f)
379 char buffer[80];
380 while (fgets( buffer, sizeof(buffer), f ))
382 int start, end, offset;
383 char r, w, x, p;
384 BYTE vprot = VPROT_COMMITTED;
386 sscanf( buffer, "%x-%x %c%c%c%c %x",
387 &start, &end, &r, &w, &x, &p, &offset );
388 if (r == 'r') vprot |= VPROT_READ;
389 if (w == 'w') vprot |= VPROT_WRITE;
390 if (x == 'x') vprot |= VPROT_EXEC;
391 if (p == 'p') vprot |= VPROT_WRITECOPY;
392 VIRTUAL_CreateView( start, end - start, 0,
393 VFLAG_SYSTEM, vprot, NULL );
395 fclose( f );
398 #endif /* linux */
399 return TRUE;
403 /***********************************************************************
404 * VirtualAlloc (KERNEL32.548)
406 LPVOID VirtualAlloc( LPVOID addr, DWORD size, DWORD type, DWORD protect )
408 FILE_VIEW *view;
409 UINT32 base, ptr, view_size;
410 BYTE vprot;
412 dprintf_virtual( stddeb, "VirtualAlloc: %08x %08lx %lx %08lx\n",
413 (UINT32)addr, size, type, protect );
415 /* Round parameters to a page boundary */
417 if (size > 0x7fc00000) /* 2Gb - 4Mb */
419 SetLastError( ERROR_OUTOFMEMORY );
420 return NULL;
422 if (addr)
424 if (type & MEM_RESERVE) /* Round down to 64k boundary */
425 base = ((UINT32)addr + granularity_mask) & ~granularity_mask;
426 else
427 base = ROUND_ADDR( addr );
428 size = (((UINT32)addr + size + page_mask) & ~page_mask) - base;
429 if (base + size < base) /* Disallow wrap-around */
431 SetLastError( ERROR_INVALID_PARAMETER );
432 return NULL;
435 else
437 base = 0;
438 size = (size + page_mask) & ~page_mask;
441 /* Compute the protection flags */
443 if (!(type & (MEM_COMMIT | MEM_RESERVE)) ||
444 (type & ~(MEM_COMMIT | MEM_RESERVE)))
446 SetLastError( ERROR_INVALID_PARAMETER );
447 return NULL;
449 if (type & MEM_COMMIT)
450 vprot = VIRTUAL_GetProt( protect ) | VPROT_COMMITTED;
451 else vprot = 0;
453 /* Reserve the memory */
455 if ((type & MEM_RESERVE) || !base)
457 view_size = size + (base ? 0 : granularity_mask + 1);
458 ptr = (UINT32)FILE_mmap( NULL, (LPVOID)base, 0, view_size, 0, 0,
459 VIRTUAL_GetUnixProt( vprot ), MAP_PRIVATE );
460 if (ptr == (UINT32)-1)
462 SetLastError( ERROR_OUTOFMEMORY );
463 return NULL;
465 if (!base)
467 /* Release the extra memory while keeping the range */
468 /* starting on a 64k boundary. */
470 if (ptr & granularity_mask)
472 UINT32 extra = granularity_mask + 1 - (ptr & granularity_mask);
473 munmap( (void *)ptr, extra );
474 ptr += extra;
475 view_size -= extra;
477 if (view_size > size)
478 munmap( (void *)(ptr + size), view_size - size );
480 if (!(view = VIRTUAL_CreateView( ptr, size, 0, 0, vprot, NULL )))
482 munmap( (void *)ptr, size );
483 SetLastError( ERROR_OUTOFMEMORY );
484 return NULL;
486 if (debugging_virtual) VIRTUAL_DumpView( view );
487 return (LPVOID)ptr;
490 /* Commit the pages */
492 if (!(view = VIRTUAL_FindView( base )) ||
493 (base + size > view->base + view->size))
495 SetLastError( ERROR_INVALID_PARAMETER );
496 return NULL;
499 if (!VIRTUAL_SetProt( view, base, size, vprot )) return NULL;
500 return (LPVOID)base;
504 /***********************************************************************
505 * VirtualFree (KERNEL32.550)
507 BOOL32 VirtualFree( LPVOID addr, DWORD size, DWORD type )
509 FILE_VIEW *view;
510 UINT32 base;
512 dprintf_virtual( stddeb, "VirtualFree: %08x %08lx %lx\n",
513 (UINT32)addr, size, type );
515 /* Fix the parameters */
517 size = ROUND_SIZE( addr, size );
518 base = ROUND_ADDR( addr );
520 if (!(view = VIRTUAL_FindView( base )) ||
521 (base + size > view->base + view->size))
523 SetLastError( ERROR_INVALID_PARAMETER );
524 return FALSE;
527 /* Compute the protection flags */
529 if ((type != MEM_DECOMMIT) && (type != MEM_RELEASE))
531 SetLastError( ERROR_INVALID_PARAMETER );
532 return FALSE;
535 /* Free the pages */
537 if (type == MEM_RELEASE)
539 if (size || (base != view->base))
541 SetLastError( ERROR_INVALID_PARAMETER );
542 return FALSE;
544 VIRTUAL_DeleteView( view );
545 return TRUE;
548 /* Decommit the pages */
550 return VIRTUAL_SetProt( view, base, size, 0 );
554 /***********************************************************************
555 * VirtualLock (KERNEL32.551)
557 BOOL32 VirtualLock( LPVOID addr, DWORD size )
559 return TRUE;
563 /***********************************************************************
564 * VirtualUnlock (KERNEL32.556)
566 BOOL32 VirtualUnlock( LPVOID addr, DWORD size )
568 return TRUE;
572 /***********************************************************************
573 * VirtualProtect (KERNEL32.552)
575 BOOL32 VirtualProtect( LPVOID addr, DWORD size, DWORD new_prot,
576 LPDWORD old_prot )
578 FILE_VIEW *view;
579 UINT32 base, i;
580 BYTE vprot, *p;
582 dprintf_virtual( stddeb, "VirtualProtect: %08x %08lx %08lx\n",
583 (UINT32)addr, size, new_prot );
585 /* Fix the parameters */
587 size = ROUND_SIZE( addr, size );
588 base = ROUND_ADDR( addr );
590 if (!(view = VIRTUAL_FindView( base )) ||
591 (base + size > view->base + view->size))
593 SetLastError( ERROR_INVALID_PARAMETER );
594 return FALSE;
597 /* Make sure all the pages are committed */
599 p = view->prot + ((base - view->base) >> page_shift);
600 for (i = size >> page_shift; i; i--, p++)
602 if (!(*p & VPROT_COMMITTED))
604 SetLastError( ERROR_INVALID_PARAMETER );
605 return FALSE;
609 VIRTUAL_GetWin32Prot( view->prot[0], old_prot, NULL );
610 vprot = VIRTUAL_GetProt( new_prot ) | VPROT_COMMITTED;
611 return VIRTUAL_SetProt( view, base, size, vprot );
615 /***********************************************************************
616 * VirtualProtectEx (KERNEL32.553)
618 BOOL32 VirtualProtectEx( HANDLE32 handle, LPVOID addr, DWORD size,
619 DWORD new_prot, LPDWORD old_prot )
621 BOOL32 ret = FALSE;
623 PDB32 *pdb = (PDB32 *)PROCESS_GetObjPtr( handle, K32OBJ_PROCESS );
624 if (pdb)
626 if (pdb == pCurrentProcess)
627 ret = VirtualProtect( addr, size, new_prot, old_prot );
628 else
629 fprintf(stderr,"Unsupported: VirtualProtectEx on other process\n");
630 K32OBJ_DecCount( &pdb->header );
632 return ret;
636 /***********************************************************************
637 * VirtualQuery (KERNEL32.554)
639 BOOL32 VirtualQuery( LPCVOID addr, LPMEMORY_BASIC_INFORMATION info, DWORD len )
641 FILE_VIEW *view = VIRTUAL_FirstView;
642 UINT32 base = ROUND_ADDR( addr );
643 UINT32 alloc_base = 0;
644 UINT32 size = 0;
646 /* Find the view containing the address */
648 for (;;)
650 if (!view)
652 size = 0xffff0000 - alloc_base;
653 break;
655 if (view->base > base)
657 size = view->base - alloc_base;
658 view = NULL;
659 break;
661 if (view->base + view->size > base)
663 alloc_base = view->base;
664 size = view->size;
665 break;
667 alloc_base = view->base + view->size;
668 view = view->next;
671 /* Fill the info structure */
673 if (!view)
675 info->State = MEM_FREE;
676 info->Protect = 0;
677 info->AllocationProtect = 0;
678 info->Type = 0;
680 else
682 BYTE vprot = view->prot[(base - alloc_base) >> page_shift];
683 VIRTUAL_GetWin32Prot( vprot, &info->Protect, &info->State );
684 for (size = base - alloc_base; size < view->size; size += page_mask+1)
685 if (view->prot[size >> page_shift] != vprot) break;
686 info->AllocationProtect = view->protect;
687 info->Type = MEM_PRIVATE; /* FIXME */
690 info->BaseAddress = (LPVOID)base;
691 info->AllocationBase = (LPVOID)alloc_base;
692 info->RegionSize = size - (base - alloc_base);
693 return TRUE;
697 /***********************************************************************
698 * VirtualQueryEx (KERNEL32.555)
700 BOOL32 VirtualQueryEx( HANDLE32 handle, LPCVOID addr,
701 LPMEMORY_BASIC_INFORMATION info, DWORD len )
703 BOOL32 ret = FALSE;
705 PDB32 *pdb = (PDB32 *)PROCESS_GetObjPtr( handle, K32OBJ_PROCESS );
706 if (pdb)
708 if (pdb == pCurrentProcess)
709 ret = VirtualQuery( addr, info, len );
710 else
711 fprintf(stderr,"Unsupported: VirtualQueryEx on other process\n");
712 K32OBJ_DecCount( &pdb->header );
714 return ret;
718 /***********************************************************************
719 * IsBadReadPtr32 (KERNEL32.354)
721 BOOL32 IsBadReadPtr32( LPCVOID ptr, UINT32 size )
723 return !VIRTUAL_CheckFlags( (UINT32)ptr, size,
724 VPROT_READ | VPROT_COMMITTED );
728 /***********************************************************************
729 * IsBadWritePtr32 (KERNEL32.357)
731 BOOL32 IsBadWritePtr32( LPVOID ptr, UINT32 size )
733 return !VIRTUAL_CheckFlags( (UINT32)ptr, size,
734 VPROT_WRITE | VPROT_COMMITTED );
738 /***********************************************************************
739 * IsBadHugeReadPtr32 (KERNEL32.352)
741 BOOL32 IsBadHugeReadPtr32( LPCVOID ptr, UINT32 size )
743 return IsBadReadPtr32( ptr, size );
747 /***********************************************************************
748 * IsBadHugeWritePtr32 (KERNEL32.353)
750 BOOL32 IsBadHugeWritePtr32( LPVOID ptr, UINT32 size )
752 return IsBadWritePtr32( ptr, size );
756 /***********************************************************************
757 * IsBadCodePtr32 (KERNEL32.351)
759 BOOL32 IsBadCodePtr32( FARPROC32 ptr )
761 return !VIRTUAL_CheckFlags( (UINT32)ptr, 1, VPROT_EXEC | VPROT_COMMITTED );
765 /***********************************************************************
766 * IsBadStringPtr32A (KERNEL32.355)
768 BOOL32 IsBadStringPtr32A( LPCSTR str, UINT32 max )
770 FILE_VIEW *view;
771 UINT32 page, count;
773 if (!max) return FALSE;
774 if (!(view = VIRTUAL_FindView( (UINT32)str ))) return TRUE;
775 page = ((UINT32)str - view->base) >> page_shift;
776 count = page_mask + 1 - ((UINT32)str & page_mask);
778 while (max)
780 if ((view->prot[page] & (VPROT_READ | VPROT_COMMITTED)) !=
781 (VPROT_READ | VPROT_COMMITTED))
782 return TRUE;
783 if (count > max) count = max;
784 max -= count;
785 while (count--) if (!*str++) return FALSE;
786 if (++page >= view->size >> page_shift) return TRUE;
787 count = page_mask + 1;
789 return FALSE;
793 /***********************************************************************
794 * IsBadStringPtr32W (KERNEL32.356)
796 BOOL32 IsBadStringPtr32W( LPCWSTR str, UINT32 max )
798 FILE_VIEW *view;
799 UINT32 page, count;
801 if (!max) return FALSE;
802 if (!(view = VIRTUAL_FindView( (UINT32)str ))) return TRUE;
803 page = ((UINT32)str - view->base) >> page_shift;
804 count = (page_mask + 1 - ((UINT32)str & page_mask)) / sizeof(WCHAR);
806 while (max)
808 if ((view->prot[page] & (VPROT_READ | VPROT_COMMITTED)) !=
809 (VPROT_READ | VPROT_COMMITTED))
810 return TRUE;
811 if (count > max) count = max;
812 max -= count;
813 while (count--) if (!*str++) return FALSE;
814 if (++page >= view->size >> page_shift) return TRUE;
815 count = (page_mask + 1) / sizeof(WCHAR);
817 return FALSE;
821 /***********************************************************************
822 * CreateFileMapping32A (KERNEL32.46)
824 HANDLE32 CreateFileMapping32A( HFILE32 hFile, LPSECURITY_ATTRIBUTES attr,
825 DWORD protect, DWORD size_high, DWORD size_low,
826 LPCSTR name )
828 FILE_MAPPING *mapping = NULL;
829 HANDLE32 handle;
830 BYTE vprot;
832 /* First search for an object with the same name */
834 K32OBJ *obj = K32OBJ_FindName( name );
835 if (obj)
837 if (obj->type == K32OBJ_MEM_MAPPED_FILE)
839 SetLastError( ERROR_ALREADY_EXISTS );
840 return PROCESS_AllocHandle( obj, 0 );
842 SetLastError( ERROR_DUP_NAME );
843 return 0;
846 /* Check parameters */
848 dprintf_virtual(stddeb,"CreateFileMapping32A(%x,%p,%08lx,%08lx%08lx,%s)\n",
849 hFile, attr, protect, size_high, size_low, name );
851 vprot = VIRTUAL_GetProt( protect );
852 if (protect & SEC_RESERVE)
854 if (hFile != INVALID_HANDLE_VALUE32)
856 SetLastError( ERROR_INVALID_PARAMETER );
857 return 0;
860 else vprot |= VPROT_COMMITTED;
861 if (protect & SEC_NOCACHE) vprot |= VPROT_NOCACHE;
863 /* Compute the size and extend the file if necessary */
865 if (hFile == INVALID_HANDLE_VALUE32)
867 if (!size_high && !size_low)
869 SetLastError( ERROR_INVALID_PARAMETER );
870 return 0;
872 obj = NULL;
874 else /* We have a file */
876 BY_HANDLE_FILE_INFORMATION info;
877 if (!(obj = PROCESS_GetObjPtr( hFile, K32OBJ_FILE ))) goto error;
878 /* FIXME: should check if the file permissions agree
879 * with the required protection flags */
880 if (!GetFileInformationByHandle( hFile, &info )) goto error;
881 if (!size_high && !size_low)
883 size_high = info.nFileSizeHigh;
884 size_low = info.nFileSizeLow;
886 else if ((size_high > info.nFileSizeHigh) ||
887 ((size_high == info.nFileSizeHigh) &&
888 (size_low > info.nFileSizeLow)))
890 /* We have to grow the file */
891 if (SetFilePointer( hFile, size_low, &size_high,
892 FILE_BEGIN ) == 0xffffffff) goto error;
893 if (!SetEndOfFile( hFile )) goto error;
897 /* Allocate the mapping object */
899 if (!(mapping = HeapAlloc( SystemHeap, 0, sizeof(*mapping) ))) goto error;
900 mapping->header.type = K32OBJ_MEM_MAPPED_FILE;
901 mapping->header.refcount = 1;
902 mapping->protect = vprot;
903 mapping->size_high = size_high;
904 mapping->size_low = ROUND_SIZE( 0, size_low );
905 mapping->file = (FILE_OBJECT *)obj;
907 handle = PROCESS_AllocHandle( &mapping->header, 0 );
908 if (handle != INVALID_HANDLE_VALUE32) return handle;
910 error:
911 if (obj) K32OBJ_DecCount( obj );
912 if (mapping) HeapFree( SystemHeap, 0, mapping );
913 return 0;
917 /***********************************************************************
918 * CreateFileMapping32W (KERNEL32.47)
920 HANDLE32 CreateFileMapping32W( HFILE32 hFile, LPSECURITY_ATTRIBUTES attr,
921 DWORD protect, DWORD size_high, DWORD size_low,
922 LPCWSTR name )
924 LPSTR nameA = HEAP_strdupWtoA( GetProcessHeap(), 0, name );
925 HANDLE32 ret = CreateFileMapping32A( hFile, attr, protect,
926 size_high, size_low, nameA );
927 HeapFree( GetProcessHeap(), 0, nameA );
928 return ret;
932 /***********************************************************************
933 * OpenFileMapping32A (KERNEL32.397)
935 HANDLE32 OpenFileMapping32A( DWORD access, BOOL32 inherit, LPCSTR name )
937 K32OBJ *obj = K32OBJ_FindNameType( name, K32OBJ_MEM_MAPPED_FILE );
938 if (!obj) return 0;
939 return PROCESS_AllocHandle( obj, 0 );
943 /***********************************************************************
944 * OpenFileMapping32W (KERNEL32.398)
946 HANDLE32 OpenFileMapping32W( DWORD access, BOOL32 inherit, LPCWSTR name )
948 LPSTR nameA = HEAP_strdupWtoA( GetProcessHeap(), 0, name );
949 HANDLE32 ret = OpenFileMapping32A( access, inherit, nameA );
950 HeapFree( GetProcessHeap(), 0, nameA );
951 return ret;
955 /***********************************************************************
956 * VIRTUAL_DestroyMapping
958 * Destroy a FILE_MAPPING object.
960 void VIRTUAL_DestroyMapping( K32OBJ *ptr )
962 FILE_MAPPING *mapping = (FILE_MAPPING *)ptr;
963 assert( ptr->type == K32OBJ_MEM_MAPPED_FILE );
965 if (mapping->file) K32OBJ_DecCount( &mapping->file->header );
966 ptr->type = K32OBJ_UNKNOWN;
967 HeapFree( SystemHeap, 0, mapping );
971 /***********************************************************************
972 * MapViewOfFile (KERNEL32.385)
974 LPVOID MapViewOfFile( HANDLE32 mapping, DWORD access, DWORD offset_high,
975 DWORD offset_low, DWORD count )
977 return MapViewOfFileEx( mapping, access, offset_high,
978 offset_low, count, NULL );
982 /***********************************************************************
983 * MapViewOfFileEx (KERNEL32.386)
985 LPVOID MapViewOfFileEx( HANDLE32 handle, DWORD access, DWORD offset_high,
986 DWORD offset_low, DWORD count, LPVOID addr )
988 FILE_MAPPING *mapping;
989 FILE_VIEW *view;
990 UINT32 ptr = (UINT32)-1, size = 0;
991 int flags = MAP_PRIVATE;
993 /* Check parameters */
995 if ((offset_low & granularity_mask) ||
996 (addr && ((UINT32)addr & granularity_mask)))
998 SetLastError( ERROR_INVALID_PARAMETER );
999 return NULL;
1002 if (!(mapping = (FILE_MAPPING *)PROCESS_GetObjPtr( handle,
1003 K32OBJ_MEM_MAPPED_FILE )))
1004 return NULL;
1006 if (mapping->size_high || offset_high)
1007 fprintf( stderr, "MapViewOfFileEx: offsets larger than 4Gb not supported\n");
1009 if ((offset_low >= mapping->size_low) ||
1010 (count > mapping->size_low - offset_low))
1012 SetLastError( ERROR_INVALID_PARAMETER );
1013 goto error;
1015 if (count) size = ROUND_SIZE( offset_low, count );
1016 else size = mapping->size_low - offset_low;
1018 switch(access)
1020 case FILE_MAP_ALL_ACCESS:
1021 case FILE_MAP_WRITE:
1022 case FILE_MAP_WRITE | FILE_MAP_READ:
1023 if (!(mapping->protect & VPROT_WRITE))
1025 SetLastError( ERROR_INVALID_PARAMETER );
1026 goto error;
1028 flags = MAP_SHARED;
1029 /* fall through */
1030 case FILE_MAP_READ:
1031 case FILE_MAP_COPY:
1032 case FILE_MAP_COPY | FILE_MAP_READ:
1033 if (mapping->protect & VPROT_READ) break;
1034 /* fall through */
1035 default:
1036 SetLastError( ERROR_INVALID_PARAMETER );
1037 goto error;
1040 /* Map the file */
1042 dprintf_virtual( stddeb, "MapViewOfFile: handle=%x size=%x offset=%lx\n",
1043 handle, size, offset_low );
1045 ptr = (UINT32)FILE_mmap( mapping->file, addr, 0, size, 0, offset_low,
1046 VIRTUAL_GetUnixProt( mapping->protect ),
1047 flags );
1048 if (ptr == (UINT32)-1)
1050 SetLastError( ERROR_OUTOFMEMORY );
1051 goto error;
1054 if (!(view = VIRTUAL_CreateView( ptr, size, offset_low, 0,
1055 mapping->protect, mapping )))
1057 SetLastError( ERROR_OUTOFMEMORY );
1058 goto error;
1060 return (LPVOID)ptr;
1062 error:
1063 if (ptr != (UINT32)-1) munmap( (void *)ptr, size );
1064 K32OBJ_DecCount( &mapping->header );
1065 return NULL;
1069 /***********************************************************************
1070 * UnmapViewOfFile (KERNEL32.540)
1072 BOOL32 UnmapViewOfFile( LPVOID addr )
1074 FILE_VIEW *view;
1075 UINT32 base = ROUND_ADDR( addr );
1076 if (!(view = VIRTUAL_FindView( base )) || (base != view->base))
1078 SetLastError( ERROR_INVALID_PARAMETER );
1079 return FALSE;
1081 VIRTUAL_DeleteView( view );
1082 return TRUE;