FileMapped write access - winapi

I try to write to file while it is opened as file mapped from another process and it fails.
Please look at fragments of code:
access = GENERIC_READ | GENERIC_WRITE;
share = FILE_SHARE_READ | FILE_SHARE_WRITE;
disposition = OPEN_EXISTING;
HANDLE fileHandle = CreateFileA(fileName.c_str(), access, share, 0, disposition, 0);
//...
unsigned long valProtect = 0;
//...
valProtect = PAGE_READWRITE;
//...
const HANDLE mappingHandle = CreateFileMapping(fileHandle, 0, valProtect, 0, 0, 0);
//...
this->m_access = FILE_MAP_ALL_ACCESS;
//...
this->m_startAddress = (uint8_t*)MapViewOfFile(mappingHandle, this->m_access, 0, 0, 0);
//...
CloseHandle(fileHandle);
At this time file is closed (it's handle) but mapped to address space.
I open this file in notepad++, modify it and try to save, but I see message:
"Please check if this file is opened in another program."
So I cannot rewrite it from another process, seems like it's permissions for writing is locked.
If I unmapped file like:
UnmapViewOfFile(this->m_startAddress);
Then I cannot rewrite file again.
What I did wrong?

Notepad++ is likely trying to obtain exclusive access to the file when writing to it, which will fail while the mapping (or anything else using the file) is still open. Many apps obtain exclusive access when writing to files, to avoid other processes reading the data until it is finished being written. You are sharing your file, but Notepad++ is simply asking for too many rights. There is nothing you can do about that in your code.

Related

CreateFile() failed with error code 32 while reading pendrive

I am trying to read raw bytes from a pen drive 'E:', but it gives error code 32 when trying to open the drive using CreateFIle(). My code is as follows:
wchar_t wszDrive[7];
wszDrive[0] = '\\';
wszDrive[1] = '\\';
wszDrive[2] = '.';
wszDrive[3] = '\\';
wszDrive[4] = 'e';
wszDrive[5] = ':';
wszDrive[6] = '\0';
hDevice = CreateFile(wszDrive, //drive name to open
GENERIC_READ | GENERIC_WRITE, ////must be opened with exclusive access(No Sharing)
0, // no access to the drive
NULL, // default security attributes
OPEN_EXISTING, // disposition i.e. if file already exist
0, // file attributes
NULL); // do not copy file attributes
if (hDevice == INVALID_HANDLE_VALUE) // cannot open the drive
{
printf("CreateFile() failed! from read with error %d.\n", GetLastError());// Program prints this line. with error code 32.
return (FALSE);
}
else
cout << "\nCreateFile() successful! in read";
Edit:
The CreateFile() runs fine without errors if I use FILE_SHARE_READ | FILE_SHARE_WRITE:
hDevice = CreateFile(wszDrive,
GENERIC_READ |
GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
0,
NULL);
Why cannot I run with exclusive access?
Error 32 is ERROR_SHARING_VIOLATION.
The process cannot access the file because it is being used by another process.
It means there is already an open handle to the drive, and that handle is using access/sharing rights which are not compatible with the access/sharing rights you are requesting.
That is why you can't open the drive for exclusive access, but you can open it for read/write sharing - the drive is already open elsewhere for reading/writing.
If you want to know where exactly, you can use a tool like SysInternals Process Explorer to see which processes have open handles to which files/folders, devices, etc.

Getting process information of every process

I am trying to create a program that any normal user can run on windows and generate a process list of all processes, including the executable location. I have used CreateToolhelp32Snapshot() to get all process names, pid, ppid. But having issues getting the image path. Everything I do results in pretty much Access Denied.
I have tried ZwQueryInformationProcess, GetProcessImageFileName, etc. and also using OpenProcess to get the handle to each process. I can get the handle by using PROCESS_QUERY_LIMITED_INFORMATION, but any other option doesn't work. I am lost and have been at this for a few days. Can anyone point me in the right direction?
This is the code that works for non-admin user on Windows. Use the szExeFile member of PROCESSENTRY32 to get the path:
HANDLE hProcessSnap = NULL;
HANDLE hProcess = NULL;
PROCESSENTRY32 pe32;
DWORD dwPriorityClass = 0;
// Take a snapshot of all processes in the system.
hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hProcessSnap == INVALID_HANDLE_VALUE)
{
return;
}
// Set the size of the structure before using it.
pe32.dwSize = sizeof(PROCESSENTRY32);
// Retrieve information about the first process,
// and exit if unsuccessful
if (!Process32First(hProcessSnap, &pe32))
{
CloseHandle(hProcessSnap); // clean the snapshot object
return;
}
// Now walk the snapshot of processes, and
// display information about each process in turn
do
{
// do something with the pe32 struct.
// pe32.szExeFile -> path of the file
} while (Process32Next(hProcessSnap, &pe32));
CloseHandle(hProcessSnap);

