When error 1224: ERROR_USER_MAPPED_FILE occurs? - c++

I want to really understand when the ERROR_USER_MAPPED_FILE occurs. So I wrote some snippets. To reproduce the error. But it did not work. Please help me fix my code
Process 1:
HANDLE hFile = CreateFile("C:\\test\\full.exe", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE)
return GetLastError();
HANDLE hMapFile = CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, 0, NULL);
if (hMapFile == INVALID_HANDLE_VALUE)
return GetLastError();
mapHandles.push_back(hMapFile);
viewHandles.push_back(MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, 0));
I am Halting the process and I have not closed any view of the map and file handles yet in this process so that when the other process tries to open the file. I thought error 1224 will be thrown.
Process 2:
HANDLE hFile = CreateFile("C:\\test\\full.exe", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE)
cout << "Error Code : " << GetLastError() << endl;
char buffer[1025];
DWORD bytesRead;
if (!ReadFile(hFile, buffer, 1024, &bytesRead, 0))
cout << "Error Code : " << GetLastError() << endl;
The CreateFile and ReadFile succeeds in the process 2.
Actually I am trying to handle this error 1224 separately. Which means when the file fails with error 32 I want to do something. and if the file fails with error 1224 I want to do something.
Now I must test those cases. In order to test those scenarios I should reproduce the error 1224.

I want to really understand when the ERROR_USER_MAPPED_FILE occurs
if really understand let some extra info.
at first this error returned from kernel. so it was initially NTSTATUS error code, which than translated to win32 error by RtlNtStatusToDosError. api for reverse translation not exist - because it not uniquely, but possible yourself write code, which create reverse translation map. two NTSTATUS codes is translated to ERROR_USER_MAPPED_FILE : STATUS_USER_MAPPED_FILE and STATUS_PURGE_FAILED:
if (
RtlNtStatusToDosError(STATUS_USER_MAPPED_FILE) != ERROR_USER_MAPPED_FILE
||
RtlNtStatusToDosError(STATUS_PURGE_FAILED) != ERROR_USER_MAPPED_FILE
)
{
__debugbreak();
}
for completely understand when this codes returned need look File System source code. we have fastfat example. if search for STATUS_USER_MAPPED_FILE - we can found that this code returned from 4 place:
FatSupersedeOrOverwriteFile - when we try call
ZwCreateFile with FILE_OVERWRITE_IF or FILE_SUPERSEDE
CreateOption or when we call CreateFile with CREATE_ALWAYS
FatSetEndOfFileInfo - when we call ZwSetInformationFile
with FileEndOfFileInformation or SetEndOfFile function
FatSetValidDataLengthInfo- when we call
ZwSetInformationFile with
FileValidDataLengthInformation or SetFileValidData
function (we need have SE_MANAGE_VOLUME_PRIVILEGE for this)
FatSetAllocationInfo - when we use ZwSetInformationFile
with FileAllocationInformation (no win32 api shell)
and you can note common pattern here:
if (!MmCanFileBeTruncated()) return STATUS_USER_MAPPED_FILE;
about demo code for reproduce this error - for what you need two processes ?!? single routine in single process - more than enough.
void test()
{
// for simplicity, i have access to this location as admin
STATIC_OBJECT_ATTRIBUTES(oa, "\\systemroot\\temp\\.tmp");
HANDLE hFile, hSection, hFile2;
IO_STATUS_BLOCK iosb;
LARGE_INTEGER AllocationSize = { PAGE_SIZE };
NTSTATUS status;
if (0 <= NtCreateFile(&hFile, FILE_GENERIC_WRITE|FILE_GENERIC_READ, &oa, &iosb, &AllocationSize, 0,
FILE_SHARE_VALID_FLAGS, FILE_OPEN_IF, FILE_SYNCHRONOUS_IO_NONALERT, 0, 0))
{
status = NtCreateSection(&hSection, SECTION_MAP_READ|SECTION_MAP_WRITE, 0, &AllocationSize, PAGE_READWRITE, SEC_COMMIT, hFile);
if (0 <= status)
{
PVOID BaseAddress = 0;
SIZE_T ViewSize = 0;
status = ZwMapViewOfSection(hSection, NtCurrentProcess(), &BaseAddress, 0, 0, 0, &ViewSize, ViewUnmap, 0, PAGE_READONLY);
NtClose(hSection);
if (0 <= status)
{
LARGE_INTEGER Eof = {};
// SetEndOfFile win32 api
status = ZwSetInformationFile(hFile, &iosb, &Eof, sizeof(Eof), FileEndOfFileInformation);
if (status != STATUS_USER_MAPPED_FILE) __debugbreak();
// no win32 api
status = ZwSetInformationFile(hFile, &iosb, &Eof, sizeof(Eof), FileAllocationInformation);
if (status != STATUS_USER_MAPPED_FILE) __debugbreak();
// SetFileValidData win32 api
// we need have SE_MANAGE_VOLUME_NAME privilege, otherwise STATUS_PRIVILEGE_NOT_HELD
status = ZwSetInformationFile(hFile, &iosb, &Eof, sizeof(Eof), FileValidDataLengthInformation);
switch (status)
{
case STATUS_USER_MAPPED_FILE:
case STATUS_PRIVILEGE_NOT_HELD:
break;
default: __debugbreak();
}
//CreateFileW(L"\\\\?\\c:\\windows\\temp\\.tmp", FILE_GENERIC_READ|FILE_GENERIC_WRITE, FILE_SHARE_VALID_FLAGS, 0, CREATE_ALWAYS, 0, 0);
status = NtCreateFile(&hFile2, FILE_GENERIC_WRITE|FILE_GENERIC_READ, &oa, &iosb, 0, 0,
FILE_SHARE_VALID_FLAGS, FILE_OVERWRITE_IF, FILE_SYNCHRONOUS_IO_NONALERT, 0, 0);
if (status != STATUS_USER_MAPPED_FILE) __debugbreak();
status = NtCreateFile(&hFile2, FILE_GENERIC_WRITE|FILE_GENERIC_READ, &oa, &iosb, 0, 0,
FILE_SHARE_VALID_FLAGS, FILE_SUPERSEDE, FILE_SYNCHRONOUS_IO_NONALERT, 0, 0);
if (status != STATUS_USER_MAPPED_FILE) __debugbreak();
ZwUnmapViewOfSection(NtCurrentProcess(), BaseAddress);
}
}
NtClose(hFile);
}
}
about STATUS_PURGE_FAILED - look like in can be returned when we call WriteFile - look here - but i can not reproduce it in test. however very rarely this error can occur - "STATUS_PURGE_FAILED" error when you perform VM replications by using SCVMM in Windows Server 2012 R2

