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