/*++ Copyright (c) 1990,1991 Microsoft Corporation Module Name: filemap.c Abstract: This module implements Win32 mapped file APIs Author: Mark Lucovsky (markl) 15-Feb-1991 Revision History: --*/ #include "basedll.h" HANDLE APIENTRY CreateFileMappingA( HANDLE hFile, LPSECURITY_ATTRIBUTES lpFileMappingAttributes, DWORD flProtect, DWORD dwMaximumSizeHigh, DWORD dwMaximumSizeLow, LPCSTR lpName ) /*++ Routine Description: ANSI thunk to CreateFileMappingW --*/ { PUNICODE_STRING Unicode; ANSI_STRING AnsiString; NTSTATUS Status; LPCWSTR NameBuffer; NameBuffer = NULL; if ( ARGUMENT_PRESENT(lpName) ) { Unicode = &NtCurrentTeb()->StaticUnicodeString; RtlInitAnsiString(&AnsiString,lpName); Status = RtlAnsiStringToUnicodeString(Unicode,&AnsiString,FALSE); if ( !NT_SUCCESS(Status) ) { if ( Status == STATUS_BUFFER_OVERFLOW ) { SetLastError(ERROR_FILENAME_EXCED_RANGE); } else { BaseSetLastNTError(Status); } return NULL; } NameBuffer = (LPCWSTR)Unicode->Buffer; } return CreateFileMappingW( hFile, lpFileMappingAttributes, flProtect, dwMaximumSizeHigh, dwMaximumSizeLow, NameBuffer ); } HANDLE APIENTRY CreateFileMappingW( HANDLE hFile, LPSECURITY_ATTRIBUTES lpFileMappingAttributes, DWORD flProtect, DWORD dwMaximumSizeHigh, DWORD dwMaximumSizeLow, LPCWSTR lpName ) /*++ Routine Description: A file mapping object can be created using CreateFileMapping Creating a file mapping object creates the potential for mapping a view of the file into an address space. File mapping objects may be shared either through process creation or handle duplication. Having a handle to a file mapping object allows for mapping of the file. It does not mean that the file is actually mapped. A file mapping object has a maximum size. This is used to size the file. A file may not grow beyond the size specified in the mapping object. While not required, it is recommended that when opening a file that you intend to map, the file should be opened for exclusive access. Win32 does not require that a mapped file and a file accessed via the IO primitives (ReadFile/WriteFile) are coherent. In addition to the STANDARD_RIGHTS_REQUIRED access flags, the following object type specific access flags are valid for file mapping objects: - FILE_MAP_WRITE - Write map access to the file mapping object is desired. This allows a writable view of the file to be mapped. Note that if flProtect does not include PAGE_READWRITE, this access type does not allow writing the mapped file. - FILE_MAP_READ - Read map access to the file mapping object is desired. This allows a readablee view of the file to be mapped. - FILE_MAP_ALL_ACCESS - This set of access flags specifies all of the possible access flags for a file mapping object. Arguments: hFile - Supplies an open handle to a file that a mapping object is to be created for. The file must be opened with an access mode that is compatible with the specified pretection flags. A value of INVALID_HANDLE_VALUE specifies that the mapping object is backed by the system paging file. If this is the case, a size must be specified. lpFileMappingAttributes - An optional parameter that may be used to specify the attributes of the new file mapping object. If the parameter is not specified, then the file mapping object is created without a security descriptor, and the resulting handle is not inherited on process creation: flProtect - The protection desired for mapping object when the file is mapped. flProtect Values PAGE_READONLY - Read access to the committed region of pages is allowed. An attempt to write or execute the committed region results in an access violation. The specified hFile must have been created with GENERIC_READ access. PAGE_READWRITE - Read and write access to the committed region of pages is allowed. The specified hFile must have been created with GENERIC_READ and GENERIC_WRITE access. PAGE_WRITECOPY - Read and copy on write access to the committed region of pages is allowed. The specified hFile must have been created with GENERIC_READ access. dwMaximumSizeHigh - Supplies the high order 32-bits of the maximum size of the file mapping object. dwMaximumSizeLow - Supplies the low order 32-bits of the maximum size of the file mapping object. A value of zero along with a value of zero in dwMaximumSizeHigh indicates that the size of the file mapping object is equal to the current size of the file specified by hFile. lpName - Supplies the name ofthe file mapping object. Return Value: NON-NULL - Returns a handle to the new file mapping object. The handle has full access to the new file mapping object and may be used in any API that requires a handle to a file mapping object. FALSE/NULL - The operation failed. Extended error status is available using GetLastError. --*/ { HANDLE Section; NTSTATUS Status; LARGE_INTEGER SectionSizeData; PLARGE_INTEGER SectionSize; OBJECT_ATTRIBUTES Obja; POBJECT_ATTRIBUTES pObja; ACCESS_MASK DesiredAccess; UNICODE_STRING ObjectName; ULONG AllocationAttributes; DesiredAccess = STANDARD_RIGHTS_REQUIRED | SECTION_QUERY | SECTION_MAP_READ; AllocationAttributes = flProtect & (SEC_FILE | SEC_IMAGE | SEC_RESERVE | SEC_COMMIT | SEC_NOCACHE); flProtect ^= AllocationAttributes; if (AllocationAttributes == 0) { AllocationAttributes = SEC_COMMIT; } if ( flProtect == PAGE_READWRITE ) { DesiredAccess |= (SECTION_MAP_READ | SECTION_MAP_WRITE); } else if ( flProtect != PAGE_READONLY && flProtect != PAGE_WRITECOPY ) { SetLastError(ERROR_INVALID_PARAMETER); return NULL; } if ( ARGUMENT_PRESENT(lpName) ) { RtlInitUnicodeString(&ObjectName,lpName); pObja = BaseFormatObjectAttributes(&Obja,lpFileMappingAttributes,&ObjectName); } else { pObja = BaseFormatObjectAttributes(&Obja,lpFileMappingAttributes,NULL); } if ( dwMaximumSizeLow || dwMaximumSizeHigh ) { SectionSize = &SectionSizeData; SectionSize->LowPart = dwMaximumSizeLow; SectionSize->HighPart = dwMaximumSizeHigh; } else { SectionSize = NULL; } if (hFile == INVALID_HANDLE_VALUE) { hFile = NULL; if ( !SectionSize ) { SetLastError(ERROR_INVALID_PARAMETER); return NULL; } } Status = NtCreateSection( &Section, DesiredAccess, pObja, SectionSize, flProtect, AllocationAttributes, hFile ); if ( !NT_SUCCESS(Status) ) { BaseSetLastNTError(Status); return Section = NULL; } else { if ( Status == STATUS_OBJECT_NAME_EXISTS ) { SetLastError(ERROR_ALREADY_EXISTS); } else { SetLastError(0); } } return Section; } HANDLE APIENTRY OpenFileMappingA( DWORD dwDesiredAccess, BOOL bInheritHandle, LPCSTR lpName ) /*++ Routine Description: ANSI thunk to OpenFileMappingW --*/ { PUNICODE_STRING Unicode; ANSI_STRING AnsiString; NTSTATUS Status; if ( ARGUMENT_PRESENT(lpName) ) { Unicode = &NtCurrentTeb()->StaticUnicodeString; RtlInitAnsiString(&AnsiString,lpName); Status = RtlAnsiStringToUnicodeString(Unicode,&AnsiString,FALSE); if ( !NT_SUCCESS(Status) ) { if ( Status == STATUS_BUFFER_OVERFLOW ) { SetLastError(ERROR_FILENAME_EXCED_RANGE); } else { BaseSetLastNTError(Status); } return NULL; } } else { BaseSetLastNTError(STATUS_INVALID_PARAMETER); return NULL; } return OpenFileMappingW( dwDesiredAccess, bInheritHandle, (LPCWSTR)Unicode->Buffer ); } HANDLE APIENTRY OpenFileMappingW( DWORD dwDesiredAccess, BOOL bInheritHandle, LPCWSTR lpName ) { OBJECT_ATTRIBUTES Obja; UNICODE_STRING ObjectName; NTSTATUS Status; HANDLE Object; if ( !lpName ) { BaseSetLastNTError(STATUS_INVALID_PARAMETER); return NULL; } RtlInitUnicodeString(&ObjectName,lpName); InitializeObjectAttributes( &Obja, &ObjectName, (bInheritHandle ? OBJ_INHERIT : 0), BaseGetNamedObjectDirectory(), NULL ); if ( dwDesiredAccess == FILE_MAP_COPY ) { dwDesiredAccess = FILE_MAP_READ; } Status = NtOpenSection( &Object, dwDesiredAccess, &Obja ); if ( !NT_SUCCESS(Status) ) { BaseSetLastNTError(Status); return NULL; } return Object; } LPVOID APIENTRY MapViewOfFile( HANDLE hFileMappingObject, DWORD dwDesiredAccess, DWORD dwFileOffsetHigh, DWORD dwFileOffsetLow, SIZE_T dwNumberOfBytesToMap ) /*++ Routine Description: A view of a file may be mapped into the address space of the calling process using MapViewOfFile. Mapping a file object makes the specified portion of the file visible in the address space of the calling process. The return address is a pointer to memory that when addressed causes data within the file to be accessed. Mapping a view of a file has some simple coherency rules: - Multiple views on a file are coherent if they are derived from the same file mapping object. If a process opens a file, creates a mapping object, duplicates the object to another process... If both processes map a view of the file, they will both see a coherent view of the file's data... they will effectively be viewing shared memory backed by the file. - If multiple mapping objects exist for the same file, then views derived from the different mapping objects are not garunteed to be coherent. - A mapped view on a file is not garunteed to be coherent with a file being accessed via ReadFile or WriteFile. Arguments: hFileMappingObject - Supplies an open handle to a file mapping object that is to be mapped into the callers address space. dwDesiredAccess - Specifies the access that is requested to the file mapping object. This determines the page protection of the pages mapped by the file. dwDesiredAccess Values: FILE_MAP_WRITE - Read/write access is desired. The mapping object must have been created with PAGE_READWRITE protection. The hFileMappingObject must have been created with FILE_MAP_WRITE access. A read/write view of the file will be mapped. FILE_MAP_READ - Read access is desired. The mapping object must have been created with PAGE_READWRITE or PAGE_READ protection. The hFileMappingObject must have been created with FILE_MAP_READ access. A read only view of the file will be mapped. dwFileOffsetHigh - Supplies the high order 32-bits of the file offset where mapping is to begin. dwFileOffsetLow - Supplies the low order 32-bits of the file offset where mapping is to begin. The combination of the high and low offsets must specify a 64Kb aligned offset within the file. It is an error if this is not the case. dwNumberOfBytesToMap - Supplies the number of bytes of the file to map. A value of zero specifies that the entire file is to be mapped. Return Value: NON-NULL - Returns the address of where the file is mapped. NULL - The operation failed. Extended error status is available using GetLastError. --*/ { return MapViewOfFileEx( hFileMappingObject, dwDesiredAccess, dwFileOffsetHigh, dwFileOffsetLow, dwNumberOfBytesToMap, NULL ); } LPVOID APIENTRY MapViewOfFileEx( HANDLE hFileMappingObject, DWORD dwDesiredAccess, DWORD dwFileOffsetHigh, DWORD dwFileOffsetLow, SIZE_T dwNumberOfBytesToMap, LPVOID lpBaseAddress ) /*++ Routine Description: A view of a file may be mapped into the address space of the calling process using MapViewOfFileEx. Mapping a file object makes the specified portion of the file visible in the address space of the calling process. The return address is a pointer to memory that when addressed causes data within the file to be accessed. This API allows the caller to supply the system with a suggested mapping address. The system will round this address down to the nearest 64k boundry and attempt to map the file at thet address. If there is not enough address space at that address, this call will fail. Mapping a view of a file has some simple coherency rules: - Multiple views on a file are coherent if they are derived from the same file mapping object. If a process opens a file, creates a mapping object, duplicates the object to another process... If both processes map a view of the file, they will both see a coherent view of the file's data... they will effectively be viewing shared memory backed by the file. - If multiple mapping objects exist for the same file, then views derived from the different mapping objects are not garunteed to be coherent. - A mapped view on a file is not garunteed to be coherent with a file being accessed via ReadFile or WriteFile. Arguments: hFileMappingObject - Supplies an open handle to a file mapping object that is to be mapped into the callers address space. dwDesiredAccess - Specifies the access that is requested to the file mapping object. This determines the page protection of the pages mapped by the file. dwDesiredAccess Values: FILE_MAP_WRITE - Read/write access is desired. The mapping object must have been created with PAGE_READWRITE protection. The hFileMappingObject must have been created with FILE_MAP_WRITE access. A read/write view of the file will be mapped. FILE_MAP_READ - Read access is desired. The mapping object must have been created with PAGE_READWRITE or PAGE_READ protection. The hFileMappingObject must have been created with FILE_MAP_READ access. A read only view of the file will be mapped. dwFileOffsetHigh - Supplies the high order 32-bits of the file offset where mapping is to begin. dwFileOffsetLow - Supplies the low order 32-bits of the file offset where mapping is to begin. The combination of the high and low offsets must specify a 64Kb aligned offset within the file. It is an error if this is not the case. dwNumberOfBytesToMap - Supplies the number of bytes of the file to map. A value of zero specifies that the entire file is to be mapped. lpBaseAddress - Supplies the base address of where in the processes address space the mapping is to begin at. The address is rounded down to the nearest 64k boundry by the system. A value of NULL for this parameter operates exactly the same as MapViewOfFile... The system picks the mapping base address without any hint from the caller. Return Value: NON-NULL - Returns the address of where the file is mapped. NULL - The operation failed. Extended error status is available using GetLastError. --*/ { NTSTATUS Status; LARGE_INTEGER SectionOffset; SIZE_T ViewSize; PVOID ViewBase; ULONG Protect; SectionOffset.LowPart = dwFileOffsetLow; SectionOffset.HighPart = dwFileOffsetHigh; ViewSize = dwNumberOfBytesToMap; ViewBase = lpBaseAddress; if ( dwDesiredAccess == FILE_MAP_COPY ) { Protect = PAGE_WRITECOPY; } else if ( dwDesiredAccess & FILE_MAP_WRITE ) { Protect = PAGE_READWRITE; } else if ( dwDesiredAccess & FILE_MAP_READ ) { Protect = PAGE_READONLY; } else { Protect = PAGE_NOACCESS; } Status = NtMapViewOfSection( hFileMappingObject, NtCurrentProcess(), &ViewBase, 0L, 0L, &SectionOffset, &ViewSize, ViewShare, 0L, Protect ); if ( !NT_SUCCESS(Status) ) { BaseSetLastNTError(Status); return NULL; } return ViewBase; } BOOL APIENTRY FlushViewOfFile( LPCVOID lpBaseAddress, SIZE_T dwNumberOfBytesToFlush ) /*++ Routine Description: A byte range within a mapped view of a file can be flushed to disk using FlushViewOfFile. A byte range within a mapped view of a file can be flushed to disk using FlushViewOfFile. Flushing a range of a mapped view causes any dirty pages within that range to be written to disk. This operation automatically happens whenever a view is unmapped (either explicitly or as a result of process termination). Arguments: lpBaseAddress - Supplies the base address of a set of bytes that are to be flushed to the on disk representation of the mapped file. dwNumberOfBytesToFlush - Supplies the number of bytes to flush. Return Value: TRUE - The operation was successful. All dirty pages within the specified range are stored in the on-disk representation of the mapped file. FALSE - The operation failed. Extended error status is available using GetLastError. --*/ { NTSTATUS Status; PVOID BaseAddress; SIZE_T RegionSize; IO_STATUS_BLOCK IoStatus; BaseAddress = (PVOID)lpBaseAddress; RegionSize = dwNumberOfBytesToFlush; Status = NtFlushVirtualMemory( NtCurrentProcess(), &BaseAddress, &RegionSize, &IoStatus ); if ( !NT_SUCCESS(Status) ) { if ( Status == STATUS_NOT_MAPPED_DATA ) { return TRUE; } BaseSetLastNTError(Status); return FALSE; } return TRUE; } BOOL APIENTRY UnmapViewOfFile( LPCVOID lpBaseAddress ) /*++ Routine Description: A previously mapped view of a file may be unmapped from the callers address space using UnmapViewOfFile. Arguments: lpBaseAddress - Supplies the base address of a previously mapped view of a file that is to be unmapped. This value must be identical to the value returned by a previous call to MapViewOfFile. Return Value: TRUE - The operation was successful. All dirty pages within the specified range are stored in the on-disk representation of the mapped file. FALSE - The operation failed. Extended error status is available using GetLastError. --*/ { NTSTATUS Status; Status = NtUnmapViewOfSection(NtCurrentProcess(),(PVOID)lpBaseAddress); if ( !NT_SUCCESS(Status) ) { if (Status == STATUS_INVALID_PAGE_PROTECTION) { // // Unlock any pages that were locked with MmSecureVirtualMemory. // This is useful for SANs. // if (RtlFlushSecureMemoryCache((PVOID)lpBaseAddress, 0)) { Status = NtUnmapViewOfSection(NtCurrentProcess(), (PVOID)lpBaseAddress ); if (NT_SUCCESS( Status )) { return( TRUE ); } } } BaseSetLastNTError(Status); return FALSE; } return TRUE; }