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