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