Match PSDK STATUS_* definitions.
[wine] / dlls / kernel / virtual.c
1 /*
2  * Win32 virtual memory functions
3  *
4  * Copyright 1997 Alexandre Julliard
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "config.h"
22 #include "wine/port.h"
23
24 #include <fcntl.h>
25 #include <stdarg.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <sys/types.h>
29 #ifdef HAVE_UNISTD_H
30 # include <unistd.h>
31 #endif
32
33 #define NONAMELESSUNION
34 #define NONAMELESSSTRUCT
35 #include "ntstatus.h"
36 #define WIN32_NO_STATUS
37 #include "windef.h"
38 #include "winbase.h"
39 #include "winnls.h"
40 #include "winternl.h"
41 #include "winerror.h"
42 #include "wine/exception.h"
43 #include "excpt.h"
44 #include "wine/debug.h"
45
46 WINE_DEFAULT_DEBUG_CHANNEL(virtual);
47 WINE_DECLARE_DEBUG_CHANNEL(seh);
48
49 static unsigned int page_size;
50
51 /* filter for page-fault exceptions */
52 static WINE_EXCEPTION_FILTER(page_fault)
53 {
54     if (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION)
55         return EXCEPTION_EXECUTE_HANDLER;
56     return EXCEPTION_CONTINUE_SEARCH;
57 }
58
59
60 /***********************************************************************
61  *             VirtualAlloc   (KERNEL32.@)
62  * Reserves or commits a region of pages in virtual address space
63  *
64  * RETURNS
65  *      Base address of allocated region of pages
66  *      NULL: Failure
67  */
68 LPVOID WINAPI VirtualAlloc(
69               LPVOID addr,  /* [in] Address of region to reserve or commit */
70               SIZE_T size,  /* [in] Size of region */
71               DWORD type,   /* [in] Type of allocation */
72               DWORD protect)/* [in] Type of access protection */
73 {
74     return VirtualAllocEx( GetCurrentProcess(), addr, size, type, protect );
75 }
76
77
78 /***********************************************************************
79  *             VirtualAllocEx   (KERNEL32.@)
80  *
81  * Seems to be just as VirtualAlloc, but with process handle.
82  *
83  * RETURNS
84  *      Base address of allocated region of pages
85  *      NULL: Failure
86  */
87 LPVOID WINAPI VirtualAllocEx(
88               HANDLE hProcess, /* [in] Handle of process to do mem operation */
89               LPVOID addr,     /* [in] Address of region to reserve or commit */
90               SIZE_T size,     /* [in] Size of region */
91               DWORD type,      /* [in] Type of allocation */
92               DWORD protect )  /* [in] Type of access protection */
93 {
94     LPVOID ret = addr;
95     NTSTATUS status;
96
97     if ((status = NtAllocateVirtualMemory( hProcess, &ret, 0, &size, type, protect )))
98     {
99         SetLastError( RtlNtStatusToDosError(status) );
100         ret = NULL;
101     }
102     return ret;
103 }
104
105
106 /***********************************************************************
107  *             VirtualFree   (KERNEL32.@)
108  * Release or decommits a region of pages in virtual address space.
109  *
110  * RETURNS
111  *      TRUE: Success
112  *      FALSE: Failure
113  */
114 BOOL WINAPI VirtualFree(
115               LPVOID addr, /* [in] Address of region of committed pages */
116               SIZE_T size, /* [in] Size of region */
117               DWORD type   /* [in] Type of operation */
118 ) {
119     return VirtualFreeEx( GetCurrentProcess(), addr, size, type );
120 }
121
122
123 /***********************************************************************
124  *             VirtualFreeEx   (KERNEL32.@)
125  * Release or decommits a region of pages in virtual address space.
126  *
127  * RETURNS
128  *      TRUE: Success
129  *      FALSE: Failure
130  */
131 BOOL WINAPI VirtualFreeEx( HANDLE process, LPVOID addr, SIZE_T size, DWORD type )
132 {
133     NTSTATUS status = NtFreeVirtualMemory( process, &addr, &size, type );
134     if (status) SetLastError( RtlNtStatusToDosError(status) );
135     return !status;
136 }
137
138
139 /***********************************************************************
140  *             VirtualLock   (KERNEL32.@)
141  * Locks the specified region of virtual address space
142  *
143  * NOTE
144  *      Always returns TRUE
145  *
146  * RETURNS
147  *      TRUE: Success
148  *      FALSE: Failure
149  */
150 BOOL WINAPI VirtualLock( LPVOID addr, /* [in] Address of first byte of range to lock */
151                          SIZE_T size ) /* [in] Number of bytes in range to lock */
152 {
153     NTSTATUS status = NtLockVirtualMemory( GetCurrentProcess(), &addr, &size, 1 );
154     if (status) SetLastError( RtlNtStatusToDosError(status) );
155     return !status;
156 }
157
158
159 /***********************************************************************
160  *             VirtualUnlock   (KERNEL32.@)
161  * Unlocks a range of pages in the virtual address space
162  *
163  * NOTE
164  *      Always returns TRUE
165  *
166  * RETURNS
167  *      TRUE: Success
168  *      FALSE: Failure
169  */
170 BOOL WINAPI VirtualUnlock( LPVOID addr, /* [in] Address of first byte of range */
171                            SIZE_T size ) /* [in] Number of bytes in range */
172 {
173     NTSTATUS status = NtUnlockVirtualMemory( GetCurrentProcess(), &addr, &size, 1 );
174     if (status) SetLastError( RtlNtStatusToDosError(status) );
175     return !status;
176 }
177
178
179 /***********************************************************************
180  *             VirtualProtect   (KERNEL32.@)
181  * Changes the access protection on a region of committed pages
182  *
183  * RETURNS
184  *      TRUE: Success
185  *      FALSE: Failure
186  */
187 BOOL WINAPI VirtualProtect(
188               LPVOID addr,     /* [in] Address of region of committed pages */
189               SIZE_T size,     /* [in] Size of region */
190               DWORD new_prot,  /* [in] Desired access protection */
191               LPDWORD old_prot /* [out] Address of variable to get old protection */
192 ) {
193     return VirtualProtectEx( GetCurrentProcess(), addr, size, new_prot, old_prot );
194 }
195
196
197 /***********************************************************************
198  *             VirtualProtectEx   (KERNEL32.@)
199  * Changes the access protection on a region of committed pages in the
200  * virtual address space of a specified process
201  *
202  * RETURNS
203  *      TRUE: Success
204  *      FALSE: Failure
205  */
206 BOOL WINAPI VirtualProtectEx(
207               HANDLE process,  /* [in]  Handle of process */
208               LPVOID addr,     /* [in]  Address of region of committed pages */
209               SIZE_T size,     /* [in]  Size of region */
210               DWORD new_prot,  /* [in]  Desired access protection */
211               LPDWORD old_prot /* [out] Address of variable to get old protection */ )
212 {
213     NTSTATUS status = NtProtectVirtualMemory( process, &addr, &size, new_prot, old_prot );
214     if (status) SetLastError( RtlNtStatusToDosError(status) );
215     return !status;
216 }
217
218
219 /***********************************************************************
220  *             VirtualQuery   (KERNEL32.@)
221  * Provides info about a range of pages in virtual address space
222  *
223  * RETURNS
224  *      Number of bytes returned in information buffer
225  *      or 0 if addr is >= 0xc0000000 (kernel space).
226  */
227 SIZE_T WINAPI VirtualQuery(
228              LPCVOID addr,                    /* [in]  Address of region */
229              PMEMORY_BASIC_INFORMATION info,  /* [out] Address of info buffer */
230              SIZE_T len                       /* [in]  Size of buffer */
231 ) {
232     return VirtualQueryEx( GetCurrentProcess(), addr, info, len );
233 }
234
235
236 /***********************************************************************
237  *             VirtualQueryEx   (KERNEL32.@)
238  * Provides info about a range of pages in virtual address space of a
239  * specified process
240  *
241  * RETURNS
242  *      Number of bytes returned in information buffer
243  */
244 SIZE_T WINAPI VirtualQueryEx(
245              HANDLE process,                  /* [in] Handle of process */
246              LPCVOID addr,                    /* [in] Address of region */
247              PMEMORY_BASIC_INFORMATION info,  /* [out] Address of info buffer */
248              SIZE_T len                       /* [in] Size of buffer */ )
249 {
250     SIZE_T ret;
251     NTSTATUS status;
252
253     if ((status = NtQueryVirtualMemory( process, addr, MemoryBasicInformation, info, len, &ret )))
254     {
255         SetLastError( RtlNtStatusToDosError(status) );
256         ret = 0;
257     }
258     return ret;
259 }
260
261
262 /***********************************************************************
263  *             CreateFileMappingA   (KERNEL32.@)
264  * Creates a named or unnamed file-mapping object for the specified file
265  *
266  * RETURNS
267  *      Handle: Success
268  *      0: Mapping object does not exist
269  *      NULL: Failure
270  */
271 HANDLE WINAPI CreateFileMappingA(
272                 HANDLE hFile,   /* [in] Handle of file to map */
273                 SECURITY_ATTRIBUTES *sa, /* [in] Optional security attributes*/
274                 DWORD protect,   /* [in] Protection for mapping object */
275                 DWORD size_high, /* [in] High-order 32 bits of object size */
276                 DWORD size_low,  /* [in] Low-order 32 bits of object size */
277                 LPCSTR name      /* [in] Name of file-mapping object */ )
278 {
279     WCHAR buffer[MAX_PATH];
280
281     if (!name) return CreateFileMappingW( hFile, sa, protect, size_high, size_low, NULL );
282
283     if (!MultiByteToWideChar( CP_ACP, 0, name, -1, buffer, MAX_PATH ))
284     {
285         SetLastError( ERROR_FILENAME_EXCED_RANGE );
286         return 0;
287     }
288     return CreateFileMappingW( hFile, sa, protect, size_high, size_low, buffer );
289 }
290
291
292 /***********************************************************************
293  *             CreateFileMappingW   (KERNEL32.@)
294  * See CreateFileMappingA.
295  */
296 HANDLE WINAPI CreateFileMappingW( HANDLE hFile, LPSECURITY_ATTRIBUTES sa,
297                                   DWORD protect, DWORD size_high,
298                                   DWORD size_low, LPCWSTR name )
299 {
300     static const int sec_flags = SEC_FILE | SEC_IMAGE | SEC_RESERVE | SEC_COMMIT | SEC_NOCACHE;
301
302     HANDLE ret;
303     OBJECT_ATTRIBUTES attr;
304     UNICODE_STRING nameW;
305     NTSTATUS status;
306     DWORD access, sec_type;
307     LARGE_INTEGER size;
308
309     attr.Length                   = sizeof(attr);
310     attr.RootDirectory            = 0;
311     attr.ObjectName               = NULL;
312     attr.Attributes               = OBJ_CASE_INSENSITIVE | OBJ_OPENIF |
313                                     ((sa && sa->bInheritHandle) ? OBJ_INHERIT : 0);
314     attr.SecurityDescriptor       = sa ? sa->lpSecurityDescriptor : NULL;
315     attr.SecurityQualityOfService = NULL;
316
317     if (name)
318     {
319         RtlInitUnicodeString( &nameW, name );
320         attr.ObjectName = &nameW;
321     }
322
323     sec_type = protect & sec_flags;
324     protect &= ~sec_flags;
325     if (!sec_type) sec_type = SEC_COMMIT;
326
327     switch(protect)
328     {
329     case 0:
330         protect = PAGE_READONLY;  /* Win9x compatibility */
331         /* fall through */
332     case PAGE_READONLY:
333     case PAGE_WRITECOPY:
334         access = STANDARD_RIGHTS_REQUIRED | SECTION_QUERY | SECTION_MAP_READ;
335         break;
336     case PAGE_READWRITE:
337         access = STANDARD_RIGHTS_REQUIRED | SECTION_QUERY | SECTION_MAP_READ | SECTION_MAP_WRITE;
338         break;
339     default:
340         SetLastError( ERROR_INVALID_PARAMETER );
341         return 0;
342     }
343
344     if (hFile == INVALID_HANDLE_VALUE)
345     {
346         hFile = 0;
347         if (!size_low && !size_high)
348         {
349             SetLastError( ERROR_INVALID_PARAMETER );
350             return 0;
351         }
352     }
353
354     size.u.LowPart  = size_low;
355     size.u.HighPart = size_high;
356
357     status = NtCreateSection( &ret, access, &attr, &size, protect, sec_type, hFile );
358     if (status == STATUS_OBJECT_NAME_EXISTS)
359         SetLastError( ERROR_ALREADY_EXISTS );
360     else
361         SetLastError( RtlNtStatusToDosError(status) );
362     return ret;
363 }
364
365
366 /***********************************************************************
367  *             OpenFileMappingA   (KERNEL32.@)
368  * Opens a named file-mapping object.
369  *
370  * RETURNS
371  *      Handle: Success
372  *      NULL: Failure
373  */
374 HANDLE WINAPI OpenFileMappingA(
375                 DWORD access,   /* [in] Access mode */
376                 BOOL inherit, /* [in] Inherit flag */
377                 LPCSTR name )   /* [in] Name of file-mapping object */
378 {
379     WCHAR buffer[MAX_PATH];
380
381     if (!name) return OpenFileMappingW( access, inherit, NULL );
382
383     if (!MultiByteToWideChar( CP_ACP, 0, name, -1, buffer, MAX_PATH ))
384     {
385         SetLastError( ERROR_FILENAME_EXCED_RANGE );
386         return 0;
387     }
388     return OpenFileMappingW( access, inherit, buffer );
389 }
390
391
392 /***********************************************************************
393  *             OpenFileMappingW   (KERNEL32.@)
394  * See OpenFileMappingA.
395  */
396 HANDLE WINAPI OpenFileMappingW( DWORD access, BOOL inherit, LPCWSTR name)
397 {
398     OBJECT_ATTRIBUTES attr;
399     UNICODE_STRING nameW;
400     HANDLE ret;
401     NTSTATUS status;
402
403     if (!name)
404     {
405         SetLastError( ERROR_INVALID_PARAMETER );
406         return 0;
407     }
408     attr.Length = sizeof(attr);
409     attr.RootDirectory = 0;
410     attr.ObjectName = &nameW;
411     attr.Attributes = OBJ_CASE_INSENSITIVE | (inherit ? OBJ_INHERIT : 0);
412     attr.SecurityDescriptor = NULL;
413     attr.SecurityQualityOfService = NULL;
414     RtlInitUnicodeString( &nameW, name );
415
416     if (access == FILE_MAP_COPY) access = FILE_MAP_READ;
417
418     if ((status = NtOpenSection( &ret, access, &attr )))
419     {
420         SetLastError( RtlNtStatusToDosError(status) );
421         ret = 0;
422     }
423     return ret;
424 }
425
426
427 /***********************************************************************
428  *             MapViewOfFile   (KERNEL32.@)
429  * Maps a view of a file into the address space
430  *
431  * RETURNS
432  *      Starting address of mapped view
433  *      NULL: Failure
434  */
435 LPVOID WINAPI MapViewOfFile(
436               HANDLE mapping,  /* [in] File-mapping object to map */
437               DWORD access,      /* [in] Access mode */
438               DWORD offset_high, /* [in] High-order 32 bits of file offset */
439               DWORD offset_low,  /* [in] Low-order 32 bits of file offset */
440               SIZE_T count       /* [in] Number of bytes to map */
441 ) {
442     return MapViewOfFileEx( mapping, access, offset_high,
443                             offset_low, count, NULL );
444 }
445
446
447 /***********************************************************************
448  *             MapViewOfFileEx   (KERNEL32.@)
449  * Maps a view of a file into the address space
450  *
451  * RETURNS
452  *      Starting address of mapped view
453  *      NULL: Failure
454  */
455 LPVOID WINAPI MapViewOfFileEx(
456               HANDLE handle,   /* [in] File-mapping object to map */
457               DWORD access,      /* [in] Access mode */
458               DWORD offset_high, /* [in] High-order 32 bits of file offset */
459               DWORD offset_low,  /* [in] Low-order 32 bits of file offset */
460               SIZE_T count,      /* [in] Number of bytes to map */
461               LPVOID addr        /* [in] Suggested starting address for mapped view */
462 ) {
463     NTSTATUS status;
464     LARGE_INTEGER offset;
465     ULONG protect;
466
467     offset.u.LowPart  = offset_low;
468     offset.u.HighPart = offset_high;
469
470     if (access & FILE_MAP_WRITE) protect = PAGE_READWRITE;
471     else if (access & FILE_MAP_READ) protect = PAGE_READONLY;
472     else if (access & FILE_MAP_COPY) protect = PAGE_WRITECOPY;
473     else protect = PAGE_NOACCESS;
474
475     if ((status = NtMapViewOfSection( handle, GetCurrentProcess(), &addr, 0, 0, &offset,
476                                       &count, ViewShare, 0, protect )))
477     {
478         SetLastError( RtlNtStatusToDosError(status) );
479         addr = NULL;
480     }
481     return addr;
482 }
483
484
485 /***********************************************************************
486  *             UnmapViewOfFile   (KERNEL32.@)
487  * Unmaps a mapped view of a file.
488  *
489  * NOTES
490  *      Should addr be an LPCVOID?
491  *
492  * RETURNS
493  *      TRUE: Success
494  *      FALSE: Failure
495  */
496 BOOL WINAPI UnmapViewOfFile( LPVOID addr ) /* [in] Address where mapped view begins */
497 {
498     NTSTATUS status = NtUnmapViewOfSection( GetCurrentProcess(), addr );
499     if (status) SetLastError( RtlNtStatusToDosError(status) );
500     return !status;
501 }
502
503
504 /***********************************************************************
505  *             FlushViewOfFile   (KERNEL32.@)
506  * Writes to the disk a byte range within a mapped view of a file
507  *
508  * RETURNS
509  *      TRUE: Success
510  *      FALSE: Failure
511  */
512 BOOL WINAPI FlushViewOfFile( LPCVOID base,  /* [in] Start address of byte range to flush */
513                              SIZE_T size )   /* [in] Number of bytes in range */
514 {
515     NTSTATUS status = NtFlushVirtualMemory( GetCurrentProcess(), &base, &size, 0 );
516     if (status)
517     {
518         if (status == STATUS_NOT_MAPPED_DATA) status = STATUS_SUCCESS;
519         else SetLastError( RtlNtStatusToDosError(status) );
520     }
521     return !status;
522 }
523
524
525 /***********************************************************************
526  *             IsBadReadPtr   (KERNEL32.@)
527  *
528  * Check for read access on a memory block.
529  *
530  * RETURNS
531  *      FALSE: Process has read access to entire block
532  *      TRUE: Otherwise
533  */
534 BOOL WINAPI IsBadReadPtr(
535               LPCVOID ptr, /* [in] Address of memory block */
536               UINT size )  /* [in] Size of block */
537 {
538     if (!size) return FALSE;  /* handle 0 size case w/o reference */
539     if (!ptr) return TRUE;
540     
541     if (!page_size) page_size = getpagesize();
542     __TRY
543     {
544         volatile const char *p = ptr;
545         char dummy;
546         UINT count = size;
547
548         while (count > page_size)
549         {
550             dummy = *p;
551             p += page_size;
552             count -= page_size;
553         }
554         dummy = p[0];
555         dummy = p[count - 1];
556     }
557     __EXCEPT(page_fault)
558     {
559         TRACE_(seh)("%p caused page fault during read\n", ptr);
560         return TRUE;
561     }
562     __ENDTRY
563     return FALSE;
564 }
565
566
567 /***********************************************************************
568  *             IsBadWritePtr   (KERNEL32.@)
569  *
570  * Check for write access on a memory block.
571  *
572  * RETURNS
573  *      FALSE: Process has write access to entire block
574  *      TRUE: Otherwise
575  */
576 BOOL WINAPI IsBadWritePtr(
577               LPVOID ptr, /* [in] Address of memory block */
578               UINT size ) /* [in] Size of block in bytes */
579 {
580     if (!size) return FALSE;  /* handle 0 size case w/o reference */
581     if (!ptr) return TRUE;
582     
583     if (!page_size) page_size = getpagesize();
584     __TRY
585     {
586         volatile char *p = ptr;
587         UINT count = size;
588
589         while (count > page_size)
590         {
591             *p |= 0;
592             p += page_size;
593             count -= page_size;
594         }
595         p[0] |= 0;
596         p[count - 1] |= 0;
597     }
598     __EXCEPT(page_fault)
599     {
600         TRACE_(seh)("%p caused page fault during write\n", ptr);
601         return TRUE;
602     }
603     __ENDTRY
604     return FALSE;
605 }
606
607
608 /***********************************************************************
609  *             IsBadHugeReadPtr   (KERNEL32.@)
610  *
611  * Check for read access on a memory block.
612  *
613  * RETURNS
614  *      FALSE: Process has read access to entire block
615  *      TRUE: Otherwise
616  */
617 BOOL WINAPI IsBadHugeReadPtr(
618               LPCVOID ptr, /* [in] Address of memory block */
619               UINT size  /* [in] Size of block */
620 ) {
621     return IsBadReadPtr( ptr, size );
622 }
623
624
625 /***********************************************************************
626  *             IsBadHugeWritePtr   (KERNEL32.@)
627  *
628  * Check for write access on a memory block.
629  *
630  * RETURNS
631  *      FALSE: Process has write access to entire block
632  *      TRUE: Otherwise
633  */
634 BOOL WINAPI IsBadHugeWritePtr(
635               LPVOID ptr, /* [in] Address of memory block */
636               UINT size /* [in] Size of block */
637 ) {
638     return IsBadWritePtr( ptr, size );
639 }
640
641
642 /***********************************************************************
643  *             IsBadCodePtr   (KERNEL32.@)
644  *
645  * Check for read access on a memory address.
646  *
647  * RETURNS
648  *      FALSE: Process has read access to specified memory
649  *      TRUE: Otherwise
650  */
651 BOOL WINAPI IsBadCodePtr( FARPROC ptr ) /* [in] Address of function */
652 {
653     return IsBadReadPtr( ptr, 1 );
654 }
655
656
657 /***********************************************************************
658  *             IsBadStringPtrA   (KERNEL32.@)
659  *
660  * Check for read access on a range of memory pointed to by a string pointer.
661  *
662  * RETURNS
663  *      FALSE: Read access to all bytes in string
664  *      TRUE: Else
665  */
666 BOOL WINAPI IsBadStringPtrA(
667               LPCSTR str, /* [in] Address of string */
668               UINT max )  /* [in] Maximum size of string */
669 {
670     if (!str) return TRUE;
671     
672     __TRY
673     {
674         volatile const char *p = str;
675         while (p != str + max) if (!*p++) break;
676     }
677     __EXCEPT(page_fault)
678     {
679         TRACE_(seh)("%p caused page fault during read\n", str);
680         return TRUE;
681     }
682     __ENDTRY
683     return FALSE;
684 }
685
686
687 /***********************************************************************
688  *             IsBadStringPtrW   (KERNEL32.@)
689  * See IsBadStringPtrA.
690  */
691 BOOL WINAPI IsBadStringPtrW( LPCWSTR str, UINT max )
692 {
693     if (!str) return TRUE;
694     
695     __TRY
696     {
697         volatile const WCHAR *p = str;
698         while (p != str + max) if (!*p++) break;
699     }
700     __EXCEPT(page_fault)
701     {
702         TRACE_(seh)("%p caused page fault during read\n", str);
703         return TRUE;
704     }
705     __ENDTRY
706     return FALSE;
707 }