From: Nikolay Sivov nsivov@codeweavers.com
--- dlls/ntdll/tests/file.c | 54 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+)
diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c index c87038d5ab1..8c06babde1a 100644 --- a/dlls/ntdll/tests/file.c +++ b/dlls/ntdll/tests/file.c @@ -87,6 +87,7 @@ static NTSTATUS (WINAPI *pNtQueryVolumeInformationFile)(HANDLE,PIO_STATUS_BLOCK, static NTSTATUS (WINAPI *pNtQueryFullAttributesFile)(const OBJECT_ATTRIBUTES*, FILE_NETWORK_OPEN_INFORMATION*); static NTSTATUS (WINAPI *pNtFlushBuffersFile)(HANDLE, IO_STATUS_BLOCK*); static NTSTATUS (WINAPI *pNtQueryEaFile)(HANDLE,PIO_STATUS_BLOCK,PVOID,ULONG,BOOLEAN,PVOID,ULONG,PULONG,BOOLEAN); +static NTSTATUS (WINAPI *pNtExtendSection)(HANDLE,LARGE_INTEGER*);
static WCHAR fooW[] = {'f','o','o',0};
@@ -6058,11 +6059,13 @@ static void test_file_map_large_size(void) { char temp_path[MAX_PATH], source[MAX_PATH]; HANDLE hfile, hmapfile; + LARGE_INTEGER li; NTSTATUS status; SIZE_T size; void *addr; DWORD ret;
+ /* Resizing mapped filed on range commit */ ret = GetTempPathA(MAX_PATH, temp_path); ok(!!ret, "GetTempPath() failed error %ld\n", GetLastError());
@@ -6110,6 +6113,56 @@ static void test_file_map_large_size(void) CloseHandle(hmapfile); CloseHandle(hfile); DeleteFileA(source); + + /* Explicit resize */ + if (!pNtExtendSection) + { + skip("NtExtendSection() is not available.\n"); + return; + } + + ret = GetTempFileNameA(temp_path, "pfx", 0, source); + ok(!!ret, "GetTempFileName() failed %ld\n", GetLastError()); + + hfile = CreateFileA(source, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0 ); + ok(hfile != INVALID_HANDLE_VALUE, "Failed to create a test file.\n"); + + SetFilePointer(hfile, 0x400, NULL, FILE_BEGIN); + SetEndOfFile(hfile); + + status = NtCreateSection(&hmapfile, SECTION_MAP_READ, NULL, NULL, PAGE_READWRITE, SEC_RESERVE, hfile); + ok(!status, "Failed to create a section %#lx.\n", status); + + li.QuadPart = 0x500; + status = pNtExtendSection(hmapfile, &li); + ok(status == STATUS_ACCESS_DENIED, "Unexpected return value %#lx.\n", status); + + ret = GetFileSize(hfile, NULL); + ok(ret == 0x400, "Unexpected size %lu.\n", ret); + + CloseHandle(hmapfile); + + status = NtCreateSection(&hmapfile, SECTION_MAP_READ | SECTION_EXTEND_SIZE, NULL, NULL, PAGE_READWRITE, SEC_RESERVE, hfile); + ok(!status, "Failed to extend a section %#lx.\n", status); + + li.QuadPart = 0x500; + status = pNtExtendSection(hmapfile, &li); + ok(!status, "Failed to create a section %#lx.\n", status); + + ret = GetFileSize(hfile, NULL); + ok(ret == 0x500, "Unexpected size %lu.\n", ret); + + li.QuadPart = 0x100; + status = pNtExtendSection(hmapfile, &li); + ok(!status, "Failed to extend a section %#lx.\n", status); + + ret = GetFileSize(hfile, NULL); + ok(ret == 0x500, "Unexpected size %lu.\n", ret); + + CloseHandle(hmapfile); + + CloseHandle(hfile); + DeleteFileA(source); }
START_TEST(file) @@ -6155,6 +6208,7 @@ START_TEST(file) pNtQueryFullAttributesFile = (void *)GetProcAddress(hntdll, "NtQueryFullAttributesFile"); pNtFlushBuffersFile = (void *)GetProcAddress(hntdll, "NtFlushBuffersFile"); pNtQueryEaFile = (void *)GetProcAddress(hntdll, "NtQueryEaFile"); + pNtExtendSection = (void *)GetProcAddress(hntdll, "NtExtendSection");
test_read_write(); test_NtCreateFile();
From: Nikolay Sivov nsivov@codeweavers.com
--- dlls/ntdll/tests/file.c | 4 ---- dlls/ntdll/unix/virtual.c | 5 ++--- server/mapping.c | 28 +++++++++++++++++++++++++--- 3 files changed, 27 insertions(+), 10 deletions(-)
diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c index 8c06babde1a..cd7deda7c5b 100644 --- a/dlls/ntdll/tests/file.c +++ b/dlls/ntdll/tests/file.c @@ -6089,7 +6089,6 @@ static void test_file_map_large_size(void)
status = NtMapViewOfSection(hmapfile, GetCurrentProcess(), &addr, 0, 0, NULL, &size, ViewUnmap, MEM_RESERVE, PAGE_READONLY); - todo_wine ok(!status, "Failed to map the section %#lx.\n", status);
ret = GetFileSize(hfile, NULL); @@ -6099,15 +6098,12 @@ static void test_file_map_large_size(void) ok(!!addr, "Failed to resize, error %ld.\n", GetLastError());
ret = GetFileSize(hfile, NULL); - todo_wine ok(ret == 0x1000, "Unexpected size %lu.\n", ret);
addr = VirtualAlloc(addr, 0x1100, MEM_COMMIT, PAGE_READONLY); - todo_wine ok(!!addr, "Failed to resize, error %ld.\n", GetLastError());
ret = GetFileSize(hfile, NULL); - todo_wine ok(ret == 0x2000, "Unexpected size %lu.\n", ret);
CloseHandle(hmapfile); diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c index e733e3ffdd6..cd5dcb0465a 100644 --- a/dlls/ntdll/unix/virtual.c +++ b/dlls/ntdll/unix/virtual.c @@ -3541,7 +3541,7 @@ static unsigned int virtual_map_section( HANDLE handle, PVOID *addr_ptr, ULONG_P if (*size_ptr) { size = *size_ptr; - if (size > full_size - offset.QuadPart) return STATUS_INVALID_VIEW_SIZE; + if (!(alloc_type & MEM_RESERVE) && (size > full_size - offset.QuadPart)) return STATUS_INVALID_VIEW_SIZE; } else { @@ -5003,9 +5003,8 @@ static NTSTATUS allocate_virtual_memory( void **ret, SIZE_T *size_ptr, ULONG typ else /* commit the pages */ { if (!(view = find_view( base, size ))) status = STATUS_NOT_MAPPED_VIEW; - else if (view->protect & SEC_FILE) status = STATUS_ALREADY_COMMITTED; else if (view->protect & VPROT_FREE_PLACEHOLDER) status = STATUS_CONFLICTING_ADDRESSES; - else if (!(status = set_protection( view, base, size, protect )) && (view->protect & SEC_RESERVE)) + else if (!(status = set_protection( view, base, size, protect )) && (view->protect & (SEC_FILE|SEC_RESERVE))) { SERVER_START_REQ( add_mapping_committed_range ) { diff --git a/server/mapping.c b/server/mapping.c index c3f57b6394c..bfd1e0d70be 100644 --- a/server/mapping.c +++ b/server/mapping.c @@ -1564,8 +1564,7 @@ DECL_HANDLER(map_view)
if ((mapping->flags & SEC_IMAGE) || req->start >= mapping->size || - req->start + req->size < req->start || - req->start + req->size > round_size( mapping->size, page_mask )) + req->start + req->size < req->start) { set_error( STATUS_INVALID_PARAMETER ); goto done; @@ -1712,7 +1711,30 @@ DECL_HANDLER(add_mapping_committed_range) { struct memory_view *view = find_mapped_view( current->process, req->base );
- if (view) add_committed_range( view, req->offset, req->offset + req->size ); + if (view) + { + if (view->flags & SEC_FILE) + { + struct stat st; + int unix_fd; + + if ((unix_fd = get_unix_fd( view->fd )) == -1) return; + if (fstat( unix_fd, &st ) == -1) + { + file_set_error(); + return; + } + + if ((req->offset + req->size) <= st.st_size) + set_error( STATUS_ALREADY_COMMITTED ); + else + grow_file( unix_fd, req->offset + req->size ); + } + else + { + add_committed_range( view, req->offset, req->offset + req->size ); + } + } }
/* check if two memory maps are for the same file */
I'd like some comments first on how to improve this, as it touches multiple existing checks.