Delete open file in Windows (creating an anonymous file)?

Under Linux, my program would do something like this:
Process 1 opens a file (e.g. by mapping it into memory). Let's call this file#1
Process 2 unlinks the file, and creates a new file with the same name. Let's call this file#2.
Process 1 continues to work with file#1. When it is closed, it is deleted (since it has no links). Process 1 continues to work with the content in file#1, and does not see content from file#2.
When both processes have exited, file#2 remains on disk.
I want to achieve the same semantics in Windows. After reading this question, I think FILE_SHARE_DELETE does basically this. Is opening the file with FILE_SHARE_DELETE enough, or do I need to consider something more?
The above execution flow is just an example, I know there are other ways of solving that exact problem in Windows, but I want to understand how to make such code portable between Windows and Linux.
Edit: to clarify: The use cases would be to reuse a filename for different unrelated files, but let existing processes keep their data (think transactional update of a config file for example), and to make a file anonymous (unnamed), but continue to use it like an anonymous memory map. Again I know both are possible on Windows through other means, but I am trying to find a way that is portable across platforms.
You can achieve this by using a combination of CreateFile, CreateFileMapping and MapViewOfFile calls. MapViewOfFile will give you a memory-mapped buffer of the file backed by the file on disk.
Following code when executed from different processes, will write the process id of last closing process in the file at c:\temp\temp.txt
int main()
{
TCHAR szMsg[256];
HANDLE hMapFile;
LPCTSTR pBuf;
HANDLE hFile = CreateFileW(
L"C:\\Temp\\temp.txt",
GENERIC_WRITE|GENERIC_READ,
FILE_SHARE_DELETE|FILE_SHARE_READ|FILE_SHARE_WRITE,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,NULL);
hMapFile = CreateFileMapping(
hFile, // Handle of file opened with rw access
NULL, // default security
PAGE_READWRITE, // read/write access
0, // maximum object size (high-order DWORD)
BUF_SIZE, // maximum object size (low-order DWORD)
szName); // name of mapping object
if (hMapFile == NULL)
{
printf( "Could not create file mapping object (%d).\n", GetLastError());
return 1;
}
pBuf = (LPTSTR) MapViewOfFile(hMapFile, // handle to map object
FILE_MAP_ALL_ACCESS, // read/write permission
0,
0,
BUF_SIZE);
if (pBuf == NULL)
{
printf("Could not map view of file (%d).\n", GetLastError());
CloseHandle(hMapFile);
return 1;
}
wsprintfW(szMsg, L"This is process id %d", GetCurrentProcessId());
CopyMemory((PVOID)pBuf, szMsg, (wcslen(szMsg) * sizeof(TCHAR)));
MessageBoxW(NULL, szMsg, L"Check", MB_OK);
UnmapViewOfFile(pBuf);
CloseHandle(hMapFile);
CloseHandle(hFile);
return 0;
}
Make sure you open the file with GENERIC_READ|GENERIC_WRITE access and allow FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE access to subsequent opens.
Also note the use of CREATE_ALWAYS in CreateFile which will delete the old file and open a new one every-time CreateFile is called. This is the 'unlink' effect you talk about.
Code inspired from Creating Named Shared Memory at msdn.

Acessing CONIN$ without a tty