ERROR_USER_MAPPED_FILE or error 1224 occurs when you try to delete or overwrite a file which has been mapped by other process.
Process #1
HANDLE hFile = CreateFile("C:\\test\\full.exe", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE)
return GetLastError();
HANDLE hMapFile = CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, 0, NULL);
if (hMapFile == INVALID_HANDLE_VALUE)
return GetLastError();
mapHandles.push_back(hMapFile);
viewHandles.push_back(MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, 0));
Process #2
HANDLE hFile = CreateFile("C:\\test\\full.exe", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
if(GetLastError() == 1224)
// File has been mapped by other process
else
// some other issue
}
In Process #2, CREATE_ALWAYS tries to overwrite a file which has been mapped. So it ends up throwing error 1224.

Related

DeviceIoControl fails with error 395 to set a reparse point

Recently I posted this question and now I am trying to set a reparse point after a file modification with WordPad app. Currently I checked that the reparse point is a Microsoft tag and I can save the reparse point data in a REPARSE_DATA_BUFFER pointer before the file lose the reparse point. But when I try to set the reparse point to the file, after a file modification, I always get the 395 error with the GetLastError function after call to DeviceIoControl function using the control code FSCTL_SET_REPARSE_POINT. The error 395 doesn't appear in this System Error Codes although I found this error here that has sense. I also removed the discretionary access control list (DACL) from the file, to grants full access to the file by everyone, before try to set the reparse point but I got the same error. Here I put two fragments of my code to get and set the reparse point. I will appreciate any help.
Code to get the reparse point
HANDLE hDevice = CreateFile(
filePath.c_str(), // File path in the computer
0,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT,
NULL);
if (hDevice != INVALID_HANDLE_VALUE)
{
size_t maxReparse = MAXIMUM_REPARSE_DATA_BUFFER_SIZE;
rdb = (REPARSE_DATA_BUFFER*)malloc(maxReparse); // rdb was declared as: REPARSE_DATA_BUFFER* rdb;
DWORD outBufferSize = maxReparse;
DWORD bytesReturned = 0;
if (DeviceIoControl(hDevice, FSCTL_GET_REPARSE_POINT, NULL, 0, rdb, outBufferSize, &bytesReturned, NULL))
{
if (rdb != NULL)
{
if (IsReparseTagMicrosoft(rdb->ReparseTag))
{
wprintf(L"Is a Microsoft tag.\n");
}
Code to set the reparse point
LPTSTR pszObjName = const_cast<wchar_t*>(filePath.c_str()); // File path in the computer
PACL newDACL = NULL; // NULL discretionary access control list to grant full access to everyone
DWORD secInfo = SetNamedSecurityInfo(pszObjName, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION, NULL, NULL, newDACL, NULL);
if (secInfo == ERROR_SUCCESS)
{
HANDLE hDevice = CreateFile(filePath.c_str(),
GENERIC_ALL, //GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, NULL);
if (hDevice != INVALID_HANDLE_VALUE)
{
size_t maxReparse = MAXIMUM_REPARSE_DATA_BUFFER_SIZE;
DWORD inBufferSize = maxReparse;
if (rdb != NULL)
{
DWORD bytesReturned = 0;
if (!DeviceIoControl(hDevice, FSCTL_SET_REPARSE_POINT, rdb, inBufferSize, NULL, 0, &bytesReturned, NULL))
{
DWORD error = GetLastError(); // Error 395
unsigned long errorUL = error;
wprintf(L"Error %lu in DeviceIoControl method.\n", errorUL);
}

How to convert L"\\\\.\\C:" to L"\\\\.\\PhysicalDrive0"

I am newbie. The code is that I copied on internet. And I don't really understand it.
I'm learning C ++, so even though the code is C, I want to switch to C ++. I need to understand the code and output the screen:
Partition Styles/Scheme: is MBR disk/drive // is GPT disk/drive // or is RAW disk/drive
Partition Number of a Disk/Drive
I put breakpoint at line below, press F5 on Visual Studio 2013 (run as admin):
DWORD part_num = szPartINF.PartitionNumber;
If I leave:
hDevice = CreateFile(L"\\\\.\\C:", 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0);
the code runs successfully (part_num have value = 2 . It is right, because my Disk0 have 2 partitions)
And, I change to:
hDevice = CreateFile(L"\\\\.\\PhysicalDrive0", 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0);
the code runs fails/unsuccess (part_num = 0)
I need to use "\\\.\\PhysicalDrive0" rather than "\\\.\\C:".
I still have another problem: I use the clean command in DiskPart for My Hard Drive. When I ran the test, the code did not recognize PartitionStyle RAW correctly, because this time my hard drive was RAW DISK (and certainly not PartitionStyle MBR or PartitionStyle GPT).
Please help me.
Thanks.
#include "windows.h"
#include <stdio.h>
#include <iostream>
//////// ok, go ///////////
int main(int argc, char* argv[])
{
HANDLE hDevice = INVALID_HANDLE_VALUE;
PARTITION_INFORMATION_EX szPartINF;
DWORD cbReturned = 0;
__try
{
hDevice = CreateFile(L"\\\\.\\PhysicalDrive0", 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0);
//hDevice = CreateFile(L"\\\\.\\C:", 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0);
if (hDevice == INVALID_HANDLE_VALUE) { return FALSE; }
RtlZeroMemory(&szPartINF, sizeof(szPartINF));
if (FALSE != DeviceIoControl(hDevice, IOCTL_DISK_GET_PARTITION_INFO_EX, NULL, 0, (LPVOID)&szPartINF, sizeof(PARTITION_INFORMATION_EX), &cbReturned, NULL))
{
DWORD part_num = szPartINF.PartitionNumber;
DWORD part_style = szPartINF.PartitionStyle;
return TRUE;
}
else
{
cbReturned = GetLastError();
wprintf(L"\n%08X (%d)\n", cbReturned, cbReturned);
}
}
__finally
{
if (hDevice != INVALID_HANDLE_VALUE) { CloseHandle(hDevice); }
}
return FALSE;
bool success;
cin >> success; //for wait to close cmd.
}
"\\\\.\PhysicalDrive0" is not necessarily "\\\\.\\C:".
You can check This PC->Manage->Storage->Disk Management:
The Disk 0 means PhysicalDrive0.If you need the corresponding physical disk.You can refer to How to list physical disks?

UnmapViewOfFile does not release file. Unable to access File after function is executed.

I am trying to upload a file to a cloud service using winhttp, however after running the below code, i am unable to access the same file anymore. It seems like the program is not closing its file handle properly:
HANDLE hFile = CreateFileW(MultiByteToWideChar(filePath), GENERIC_READ, FILE_SHARE_READ+FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
DWORD dwFileSize = GetFileSize(hFile, NULL);
HANDLE hFileMappingObject = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, dwFileSize, NULL);
HANDLE file = MapViewOfFile(hFileMappingObject, FILE_MAP_READ, 0, 0, 0);
bool result = WinHttpSendRequest( hRequest,
WINHTTP_NO_ADDITIONAL_HEADERS,
0, WINHTTP_NO_REQUEST_DATA, 0,
dwFileSize, 0);
result = WinHttpWriteData( hRequest, file, dwFileSize, &dwBytesWritten);
FlushViewOfFile(file, dwFileSize);
FlushFileBuffers(hFile);
UnmapViewOfFile(file);
CloseHandle(hFileMappingObject);
CloseHandle(hFile);

Why does CreateFile return invalid handle?

I have CreateFile() to create a hidden file type but the problem that it keeps returning invalid handle.
file = CreateFileW(_T("hey.txt"),
GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
0, 0);
error = GetLastError();
WriteFile(file, buff, sizeof(buff),
&dwRet, NULL);
Any idea?
It would probably be best if you showed the exact code that you're using including all the error checking, and how you do it, is important (especially in the case of this question)...
The correct error checking for your code should be something more like...
file = CreateFile(_T("hey.txt"), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0);
if (file == INVALID_HANDLE_VALUE)
{
const DWORD error = GetLastError();
// Do something!
}
else
{
if (!WriteFile(file, buff, sizeof(buff), &dwRet, NULL))
{
const DWORD error = GetLastError();
// Do something!
}
}
You should only be checking for an error if you get a return value of INVALID_FILE_HANDLE as CreateFile() might not reset the last error before it starts and so you might get spurious error values from GetLastError() if the function succeeds...
A last error of 6, ERROR_INVALID_HANDLE, is unusual from CreateFile() unless you're using the template file parameter, which you're not...
Your code using CreateFileW and _T("") is incorrect and wont compile in a non unicode build. Better to use CreateFile and _T("") or CreateFileW and L"".
Your code will not create a hidden file, see molbdnilo's answer.
0 is not a valid parameter for dwFlagsAndAttributes. To create a hidden file, pass FILE_ATTRIBUTE_HIDDEN.
If "C:\test.txt" exists and is hidden, then following code fails (h = INVALID_HANDLE_VALUE) :
h = CreateFile("C:\\test.txt", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0);
this fails too (argument 6 == FILE_ATTRIBUTES_NORMAL or argument6 == 0 seems so be the same) :
h = CreateFile("C:\\test.txt", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
but this works :
h = CreateFile("C:\\test.txt", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_HIDDEN, 0);
So roughly in other words :
if the file already exists and is hidden then CreateFile with "CREATE_ALWAYS" fails if argument 6 != FILE_ATTRIBUTE_HIDDEN.

Named Pipes, Server question

I'm hanging on the WaitNamedPipe function even though I called CreateNamedPipe right before. Since waitnamedpipe function just waits for the initiation of the pipe, why? code is below. thanks
PROCESS_INFORMATION po;
STARTUPINFO
s;
GetStartupInfo (&s);
if(CreateProcess ("c:\s2.exe", NULL, NULL, NULL, false, 0, NULL,
NULL, &s, &po) == FALSE)
{
printf("Error %d starting CC\n",
GetLastError());
exit(-1);
}
HANDLE pipe=CreateNamedPipe (pipe_name, 0x00000003,
FILE_FLAG_FIRST_PIPE_INSTANCE,
PIPE_UNLIMITED_INSTANCES,128, 128, 0,
NULL);
while(WaitNamedPipe(pipe_name, INFINITE)==FALSE) Sleep(300);
HANDLE CC = CreateFile (pipe_name, GENERIC_READ | GENERIC_WRITE, 0, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
NULL);
bool fConnected = ConnectNamedPipe(pipe, NULL) ? TRUE :
(GetLastError() ==
ERROR_PIPE_CONNECTED);
if(fConnected) printf("true");
else printf("false");
"C:\s2.exe" is not "C:\\s2.exe"