Ignore RBBS_BREAK style on first band.
[wine.git] / memory / virtual.c
blob2ebc1175d035d19e9dbdf302f35cff173a4cf8a8
1 /*
2 * Win32 virtual memory functions
4 * Copyright 1997 Alexandre Julliard
5 */
7 #include "config.h"
9 #include <assert.h>
10 #include <errno.h>
11 #ifdef HAVE_SYS_ERRNO_H
12 #include <sys/errno.h>
13 #endif
14 #include <fcntl.h>
15 #include <unistd.h>
16 #include <stdlib.h>
17 #include <stdio.h>
18 #include <string.h>
19 #include <sys/types.h>
20 #ifdef HAVE_SYS_MMAN_H
21 #include <sys/mman.h>
22 #endif
23 #include "winnls.h"
24 #include "winbase.h"
25 #include "wine/exception.h"
26 #include "wine/unicode.h"
27 #include "winerror.h"
28 #include "file.h"
29 #include "process.h"
30 #include "global.h"
31 #include "server.h"
32 #include "debugtools.h"
34 DEFAULT_DEBUG_CHANNEL(virtual);
35 DECLARE_DEBUG_CHANNEL(module);
37 #ifndef MS_SYNC
38 #define MS_SYNC 0
39 #endif
41 /* File view */
42 typedef struct _FV
44 struct _FV *next; /* Next view */
45 struct _FV *prev; /* Prev view */
46 UINT base; /* Base address */
47 UINT size; /* Size in bytes */
48 UINT flags; /* Allocation flags */
49 HANDLE mapping; /* Handle to the file mapping */
50 HANDLERPROC handlerProc; /* Fault handler */
51 LPVOID handlerArg; /* Fault handler argument */
52 BYTE protect; /* Protection for all pages at allocation time */
53 BYTE prot[1]; /* Protection byte for each page */
54 } FILE_VIEW;
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;
82 static CRITICAL_SECTION csVirtual = CRITICAL_SECTION_INIT;
84 #ifdef __i386__
85 /* These are always the same on an i386, and it will be faster this way */
86 # define page_mask 0xfff
87 # define page_shift 12
88 # define page_size 0x1000
89 #else
90 static UINT page_shift;
91 static UINT page_mask;
92 static UINT page_size;
93 #endif /* __i386__ */
94 #define granularity_mask 0xffff /* Allocation granularity (usually 64k) */
96 #define ROUND_ADDR(addr) \
97 ((UINT)(addr) & ~page_mask)
99 #define ROUND_SIZE(addr,size) \
100 (((UINT)(size) + ((UINT)(addr) & page_mask) + page_mask) & ~page_mask)
102 #define VIRTUAL_DEBUG_DUMP_VIEW(view) \
103 if (!TRACE_ON(virtual)); else VIRTUAL_DumpView(view)
106 /* filter for page-fault exceptions */
107 static WINE_EXCEPTION_FILTER(page_fault)
109 if (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION)
110 return EXCEPTION_EXECUTE_HANDLER;
111 return EXCEPTION_CONTINUE_SEARCH;
114 /***********************************************************************
115 * VIRTUAL_GetProtStr
117 static const char *VIRTUAL_GetProtStr( BYTE prot )
119 static char buffer[6];
120 buffer[0] = (prot & VPROT_COMMITTED) ? 'c' : '-';
121 buffer[1] = (prot & VPROT_GUARD) ? 'g' : '-';
122 buffer[2] = (prot & VPROT_READ) ? 'r' : '-';
123 buffer[3] = (prot & VPROT_WRITE) ?
124 ((prot & VPROT_WRITECOPY) ? 'w' : 'W') : '-';
125 buffer[4] = (prot & VPROT_EXEC) ? 'x' : '-';
126 buffer[5] = 0;
127 return buffer;
131 /***********************************************************************
132 * VIRTUAL_DumpView
134 static void VIRTUAL_DumpView( FILE_VIEW *view )
136 UINT i, count;
137 UINT addr = view->base;
138 BYTE prot = view->prot[0];
140 DPRINTF( "View: %08x - %08x%s",
141 view->base, view->base + view->size - 1,
142 (view->flags & VFLAG_SYSTEM) ? " (system)" : "" );
143 if (view->mapping)
144 DPRINTF( " %d\n", view->mapping );
145 else
146 DPRINTF( " (anonymous)\n");
148 for (count = i = 1; i < view->size >> page_shift; i++, count++)
150 if (view->prot[i] == prot) continue;
151 DPRINTF( " %08x - %08x %s\n",
152 addr, addr + (count << page_shift) - 1,
153 VIRTUAL_GetProtStr(prot) );
154 addr += (count << page_shift);
155 prot = view->prot[i];
156 count = 0;
158 if (count)
159 DPRINTF( " %08x - %08x %s\n",
160 addr, addr + (count << page_shift) - 1,
161 VIRTUAL_GetProtStr(prot) );
165 /***********************************************************************
166 * VIRTUAL_Dump
168 void VIRTUAL_Dump(void)
170 FILE_VIEW *view;
171 DPRINTF( "\nDump of all virtual memory views:\n\n" );
172 EnterCriticalSection(&csVirtual);
173 view = VIRTUAL_FirstView;
174 while (view)
176 VIRTUAL_DumpView( view );
177 view = view->next;
179 LeaveCriticalSection(&csVirtual);
183 /***********************************************************************
184 * VIRTUAL_FindView
186 * Find the view containing a given address.
188 * RETURNS
189 * View: Success
190 * NULL: Failure
192 static FILE_VIEW *VIRTUAL_FindView(
193 UINT addr /* [in] Address */
195 FILE_VIEW *view;
197 EnterCriticalSection(&csVirtual);
198 view = VIRTUAL_FirstView;
199 while (view)
201 if (view->base > addr)
203 view = NULL;
204 break;
206 if (view->base + view->size > addr) break;
207 view = view->next;
209 LeaveCriticalSection(&csVirtual);
210 return view;
214 /***********************************************************************
215 * VIRTUAL_CreateView
217 * Create a new view and add it in the linked list.
219 static FILE_VIEW *VIRTUAL_CreateView( UINT base, UINT size, UINT flags,
220 BYTE vprot, HANDLE mapping )
222 FILE_VIEW *view, *prev;
224 /* Create the view structure */
226 assert( !(base & page_mask) );
227 assert( !(size & page_mask) );
228 size >>= page_shift;
229 if (!(view = (FILE_VIEW *)malloc( sizeof(*view) + size - 1 ))) return NULL;
230 view->base = base;
231 view->size = size << page_shift;
232 view->flags = flags;
233 view->mapping = mapping;
234 view->protect = vprot;
235 view->handlerProc = NULL;
236 memset( view->prot, vprot, size );
238 /* Duplicate the mapping handle */
240 if ((view->mapping != -1) &&
241 !DuplicateHandle( GetCurrentProcess(), view->mapping,
242 GetCurrentProcess(), &view->mapping,
243 0, FALSE, DUPLICATE_SAME_ACCESS ))
245 free( view );
246 return NULL;
249 /* Insert it in the linked list */
251 EnterCriticalSection(&csVirtual);
252 if (!VIRTUAL_FirstView || (VIRTUAL_FirstView->base > base))
254 view->next = VIRTUAL_FirstView;
255 view->prev = NULL;
256 if (view->next) view->next->prev = view;
257 VIRTUAL_FirstView = view;
259 else
261 prev = VIRTUAL_FirstView;
262 while (prev->next && (prev->next->base < base)) prev = prev->next;
263 view->next = prev->next;
264 view->prev = prev;
265 if (view->next) view->next->prev = view;
266 prev->next = view;
268 LeaveCriticalSection(&csVirtual);
269 VIRTUAL_DEBUG_DUMP_VIEW( view );
270 return view;
274 /***********************************************************************
275 * VIRTUAL_DeleteView
276 * Deletes a view.
278 * RETURNS
279 * None
281 static void VIRTUAL_DeleteView(
282 FILE_VIEW *view /* [in] View */
284 if (!(view->flags & VFLAG_SYSTEM))
285 munmap( (void *)view->base, view->size );
286 EnterCriticalSection(&csVirtual);
287 if (view->next) view->next->prev = view->prev;
288 if (view->prev) view->prev->next = view->next;
289 else VIRTUAL_FirstView = view->next;
290 LeaveCriticalSection(&csVirtual);
291 if (view->mapping) CloseHandle( view->mapping );
292 free( view );
296 /***********************************************************************
297 * VIRTUAL_GetUnixProt
299 * Convert page protections to protection for mmap/mprotect.
301 static int VIRTUAL_GetUnixProt( BYTE vprot )
303 int prot = 0;
304 if ((vprot & VPROT_COMMITTED) && !(vprot & VPROT_GUARD))
306 if (vprot & VPROT_READ) prot |= PROT_READ;
307 if (vprot & VPROT_WRITE) prot |= PROT_WRITE;
308 if (vprot & VPROT_WRITECOPY) prot |= PROT_WRITE;
309 if (vprot & VPROT_EXEC) prot |= PROT_EXEC;
311 return prot;
315 /***********************************************************************
316 * VIRTUAL_GetWin32Prot
318 * Convert page protections to Win32 flags.
320 * RETURNS
321 * None
323 static void VIRTUAL_GetWin32Prot(
324 BYTE vprot, /* [in] Page protection flags */
325 DWORD *protect, /* [out] Location to store Win32 protection flags */
326 DWORD *state /* [out] Location to store mem state flag */
328 if (protect) {
329 *protect = VIRTUAL_Win32Flags[vprot & 0x0f];
330 /* if (vprot & VPROT_GUARD) *protect |= PAGE_GUARD;*/
331 if (vprot & VPROT_NOCACHE) *protect |= PAGE_NOCACHE;
333 if (vprot & VPROT_GUARD) *protect = PAGE_NOACCESS;
336 if (state) *state = (vprot & VPROT_COMMITTED) ? MEM_COMMIT : MEM_RESERVE;
340 /***********************************************************************
341 * VIRTUAL_GetProt
343 * Build page protections from Win32 flags.
345 * RETURNS
346 * Value of page protection flags
348 static BYTE VIRTUAL_GetProt(
349 DWORD protect /* [in] Win32 protection flags */
351 BYTE vprot;
353 switch(protect & 0xff)
355 case PAGE_READONLY:
356 vprot = VPROT_READ;
357 break;
358 case PAGE_READWRITE:
359 vprot = VPROT_READ | VPROT_WRITE;
360 break;
361 case PAGE_WRITECOPY:
362 vprot = VPROT_READ | VPROT_WRITE | VPROT_WRITECOPY;
363 break;
364 case PAGE_EXECUTE:
365 vprot = VPROT_EXEC;
366 break;
367 case PAGE_EXECUTE_READ:
368 vprot = VPROT_EXEC | VPROT_READ;
369 break;
370 case PAGE_EXECUTE_READWRITE:
371 vprot = VPROT_EXEC | VPROT_READ | VPROT_WRITE;
372 break;
373 case PAGE_EXECUTE_WRITECOPY:
374 vprot = VPROT_EXEC | VPROT_READ | VPROT_WRITE | VPROT_WRITECOPY;
375 break;
376 case PAGE_NOACCESS:
377 default:
378 vprot = 0;
379 break;
381 if (protect & PAGE_GUARD) vprot |= VPROT_GUARD;
382 if (protect & PAGE_NOCACHE) vprot |= VPROT_NOCACHE;
383 return vprot;
387 /***********************************************************************
388 * VIRTUAL_SetProt
390 * Change the protection of a range of pages.
392 * RETURNS
393 * TRUE: Success
394 * FALSE: Failure
396 static BOOL VIRTUAL_SetProt(
397 FILE_VIEW *view, /* [in] Pointer to view */
398 UINT base, /* [in] Starting address */
399 UINT size, /* [in] Size in bytes */
400 BYTE vprot /* [in] Protections to use */
402 TRACE("%08x-%08x %s\n",
403 base, base + size - 1, VIRTUAL_GetProtStr( vprot ) );
405 if (mprotect( (void *)base, size, VIRTUAL_GetUnixProt(vprot) ))
406 return FALSE; /* FIXME: last error */
408 memset( view->prot + ((base - view->base) >> page_shift),
409 vprot, size >> page_shift );
410 VIRTUAL_DEBUG_DUMP_VIEW( view );
411 return TRUE;
415 /***********************************************************************
416 * map_image
418 * Map an executable (PE format) image into memory.
420 static LPVOID map_image( HANDLE hmapping, int fd, char *base, DWORD total_size,
421 DWORD header_size, HANDLE shared_file, DWORD shared_size )
423 IMAGE_DOS_HEADER *dos;
424 IMAGE_NT_HEADERS *nt;
425 IMAGE_SECTION_HEADER *sec;
426 int i, pos;
427 DWORD err = GetLastError();
428 FILE_VIEW *view = NULL;
429 char *ptr;
430 int shared_fd = -1;
432 SetLastError( ERROR_BAD_EXE_FORMAT ); /* generic error */
434 /* zero-map the whole range */
436 if ((ptr = VIRTUAL_mmap( -1, base, total_size, 0,
437 PROT_READ | PROT_WRITE | PROT_EXEC, 0 )) == (char *)-1)
439 ptr = VIRTUAL_mmap( -1, NULL, total_size, 0,
440 PROT_READ | PROT_WRITE | PROT_EXEC, 0 );
441 if (ptr == (char *)-1)
443 ERR_(module)("Not enough memory for module (%ld bytes)\n", total_size);
444 goto error;
447 TRACE_(module)( "mapped PE file at %p-%p\n", ptr, ptr + total_size );
449 if (!(view = VIRTUAL_CreateView( (UINT)ptr, total_size, 0,
450 VPROT_COMMITTED|VPROT_READ|VPROT_WRITE|VPROT_WRITECOPY,
451 hmapping )))
453 munmap( ptr, total_size );
454 SetLastError( ERROR_OUTOFMEMORY );
455 goto error;
458 /* map the header */
460 if (VIRTUAL_mmap( fd, ptr, header_size, 0, PROT_READ | PROT_WRITE,
461 MAP_PRIVATE | MAP_FIXED ) == (char *)-1) goto error;
462 dos = (IMAGE_DOS_HEADER *)ptr;
463 nt = (IMAGE_NT_HEADERS *)(ptr + dos->e_lfanew);
464 if ((char *)(nt + 1) > ptr + header_size) goto error;
466 sec = (IMAGE_SECTION_HEADER*)((char*)&nt->OptionalHeader+nt->FileHeader.SizeOfOptionalHeader);
467 if ((char *)(sec + nt->FileHeader.NumberOfSections) > ptr + header_size) goto error;
469 /* check the architecture */
471 if (nt->FileHeader.Machine != IMAGE_FILE_MACHINE_I386)
473 MESSAGE("Trying to load PE image for unsupported architecture (");
474 switch (nt->FileHeader.Machine)
476 case IMAGE_FILE_MACHINE_UNKNOWN: MESSAGE("Unknown"); break;
477 case IMAGE_FILE_MACHINE_I860: MESSAGE("I860"); break;
478 case IMAGE_FILE_MACHINE_R3000: MESSAGE("R3000"); break;
479 case IMAGE_FILE_MACHINE_R4000: MESSAGE("R4000"); break;
480 case IMAGE_FILE_MACHINE_R10000: MESSAGE("R10000"); break;
481 case IMAGE_FILE_MACHINE_ALPHA: MESSAGE("Alpha"); break;
482 case IMAGE_FILE_MACHINE_POWERPC: MESSAGE("PowerPC"); break;
483 default: MESSAGE("Unknown-%04x", nt->FileHeader.Machine); break;
485 MESSAGE(")\n");
486 goto error;
489 /* retrieve the shared sections file */
491 if (shared_size)
493 if ((shared_fd = FILE_GetUnixHandle( shared_file, GENERIC_READ )) == -1) goto error;
494 CloseHandle( shared_file ); /* we no longer need it */
495 shared_file = INVALID_HANDLE_VALUE;
498 /* map all the sections */
500 for (i = pos = 0; i < nt->FileHeader.NumberOfSections; i++, sec++)
502 DWORD size;
504 /* a few sanity checks */
505 size = sec->VirtualAddress + ROUND_SIZE( sec->VirtualAddress, sec->Misc.VirtualSize );
506 if (sec->VirtualAddress > total_size || size > total_size || size < sec->VirtualAddress)
508 ERR_(module)( "Section %.8s too large (%lx+%lx/%lx)\n",
509 sec->Name, sec->VirtualAddress, sec->Misc.VirtualSize, total_size );
510 goto error;
513 if ((sec->Characteristics & IMAGE_SCN_MEM_SHARED) &&
514 (sec->Characteristics & IMAGE_SCN_MEM_WRITE))
516 size = ROUND_SIZE( 0, sec->Misc.VirtualSize );
517 TRACE_(module)( "mapping shared section %.8s at %p off %lx (%x) size %lx (%lx) flags %lx\n",
518 sec->Name, (char *)ptr + sec->VirtualAddress,
519 sec->PointerToRawData, pos, sec->SizeOfRawData,
520 size, sec->Characteristics );
521 if (VIRTUAL_mmap( shared_fd, (char *)ptr + sec->VirtualAddress, size,
522 pos, PROT_READ|PROT_WRITE|PROT_EXEC,
523 MAP_SHARED|MAP_FIXED ) == (void *)-1)
525 ERR_(module)( "Could not map shared section %.8s\n", sec->Name );
526 goto error;
528 pos += size;
529 continue;
532 if (sec->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA) continue;
533 if (!sec->PointerToRawData || !sec->SizeOfRawData) continue;
535 TRACE_(module)( "mapping section %.8s at %p off %lx size %lx flags %lx\n",
536 sec->Name, (char *)ptr + sec->VirtualAddress,
537 sec->PointerToRawData, sec->SizeOfRawData,
538 sec->Characteristics );
540 /* Note: if the section is not aligned properly VIRTUAL_mmap will magically
541 * fall back to read(), so we don't need to check anything here.
543 if (VIRTUAL_mmap( fd, (char *)ptr + sec->VirtualAddress, sec->SizeOfRawData,
544 sec->PointerToRawData, PROT_READ|PROT_WRITE|PROT_EXEC,
545 MAP_PRIVATE | MAP_FIXED ) == (void *)-1)
547 ERR_(module)( "Could not map section %.8s, file probably truncated\n", sec->Name );
548 goto error;
551 if ((sec->SizeOfRawData < sec->Misc.VirtualSize) && (sec->SizeOfRawData & page_mask))
553 DWORD end = ROUND_SIZE( 0, sec->SizeOfRawData );
554 if (end > sec->Misc.VirtualSize) end = sec->Misc.VirtualSize;
555 TRACE_(module)("clearing %p - %p\n",
556 (char *)ptr + sec->VirtualAddress + sec->SizeOfRawData,
557 (char *)ptr + sec->VirtualAddress + end );
558 memset( (char *)ptr + sec->VirtualAddress + sec->SizeOfRawData, 0,
559 end - sec->SizeOfRawData );
563 SetLastError( err ); /* restore last error */
564 close( fd );
565 if (shared_fd != -1) close( shared_fd );
566 return ptr;
568 error:
569 if (view) VIRTUAL_DeleteView( view );
570 close( fd );
571 if (shared_fd != -1) close( shared_fd );
572 if (shared_file != INVALID_HANDLE_VALUE) CloseHandle( shared_file );
573 return NULL;
577 /***********************************************************************
578 * VIRTUAL_Init
580 #ifndef page_mask
581 DECL_GLOBAL_CONSTRUCTOR(VIRTUAL_Init)
583 # ifdef HAVE_GETPAGESIZE
584 page_size = getpagesize();
585 # else
586 # ifdef __svr4__
587 page_size = sysconf(_SC_PAGESIZE);
588 # else
589 # error Cannot get the page size on this platform
590 # endif
591 # endif
592 page_mask = page_size - 1;
593 /* Make sure we have a power of 2 */
594 assert( !(page_size & page_mask) );
595 page_shift = 0;
596 while ((1 << page_shift) != page_size) page_shift++;
598 #endif /* page_mask */
601 /***********************************************************************
602 * VIRTUAL_GetPageSize
604 DWORD VIRTUAL_GetPageSize(void)
606 return 1 << page_shift;
610 /***********************************************************************
611 * VIRTUAL_GetGranularity
613 DWORD VIRTUAL_GetGranularity(void)
615 return granularity_mask + 1;
619 /***********************************************************************
620 * VIRTUAL_SetFaultHandler
622 BOOL VIRTUAL_SetFaultHandler( LPCVOID addr, HANDLERPROC proc, LPVOID arg )
624 FILE_VIEW *view;
626 if (!(view = VIRTUAL_FindView((UINT)addr))) return FALSE;
627 view->handlerProc = proc;
628 view->handlerArg = arg;
629 return TRUE;
632 /***********************************************************************
633 * VIRTUAL_HandleFault
635 DWORD VIRTUAL_HandleFault( LPCVOID addr )
637 FILE_VIEW *view = VIRTUAL_FindView((UINT)addr);
638 DWORD ret = EXCEPTION_ACCESS_VIOLATION;
640 if (view)
642 if (view->handlerProc)
644 if (view->handlerProc(view->handlerArg, addr)) ret = 0; /* handled */
646 else
648 BYTE vprot = view->prot[((UINT)addr - view->base) >> page_shift];
649 UINT page = (UINT)addr & ~page_mask;
650 char *stack = (char *)NtCurrentTeb()->stack_base + SIGNAL_STACK_SIZE + page_mask + 1;
651 if (vprot & VPROT_GUARD)
653 VIRTUAL_SetProt( view, page, page_mask + 1, vprot & ~VPROT_GUARD );
654 ret = STATUS_GUARD_PAGE_VIOLATION;
656 /* is it inside the stack guard pages? */
657 if (((char *)addr >= stack) && ((char *)addr < stack + 2*(page_mask+1)))
658 ret = STATUS_STACK_OVERFLOW;
661 return ret;
665 /***********************************************************************
666 * VIRTUAL_mmap
668 * Wrapper for mmap() that handles anonymous mappings portably,
669 * and falls back to read if mmap of a file fails.
671 LPVOID VIRTUAL_mmap( int unix_handle, LPVOID start, DWORD size,
672 DWORD offset, int prot, int flags )
674 int fd = -1;
675 int pos;
676 LPVOID ret;
678 if (unix_handle == -1)
680 #ifdef MAP_ANON
681 flags |= MAP_ANON;
682 #else
683 static int fdzero = -1;
685 if (fdzero == -1)
687 if ((fdzero = open( "/dev/zero", O_RDONLY )) == -1)
689 perror( "/dev/zero: open" );
690 ExitProcess(1);
693 fd = fdzero;
694 #endif /* MAP_ANON */
695 /* Linux EINVAL's on us if we don't pass MAP_PRIVATE to an anon mmap */
696 #ifdef MAP_SHARED
697 flags &= ~MAP_SHARED;
698 #endif
699 #ifdef MAP_PRIVATE
700 flags |= MAP_PRIVATE;
701 #endif
703 else fd = unix_handle;
705 if ((ret = mmap( start, size, prot, flags, fd, offset )) != (LPVOID)-1)
706 return ret;
708 /* mmap() failed; if this is because the file offset is not */
709 /* page-aligned (EINVAL), or because the underlying filesystem */
710 /* does not support mmap() (ENOEXEC,ENODEV), we do it by hand. */
712 if (unix_handle == -1) return ret;
713 if ((errno != ENOEXEC) && (errno != EINVAL) && (errno != ENODEV)) return ret;
714 if (prot & PROT_WRITE)
716 /* We cannot fake shared write mappings */
717 #ifdef MAP_SHARED
718 if (flags & MAP_SHARED) return ret;
719 #endif
720 #ifdef MAP_PRIVATE
721 if (!(flags & MAP_PRIVATE)) return ret;
722 #endif
725 /* Reserve the memory with an anonymous mmap */
726 ret = VIRTUAL_mmap( -1, start, size, 0, PROT_READ | PROT_WRITE, flags );
727 if (ret == (LPVOID)-1) return ret;
728 /* Now read in the file */
729 if ((pos = lseek( fd, offset, SEEK_SET )) == -1)
731 munmap( ret, size );
732 return (LPVOID)-1;
734 read( fd, ret, size );
735 lseek( fd, pos, SEEK_SET ); /* Restore the file pointer */
736 mprotect( ret, size, prot ); /* Set the right protection */
737 return ret;
741 /***********************************************************************
742 * VirtualAlloc (KERNEL32.548)
743 * Reserves or commits a region of pages in virtual address space
745 * RETURNS
746 * Base address of allocated region of pages
747 * NULL: Failure
749 LPVOID WINAPI VirtualAlloc(
750 LPVOID addr, /* [in] Address of region to reserve or commit */
751 DWORD size, /* [in] Size of region */
752 DWORD type, /* [in] Type of allocation */
753 DWORD protect /* [in] Type of access protection */
755 FILE_VIEW *view;
756 UINT base, ptr, view_size;
757 BYTE vprot;
759 TRACE("%08x %08lx %lx %08lx\n",
760 (UINT)addr, size, type, protect );
762 /* Round parameters to a page boundary */
764 if (size > 0x7fc00000) /* 2Gb - 4Mb */
766 SetLastError( ERROR_OUTOFMEMORY );
767 return NULL;
769 if (addr)
771 if (type & MEM_RESERVE) /* Round down to 64k boundary */
772 base = (UINT)addr & ~granularity_mask;
773 else
774 base = ROUND_ADDR( addr );
775 size = (((UINT)addr + size + page_mask) & ~page_mask) - base;
776 if ((base <= granularity_mask) || (base + size < base))
778 /* disallow low 64k and wrap-around */
779 SetLastError( ERROR_INVALID_PARAMETER );
780 return NULL;
783 else
785 base = 0;
786 size = (size + page_mask) & ~page_mask;
789 if (type & MEM_TOP_DOWN) {
790 /* FIXME: MEM_TOP_DOWN allocates the largest possible address.
791 * Is there _ANY_ way to do it with UNIX mmap()?
793 WARN("MEM_TOP_DOWN ignored\n");
794 type &= ~MEM_TOP_DOWN;
796 /* Compute the alloc type flags */
798 if (!(type & (MEM_COMMIT | MEM_RESERVE | MEM_SYSTEM)) ||
799 (type & ~(MEM_COMMIT | MEM_RESERVE | MEM_SYSTEM)))
801 ERR("called with wrong alloc type flags (%08lx) !\n", type);
802 SetLastError( ERROR_INVALID_PARAMETER );
803 return NULL;
805 if (type & (MEM_COMMIT | MEM_SYSTEM))
806 vprot = VIRTUAL_GetProt( protect ) | VPROT_COMMITTED;
807 else vprot = 0;
809 /* Reserve the memory */
811 if ((type & MEM_RESERVE) || !base)
813 view_size = size + (base ? 0 : granularity_mask + 1);
814 if (type & MEM_SYSTEM)
815 ptr = base;
816 else
817 ptr = (UINT)VIRTUAL_mmap( -1, (LPVOID)base, view_size, 0,
818 VIRTUAL_GetUnixProt( vprot ), 0 );
819 if (ptr == (UINT)-1)
821 SetLastError( ERROR_OUTOFMEMORY );
822 return NULL;
824 if (!base)
826 /* Release the extra memory while keeping the range */
827 /* starting on a 64k boundary. */
829 if (ptr & granularity_mask)
831 UINT extra = granularity_mask + 1 - (ptr & granularity_mask);
832 munmap( (void *)ptr, extra );
833 ptr += extra;
834 view_size -= extra;
836 if (view_size > size)
837 munmap( (void *)(ptr + size), view_size - size );
839 else if (ptr != base)
841 /* We couldn't get the address we wanted */
842 munmap( (void *)ptr, view_size );
843 SetLastError( ERROR_INVALID_ADDRESS );
844 return NULL;
846 if (!(view = VIRTUAL_CreateView( ptr, size, (type & MEM_SYSTEM) ?
847 VFLAG_SYSTEM : 0, vprot, -1 )))
849 munmap( (void *)ptr, size );
850 SetLastError( ERROR_OUTOFMEMORY );
851 return NULL;
853 return (LPVOID)ptr;
856 /* Commit the pages */
858 if (!(view = VIRTUAL_FindView( base )) ||
859 (base + size > view->base + view->size))
861 SetLastError( ERROR_INVALID_ADDRESS );
862 return NULL;
865 if (!VIRTUAL_SetProt( view, base, size, vprot )) return NULL;
866 return (LPVOID)base;
870 /***********************************************************************
871 * VirtualAllocEx (KERNEL32.548)
873 * Seems to be just as VirtualAlloc, but with process handle.
875 LPVOID WINAPI VirtualAllocEx(
876 HANDLE hProcess, /* [in] Handle of process to do mem operation */
877 LPVOID addr, /* [in] Address of region to reserve or commit */
878 DWORD size, /* [in] Size of region */
879 DWORD type, /* [in] Type of allocation */
880 DWORD protect /* [in] Type of access protection */
882 if (MapProcessHandle( hProcess ) == GetCurrentProcessId())
883 return VirtualAlloc( addr, size, type, protect );
884 ERR("Unsupported on other process\n");
885 return NULL;
889 /***********************************************************************
890 * VirtualFree (KERNEL32.550)
891 * Release or decommits a region of pages in virtual address space.
893 * RETURNS
894 * TRUE: Success
895 * FALSE: Failure
897 BOOL WINAPI VirtualFree(
898 LPVOID addr, /* [in] Address of region of committed pages */
899 DWORD size, /* [in] Size of region */
900 DWORD type /* [in] Type of operation */
902 FILE_VIEW *view;
903 UINT base;
905 TRACE("%08x %08lx %lx\n",
906 (UINT)addr, size, type );
908 /* Fix the parameters */
910 size = ROUND_SIZE( addr, size );
911 base = ROUND_ADDR( addr );
913 if (!(view = VIRTUAL_FindView( base )) ||
914 (base + size > view->base + view->size))
916 SetLastError( ERROR_INVALID_PARAMETER );
917 return FALSE;
920 /* Compute the protection flags */
922 if ((type != MEM_DECOMMIT) && (type != MEM_RELEASE))
924 ERR("called with wrong free type flags (%08lx) !\n", type);
925 SetLastError( ERROR_INVALID_PARAMETER );
926 return FALSE;
929 /* Free the pages */
931 if (type == MEM_RELEASE)
933 if (size || (base != view->base))
935 SetLastError( ERROR_INVALID_PARAMETER );
936 return FALSE;
938 VIRTUAL_DeleteView( view );
939 return TRUE;
942 /* Decommit the pages by remapping zero-pages instead */
944 if (VIRTUAL_mmap( -1, (LPVOID)base, size, 0, VIRTUAL_GetUnixProt( 0 ),
945 MAP_FIXED ) != (LPVOID)base)
946 ERR( "Could not remap pages, expect trouble\n" );
947 return VIRTUAL_SetProt( view, base, size, 0 );
951 /***********************************************************************
952 * VirtualLock (KERNEL32.551)
953 * Locks the specified region of virtual address space
955 * NOTE
956 * Always returns TRUE
958 * RETURNS
959 * TRUE: Success
960 * FALSE: Failure
962 BOOL WINAPI VirtualLock(
963 LPVOID addr, /* [in] Address of first byte of range to lock */
964 DWORD size /* [in] Number of bytes in range to lock */
966 return TRUE;
970 /***********************************************************************
971 * VirtualUnlock (KERNEL32.556)
972 * Unlocks a range of pages in the virtual address space
974 * NOTE
975 * Always returns TRUE
977 * RETURNS
978 * TRUE: Success
979 * FALSE: Failure
981 BOOL WINAPI VirtualUnlock(
982 LPVOID addr, /* [in] Address of first byte of range */
983 DWORD size /* [in] Number of bytes in range */
985 return TRUE;
989 /***********************************************************************
990 * VirtualProtect (KERNEL32.552)
991 * Changes the access protection on a region of committed pages
993 * RETURNS
994 * TRUE: Success
995 * FALSE: Failure
997 BOOL WINAPI VirtualProtect(
998 LPVOID addr, /* [in] Address of region of committed pages */
999 DWORD size, /* [in] Size of region */
1000 DWORD new_prot, /* [in] Desired access protection */
1001 LPDWORD old_prot /* [out] Address of variable to get old protection */
1003 FILE_VIEW *view;
1004 UINT base, i;
1005 BYTE vprot, *p;
1007 TRACE("%08x %08lx %08lx\n",
1008 (UINT)addr, size, new_prot );
1010 /* Fix the parameters */
1012 size = ROUND_SIZE( addr, size );
1013 base = ROUND_ADDR( addr );
1015 if (!(view = VIRTUAL_FindView( base )) ||
1016 (base + size > view->base + view->size))
1018 SetLastError( ERROR_INVALID_PARAMETER );
1019 return FALSE;
1022 /* Make sure all the pages are committed */
1024 p = view->prot + ((base - view->base) >> page_shift);
1025 for (i = size >> page_shift; i; i--, p++)
1027 if (!(*p & VPROT_COMMITTED))
1029 SetLastError( ERROR_INVALID_PARAMETER );
1030 return FALSE;
1034 if (old_prot) VIRTUAL_GetWin32Prot( view->prot[0], old_prot, NULL );
1035 vprot = VIRTUAL_GetProt( new_prot ) | VPROT_COMMITTED;
1036 return VIRTUAL_SetProt( view, base, size, vprot );
1040 /***********************************************************************
1041 * VirtualProtectEx (KERNEL32.553)
1042 * Changes the access protection on a region of committed pages in the
1043 * virtual address space of a specified process
1045 * RETURNS
1046 * TRUE: Success
1047 * FALSE: Failure
1049 BOOL WINAPI VirtualProtectEx(
1050 HANDLE handle, /* [in] Handle of process */
1051 LPVOID addr, /* [in] Address of region of committed pages */
1052 DWORD size, /* [in] Size of region */
1053 DWORD new_prot, /* [in] Desired access protection */
1054 LPDWORD old_prot /* [out] Address of variable to get old protection */ )
1056 if (MapProcessHandle( handle ) == GetCurrentProcessId())
1057 return VirtualProtect( addr, size, new_prot, old_prot );
1058 ERR("Unsupported on other process\n");
1059 return FALSE;
1063 /***********************************************************************
1064 * VirtualQuery (KERNEL32.554)
1065 * Provides info about a range of pages in virtual address space
1067 * RETURNS
1068 * Number of bytes returned in information buffer
1070 DWORD WINAPI VirtualQuery(
1071 LPCVOID addr, /* [in] Address of region */
1072 LPMEMORY_BASIC_INFORMATION info, /* [out] Address of info buffer */
1073 DWORD len /* [in] Size of buffer */
1075 FILE_VIEW *view;
1076 UINT base = ROUND_ADDR( addr );
1077 UINT alloc_base = 0;
1078 UINT size = 0;
1080 /* Find the view containing the address */
1082 EnterCriticalSection(&csVirtual);
1083 view = VIRTUAL_FirstView;
1084 for (;;)
1086 if (!view)
1088 size = 0xffff0000 - alloc_base;
1089 break;
1091 if (view->base > base)
1093 size = view->base - alloc_base;
1094 view = NULL;
1095 break;
1097 if (view->base + view->size > base)
1099 alloc_base = view->base;
1100 size = view->size;
1101 break;
1103 alloc_base = view->base + view->size;
1104 view = view->next;
1106 LeaveCriticalSection(&csVirtual);
1108 /* Fill the info structure */
1110 if (!view)
1112 info->State = MEM_FREE;
1113 info->Protect = 0;
1114 info->AllocationProtect = 0;
1115 info->Type = 0;
1117 else
1119 BYTE vprot = view->prot[(base - alloc_base) >> page_shift];
1120 VIRTUAL_GetWin32Prot( vprot, &info->Protect, &info->State );
1121 for (size = base - alloc_base; size < view->size; size += page_mask+1)
1122 if (view->prot[size >> page_shift] != vprot) break;
1123 info->AllocationProtect = view->protect;
1124 info->Type = MEM_PRIVATE; /* FIXME */
1127 info->BaseAddress = (LPVOID)base;
1128 info->AllocationBase = (LPVOID)alloc_base;
1129 info->RegionSize = size - (base - alloc_base);
1130 return sizeof(*info);
1134 /***********************************************************************
1135 * VirtualQueryEx (KERNEL32.555)
1136 * Provides info about a range of pages in virtual address space of a
1137 * specified process
1139 * RETURNS
1140 * Number of bytes returned in information buffer
1142 DWORD WINAPI VirtualQueryEx(
1143 HANDLE handle, /* [in] Handle of process */
1144 LPCVOID addr, /* [in] Address of region */
1145 LPMEMORY_BASIC_INFORMATION info, /* [out] Address of info buffer */
1146 DWORD len /* [in] Size of buffer */ )
1148 if (MapProcessHandle( handle ) == GetCurrentProcessId())
1149 return VirtualQuery( addr, info, len );
1150 ERR("Unsupported on other process\n");
1151 return 0;
1155 /***********************************************************************
1156 * IsBadReadPtr (KERNEL32.354)
1158 * RETURNS
1159 * FALSE: Process has read access to entire block
1160 * TRUE: Otherwise
1162 BOOL WINAPI IsBadReadPtr(
1163 LPCVOID ptr, /* Address of memory block */
1164 UINT size ) /* Size of block */
1166 if (!size) return FALSE; /* handle 0 size case w/o reference */
1167 __TRY
1169 volatile const char *p = ptr;
1170 char dummy;
1171 UINT count = size;
1173 while (count > page_size)
1175 dummy = *p;
1176 p += page_size;
1177 count -= page_size;
1179 dummy = p[0];
1180 dummy = p[count - 1];
1182 __EXCEPT(page_fault) { return TRUE; }
1183 __ENDTRY
1184 return FALSE;
1188 /***********************************************************************
1189 * IsBadWritePtr (KERNEL32.357)
1191 * RETURNS
1192 * FALSE: Process has write access to entire block
1193 * TRUE: Otherwise
1195 BOOL WINAPI IsBadWritePtr(
1196 LPVOID ptr, /* [in] Address of memory block */
1197 UINT size ) /* [in] Size of block in bytes */
1199 if (!size) return FALSE; /* handle 0 size case w/o reference */
1200 __TRY
1202 volatile char *p = ptr;
1203 UINT count = size;
1205 while (count > page_size)
1207 *p |= 0;
1208 p += page_size;
1209 count -= page_size;
1211 p[0] |= 0;
1212 p[count - 1] |= 0;
1214 __EXCEPT(page_fault) { return TRUE; }
1215 __ENDTRY
1216 return FALSE;
1220 /***********************************************************************
1221 * IsBadHugeReadPtr (KERNEL32.352)
1222 * RETURNS
1223 * FALSE: Process has read access to entire block
1224 * TRUE: Otherwise
1226 BOOL WINAPI IsBadHugeReadPtr(
1227 LPCVOID ptr, /* [in] Address of memory block */
1228 UINT size /* [in] Size of block */
1230 return IsBadReadPtr( ptr, size );
1234 /***********************************************************************
1235 * IsBadHugeWritePtr (KERNEL32.353)
1236 * RETURNS
1237 * FALSE: Process has write access to entire block
1238 * TRUE: Otherwise
1240 BOOL WINAPI IsBadHugeWritePtr(
1241 LPVOID ptr, /* [in] Address of memory block */
1242 UINT size /* [in] Size of block */
1244 return IsBadWritePtr( ptr, size );
1248 /***********************************************************************
1249 * IsBadCodePtr (KERNEL32.351)
1251 * RETURNS
1252 * FALSE: Process has read access to specified memory
1253 * TRUE: Otherwise
1255 BOOL WINAPI IsBadCodePtr( FARPROC ptr ) /* [in] Address of function */
1257 return IsBadReadPtr( ptr, 1 );
1261 /***********************************************************************
1262 * IsBadStringPtrA (KERNEL32.355)
1264 * RETURNS
1265 * FALSE: Read access to all bytes in string
1266 * TRUE: Else
1268 BOOL WINAPI IsBadStringPtrA(
1269 LPCSTR str, /* [in] Address of string */
1270 UINT max ) /* [in] Maximum size of string */
1272 __TRY
1274 volatile const char *p = str;
1275 while (p != str + max) if (!*p++) break;
1277 __EXCEPT(page_fault) { return TRUE; }
1278 __ENDTRY
1279 return FALSE;
1283 /***********************************************************************
1284 * IsBadStringPtrW (KERNEL32.356)
1285 * See IsBadStringPtrA
1287 BOOL WINAPI IsBadStringPtrW( LPCWSTR str, UINT max )
1289 __TRY
1291 volatile const WCHAR *p = str;
1292 while (p != str + max) if (!*p++) break;
1294 __EXCEPT(page_fault) { return TRUE; }
1295 __ENDTRY
1296 return FALSE;
1300 /***********************************************************************
1301 * CreateFileMappingA (KERNEL32.46)
1302 * Creates a named or unnamed file-mapping object for the specified file
1304 * RETURNS
1305 * Handle: Success
1306 * 0: Mapping object does not exist
1307 * NULL: Failure
1309 HANDLE WINAPI CreateFileMappingA(
1310 HANDLE hFile, /* [in] Handle of file to map */
1311 SECURITY_ATTRIBUTES *sa, /* [in] Optional security attributes*/
1312 DWORD protect, /* [in] Protection for mapping object */
1313 DWORD size_high, /* [in] High-order 32 bits of object size */
1314 DWORD size_low, /* [in] Low-order 32 bits of object size */
1315 LPCSTR name /* [in] Name of file-mapping object */ )
1317 HANDLE ret;
1318 BYTE vprot;
1319 DWORD len = name ? MultiByteToWideChar( CP_ACP, 0, name, strlen(name), NULL, 0 ) : 0;
1321 /* Check parameters */
1323 TRACE("(%x,%p,%08lx,%08lx%08lx,%s)\n",
1324 hFile, sa, protect, size_high, size_low, debugstr_a(name) );
1326 if (len > MAX_PATH)
1328 SetLastError( ERROR_FILENAME_EXCED_RANGE );
1329 return 0;
1331 vprot = VIRTUAL_GetProt( protect );
1332 if (protect & SEC_RESERVE)
1334 if (hFile != INVALID_HANDLE_VALUE)
1336 SetLastError( ERROR_INVALID_PARAMETER );
1337 return 0;
1340 else vprot |= VPROT_COMMITTED;
1341 if (protect & SEC_NOCACHE) vprot |= VPROT_NOCACHE;
1342 if (protect & SEC_IMAGE) vprot |= VPROT_IMAGE;
1344 /* Create the server object */
1346 SERVER_START_REQ
1348 struct create_mapping_request *req = server_alloc_req( sizeof(*req),
1349 len * sizeof(WCHAR) );
1350 req->file_handle = hFile;
1351 req->size_high = size_high;
1352 req->size_low = size_low;
1353 req->protect = vprot;
1354 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
1355 if (len) MultiByteToWideChar( CP_ACP, 0, name, strlen(name), server_data_ptr(req), len );
1356 SetLastError(0);
1357 server_call( REQ_CREATE_MAPPING );
1358 ret = req->handle;
1360 SERVER_END_REQ;
1361 if (ret == -1) ret = 0; /* must return 0 on failure, not -1 */
1362 return ret;
1366 /***********************************************************************
1367 * CreateFileMappingW (KERNEL32.47)
1368 * See CreateFileMappingA
1370 HANDLE WINAPI CreateFileMappingW( HANDLE hFile, LPSECURITY_ATTRIBUTES sa,
1371 DWORD protect, DWORD size_high,
1372 DWORD size_low, LPCWSTR name )
1374 HANDLE ret;
1375 BYTE vprot;
1376 DWORD len = name ? strlenW(name) : 0;
1378 /* Check parameters */
1380 TRACE("(%x,%p,%08lx,%08lx%08lx,%s)\n",
1381 hFile, sa, protect, size_high, size_low, debugstr_w(name) );
1383 if (len > MAX_PATH)
1385 SetLastError( ERROR_FILENAME_EXCED_RANGE );
1386 return 0;
1389 vprot = VIRTUAL_GetProt( protect );
1390 if (protect & SEC_RESERVE)
1392 if (hFile != INVALID_HANDLE_VALUE)
1394 SetLastError( ERROR_INVALID_PARAMETER );
1395 return 0;
1398 else vprot |= VPROT_COMMITTED;
1399 if (protect & SEC_NOCACHE) vprot |= VPROT_NOCACHE;
1400 if (protect & SEC_IMAGE) vprot |= VPROT_IMAGE;
1402 /* Create the server object */
1404 SERVER_START_REQ
1406 struct create_mapping_request *req = server_alloc_req( sizeof(*req),
1407 len * sizeof(WCHAR) );
1408 req->file_handle = hFile;
1409 req->size_high = size_high;
1410 req->size_low = size_low;
1411 req->protect = vprot;
1412 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
1413 memcpy( server_data_ptr(req), name, len * sizeof(WCHAR) );
1414 SetLastError(0);
1415 server_call( REQ_CREATE_MAPPING );
1416 ret = req->handle;
1418 SERVER_END_REQ;
1419 if (ret == -1) ret = 0; /* must return 0 on failure, not -1 */
1420 return ret;
1424 /***********************************************************************
1425 * OpenFileMappingA (KERNEL32.397)
1426 * Opens a named file-mapping object.
1428 * RETURNS
1429 * Handle: Success
1430 * NULL: Failure
1432 HANDLE WINAPI OpenFileMappingA(
1433 DWORD access, /* [in] Access mode */
1434 BOOL inherit, /* [in] Inherit flag */
1435 LPCSTR name ) /* [in] Name of file-mapping object */
1437 HANDLE ret;
1438 DWORD len = name ? MultiByteToWideChar( CP_ACP, 0, name, strlen(name), NULL, 0 ) : 0;
1439 if (len > MAX_PATH)
1441 SetLastError( ERROR_FILENAME_EXCED_RANGE );
1442 return 0;
1444 SERVER_START_REQ
1446 struct open_mapping_request *req = server_alloc_req( sizeof(*req), len * sizeof(WCHAR) );
1448 req->access = access;
1449 req->inherit = inherit;
1450 if (len) MultiByteToWideChar( CP_ACP, 0, name, strlen(name), server_data_ptr(req), len );
1451 server_call( REQ_OPEN_MAPPING );
1452 ret = req->handle;
1454 SERVER_END_REQ;
1455 if (ret == -1) ret = 0; /* must return 0 on failure, not -1 */
1456 return ret;
1460 /***********************************************************************
1461 * OpenFileMappingW (KERNEL32.398)
1462 * See OpenFileMappingA
1464 HANDLE WINAPI OpenFileMappingW( DWORD access, BOOL inherit, LPCWSTR name)
1466 HANDLE ret;
1467 DWORD len = name ? strlenW(name) : 0;
1468 if (len > MAX_PATH)
1470 SetLastError( ERROR_FILENAME_EXCED_RANGE );
1471 return 0;
1473 SERVER_START_REQ
1475 struct open_mapping_request *req = server_alloc_req( sizeof(*req), len * sizeof(WCHAR) );
1477 req->access = access;
1478 req->inherit = inherit;
1479 memcpy( server_data_ptr(req), name, len * sizeof(WCHAR) );
1480 server_call( REQ_OPEN_MAPPING );
1481 ret = req->handle;
1483 SERVER_END_REQ;
1484 if (ret == -1) ret = 0; /* must return 0 on failure, not -1 */
1485 return ret;
1489 /***********************************************************************
1490 * MapViewOfFile (KERNEL32.385)
1491 * Maps a view of a file into the address space
1493 * RETURNS
1494 * Starting address of mapped view
1495 * NULL: Failure
1497 LPVOID WINAPI MapViewOfFile(
1498 HANDLE mapping, /* [in] File-mapping object to map */
1499 DWORD access, /* [in] Access mode */
1500 DWORD offset_high, /* [in] High-order 32 bits of file offset */
1501 DWORD offset_low, /* [in] Low-order 32 bits of file offset */
1502 DWORD count /* [in] Number of bytes to map */
1504 return MapViewOfFileEx( mapping, access, offset_high,
1505 offset_low, count, NULL );
1509 /***********************************************************************
1510 * MapViewOfFileEx (KERNEL32.386)
1511 * Maps a view of a file into the address space
1513 * RETURNS
1514 * Starting address of mapped view
1515 * NULL: Failure
1517 LPVOID WINAPI MapViewOfFileEx(
1518 HANDLE handle, /* [in] File-mapping object to map */
1519 DWORD access, /* [in] Access mode */
1520 DWORD offset_high, /* [in] High-order 32 bits of file offset */
1521 DWORD offset_low, /* [in] Low-order 32 bits of file offset */
1522 DWORD count, /* [in] Number of bytes to map */
1523 LPVOID addr /* [in] Suggested starting address for mapped view */
1525 FILE_VIEW *view;
1526 UINT ptr = (UINT)-1, size = 0;
1527 int flags = MAP_PRIVATE;
1528 int unix_handle = -1;
1529 int prot;
1530 struct get_mapping_info_request *req = get_req_buffer();
1532 /* Check parameters */
1534 if ((offset_low & granularity_mask) ||
1535 (addr && ((UINT)addr & granularity_mask)))
1537 SetLastError( ERROR_INVALID_PARAMETER );
1538 return NULL;
1541 req->handle = handle;
1542 if (server_call_fd( REQ_GET_MAPPING_INFO, -1, &unix_handle )) goto error;
1543 prot = req->protect;
1545 if (prot & VPROT_IMAGE)
1546 return map_image( handle, unix_handle, req->base, req->size_low, req->header_size,
1547 req->shared_file, req->shared_size );
1549 if (req->size_high || offset_high)
1550 ERR("Offsets larger than 4Gb not supported\n");
1552 if ((offset_low >= req->size_low) ||
1553 (count > req->size_low - offset_low))
1555 SetLastError( ERROR_INVALID_PARAMETER );
1556 goto error;
1558 if (count) size = ROUND_SIZE( offset_low, count );
1559 else size = req->size_low - offset_low;
1561 switch(access)
1563 case FILE_MAP_ALL_ACCESS:
1564 case FILE_MAP_WRITE:
1565 case FILE_MAP_WRITE | FILE_MAP_READ:
1566 if (!(prot & VPROT_WRITE))
1568 SetLastError( ERROR_INVALID_PARAMETER );
1569 goto error;
1571 flags = MAP_SHARED;
1572 /* fall through */
1573 case FILE_MAP_READ:
1574 case FILE_MAP_COPY:
1575 case FILE_MAP_COPY | FILE_MAP_READ:
1576 if (prot & VPROT_READ) break;
1577 /* fall through */
1578 default:
1579 SetLastError( ERROR_INVALID_PARAMETER );
1580 goto error;
1583 /* FIXME: If a mapping is created with SEC_RESERVE and a process,
1584 * which has a view of this mapping commits some pages, they will
1585 * appear commited in all other processes, which have the same
1586 * view created. Since we don`t support this yet, we create the
1587 * whole mapping commited.
1589 prot |= VPROT_COMMITTED;
1591 /* Map the file */
1593 TRACE("handle=%x size=%x offset=%lx\n", handle, size, offset_low );
1595 ptr = (UINT)VIRTUAL_mmap( unix_handle, addr, size, offset_low,
1596 VIRTUAL_GetUnixProt( prot ), flags );
1597 if (ptr == (UINT)-1) {
1598 /* KB: Q125713, 25-SEP-1995, "Common File Mapping Problems and
1599 * Platform Differences":
1600 * Windows NT: ERROR_INVALID_PARAMETER
1601 * Windows 95: ERROR_INVALID_ADDRESS.
1602 * FIXME: So should we add a module dependend check here? -MM
1604 if (errno==ENOMEM)
1605 SetLastError( ERROR_OUTOFMEMORY );
1606 else
1607 SetLastError( ERROR_INVALID_PARAMETER );
1608 goto error;
1611 if (!(view = VIRTUAL_CreateView( ptr, size, 0, prot, handle )))
1613 SetLastError( ERROR_OUTOFMEMORY );
1614 goto error;
1616 if (unix_handle != -1) close( unix_handle );
1617 return (LPVOID)ptr;
1619 error:
1620 if (unix_handle != -1) close( unix_handle );
1621 if (ptr != (UINT)-1) munmap( (void *)ptr, size );
1622 return NULL;
1626 /***********************************************************************
1627 * FlushViewOfFile (KERNEL32.262)
1628 * Writes to the disk a byte range within a mapped view of a file
1630 * RETURNS
1631 * TRUE: Success
1632 * FALSE: Failure
1634 BOOL WINAPI FlushViewOfFile(
1635 LPCVOID base, /* [in] Start address of byte range to flush */
1636 DWORD cbFlush /* [in] Number of bytes in range */
1638 FILE_VIEW *view;
1639 UINT addr = ROUND_ADDR( base );
1641 TRACE("FlushViewOfFile at %p for %ld bytes\n",
1642 base, cbFlush );
1644 if (!(view = VIRTUAL_FindView( addr )))
1646 SetLastError( ERROR_INVALID_PARAMETER );
1647 return FALSE;
1649 if (!cbFlush) cbFlush = view->size;
1650 if (!msync( (void *)addr, cbFlush, MS_SYNC )) return TRUE;
1651 SetLastError( ERROR_INVALID_PARAMETER );
1652 return FALSE;
1656 /***********************************************************************
1657 * UnmapViewOfFile (KERNEL32.540)
1658 * Unmaps a mapped view of a file.
1660 * NOTES
1661 * Should addr be an LPCVOID?
1663 * RETURNS
1664 * TRUE: Success
1665 * FALSE: Failure
1667 BOOL WINAPI UnmapViewOfFile(
1668 LPVOID addr /* [in] Address where mapped view begins */
1670 FILE_VIEW *view;
1671 UINT base = ROUND_ADDR( addr );
1672 if (!(view = VIRTUAL_FindView( base )) || (base != view->base))
1674 SetLastError( ERROR_INVALID_PARAMETER );
1675 return FALSE;
1677 VIRTUAL_DeleteView( view );
1678 return TRUE;
1681 /***********************************************************************
1682 * VIRTUAL_MapFileW
1684 * Helper function to map a file to memory:
1685 * name - file name
1686 * [RETURN] ptr - pointer to mapped file
1688 LPVOID VIRTUAL_MapFileW( LPCWSTR name )
1690 HANDLE hFile, hMapping;
1691 LPVOID ptr = NULL;
1693 hFile = CreateFileW( name, GENERIC_READ, FILE_SHARE_READ, NULL,
1694 OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS, 0);
1695 if (hFile != INVALID_HANDLE_VALUE)
1697 hMapping = CreateFileMappingA( hFile, NULL, PAGE_READONLY, 0, 0, NULL );
1698 CloseHandle( hFile );
1699 if (hMapping)
1701 ptr = MapViewOfFile( hMapping, FILE_MAP_READ, 0, 0, 0 );
1702 CloseHandle( hMapping );
1705 return ptr;