Acessing CONIN$ without a tty - windows

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$.)

Related

Windows App using PeekNamedPipe() used to work in XP but does not in Win7

I used to have an application which launched an application using CreateProcess() and then piped data back and forth. The child process used printf() and getch().
The code had:
PeekNamedPipe(pCmdIF->m_asynch_hReadPipeOut,NULL,NULL,NULL, &dwBytesInOutPipe, &dwBytesLeftInOutPipe))
Which checked how much data was in the incoming pipe and then I used ReadFile to read that data.
Now, in Windows 7 that same code does not work.
To create the pipe I used the code ...
// Set the bInheritHandle flag so pipe handles are inherited.
ZeroMemory( &m_asynch_sa, sizeof(SECURITY_ATTRIBUTES));
m_asynch_sa.bInheritHandle = TRUE;
m_asynch_sa.lpSecurityDescriptor = NULL;
m_asynch_sa.nLength = sizeof(SECURITY_ATTRIBUTES);
// Create a pipe for the child process's STDOUT (will also be used for STDERR)
if( ! CreatePipe( &m_hChildStd_OUT_Rd, &m_hChildStd_OUT_Wr, &m_asynch_sa, 0 ) )
{
return 2;
}
Is it a case that m_asynch_sa.lpSecurityDescriptor should not be set to NULL. If that is the case, I cannot find any example of how to set it to a proper value.
Thank you in advance.

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.

win7 boost::asio::windows::stream_handle constructor throws error

The following code gets an error when trying to execute the last line
boost::shared_ptr<boost::asio::io_service> ioServicePtr(new boost::asio::io_service());
//setup the terminal with stdin and stdout
int inFD = ::dup(STDIN_FILENO);
int outFD = ::dup(STDOUT_FILENO);
HANDLE osfhandle = (HANDLE)_get_osfhandle(inFD);//osfhandle is valid
boost::asio::windows::stream_handle inputStream(*ioServicePtr, osfhandle); //error
the error is:
uncaught exception of type N5boost16exception_detail10clone_implINS0_19error_info_injectorINS_6system12system_errorEEEEE
- assign: The parameter is incorrect
Appreciate your input.
#sehe
I tried
hstdhandle = GetStdHandle(STD_OUTPUT_HANDLE);
and got the same error
So then I tried
HANDLE handle=
CreateFile(
"CONIN$", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
FILE_FLAG_OVERLAPPED, NULL);
boost::asio::windows::stream_handle inputStream(*ioServicePtr, handle);
and the error was
-assign handle invalid
You might use GetStdHandle, so:
HANDLE isfhandle = GetStdHandle(STD_INPUT_HANDLE);
However, I don't think consoles support asynchronous IO in windows:
The handle must be to an object that supports overlapped I/O.
If a handle is provided, it has to have been opened for overlapped I/O completion. For example, you must
specify the FILE_FLAG_OVERLAPPED flag when using the CreateFile function to obtain the handle
But further the docs for CreateFile say that CreateFile ignores file flags when creating a handle to a console buffer.
So, you will need to emulate stdin/stdout async IO.
Note that on Linux, asynchronous IO to the standard IO handles is only possible in certain situations anyway - depending on the input/output being redirected: Strange exception throw - assign: Operation not permitted

FileMapped write access

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.

Windows fopen and the N flag

I'm reading some code that uses fopen to open files for writing. The code needs to be able to close and rename these files from time to time (it's a rotating file logger). The author says that for this to happen the child processes must not inherit these FILE handles. (On Windows, that is; on Unix it's OK.) So the author writes a special subroutine that duplicates the handle as non-inheritable and closes the original handle:
if (!(log->file = fopen(log->path, mode)))
return ERROR;
#ifdef _WIN32
sf = _fileno(log->file);
sh = (HANDLE)_get_osfhandle(sf);
if (!DuplicateHandle(GetCurrentProcess(), sh, GetCurrentProcess(),
&th, 0, FALSE, DUPLICATE_SAME_ACCESS)) {
fclose(log->file);
return ERROR;
}
fclose(log->file);
flags = (*mode == 'a') ? _O_APPEND : 0;
tf = _open_osfhandle((intptr_t)th, _O_TEXT | flags);
if (!(log->file = _fdopen(tf, "at"))) {
_close(tf);
return ERROR;
}
#endif
Now, I'm also reading MSDN docs on fopen and see that their version of fopen has a Microsoft-specific flag that seems to do the same: the N flag:
N: Specifies that the file is not inherited by child processes.
Question: do I understand it correctly that I can get rid of that piece above and replace it (on Windows) with an additional N in the mode parameter?
Yes, you can.
fopen("myfile", "rbN") creates a non-inheritable file handle.
The N flag is not mentioned anywhere in Linux documentation for fopen, so the solution will be most probably not portable, but for MS VC it works fine.

Resources