I am trying to get access to a file descriptor which receives input from the console. I am currently using
HANDLE fd = CreateFile(
"CONIN$",
GENERIC_READ | GENERIC_WRITE,
TRUE,
0,
OPEN_EXISTING,
0,
0);
SetConsoleMode(fd, ENABLE_WINDOW_INPUT);
And returning the fd to a program that reads (based on libuv) the input from the console.
This works fine when the process is executed in the console, but reading from the fd crashes when I pipe input into the program
echo hello | inputProgram
I have a suspicion that there is no console associated with the input process, but I'm not certain. How do I properly read the input into the cmd window when executing in this way?
So I a am binding to this C++ program in Node.js. I call
var ReadStream = require("tty").ReadStream();
var TTY = process.binding("tty_wrap").TTY;
module.exports = function () {
var opentty = require("./bin/opentty.node") // program returns the fd int
var fd = opentty();
var t = new _TTY(fd, true);
return new ReadStream(t);
}
opentty returns 3 in redirected input mode for the file handle. The code that deals with this file handle can be found here
https://github.com/joyent/node/blob/master/src/tty_wrap.cc#L185
which essentially calls into uv_tty_init found here
https://github.com/joyent/node/blob/master/deps/uv/src/win/tty.c#L99
The stream errors with Error: read EBADF, syscall: read
Looking through the Node repository it seems clear that new _TTY(fd, true) is expecting a C file descriptor, but you're passing it a Win32 handle.
The _open_osfhandle function creates a file descriptor from a handle.
So, you should try
var t = new _TTY(_open_osfhandle(fd), true);
(as discussed in the comments, this will only work if you're sharing the C runtime with libuv.)
Ideally you would use libuv's open function, but unfortunately there's a bug in fs__open:
case _O_RDWR:
access = FILE_GENERIC_READ | FILE_GENERIC_WRITE;
This is where it decides which access permissions to request. FILE_GENERIC_WRITE and FILE_GENERIC_READ are, as the names suggest, specific to files, and can't be used to open CONIN$. It should be
case _O_RDWR:
access = GENERIC_READ | GENERIC_WRITE;
which will work for both files and other types of objects such as the console input and output. (I've reproduced this in a simple C program; on my system, using the FILE_* permissions definitely prevents you from opening CONIN$.)

How to get the next page/part/view of file, if i read part of file using MapViewOfFile?

I am trying to use combination of functions CreateFileMapping , MapViewOfFile, FlushViewOfFile.
the total buffer size is more than the mapped view.
example buffer is 50KB. and mapped view is 2KB. in such scenario,
i want to write the total buffer to a physical file, using the above function.
First part i am able to write to file. but the remaining part how to write to file. I mean, how to move to next page and write the next part of data.
#define MEM_UNIT_SIZE 100
-first module...Memory map creator
GetTempPath (256, szTmpFile);
GetTempFileName (szTmpFile, pName, 0, szMMFile);
hFile = CreateFile (szMMFile, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_WRITE,
NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY, NULL);
HANDLE hFileMMF = CreateFileMapping( hFile ,NULL,PAGE_READWRITE,0,
(MEM_UNIT_SIZE),pName)
-second module... Memory writer
long lBinarySize = 1000;
long lPageSize = MEM_UNIT_SIZE;
HANDLE hFileMMF = OpenFileMapping(FILE_MAP_WRITE,FALSE,pMemName);
LPVOID pViewMMFFile = MapViewOfFile(hFileMMF,FILE_MAP_WRITE,0,0, lPageSize );
CMutex mutex (FALSE, _T("Writer"));
mutex.Lock();
try
{
ASSERT(FALSE);
CopyMemory(pViewMMFFile,pBinary,lPageSize); // write
FlushViewOfFile(pViewMMFFile,lPageSize);
// first 100 bytes flushed to file.
//how to move to next location and write next 900 bytes..<---??
}
catch(CException e)
{
...
}
please share if you have any suggestion.
thanks in advance,
haranadh
Repeat your call to MapViewOfFile with a different range.
as described in the following link,
http://msdn.microsoft.com/en-us/library/windows/desktop/aa366761(v=VS.85).aspx
can you please check "allocation granularity", I think you should use this parameter to set the values for "dwFileOffsetLow" or "dwFileOffsetHigh".

Resources