|
From: Brian D. <br...@de...> - 2008-03-07 22:24:01
|
Tor Lillqvist wrote:
> What you need to do is prevent the file HANDLE for the file from being
> inherited by the child process. If you use open() to open the file
> instead of fopen(), you can add the O_NOINHERIT flag to the open
> flags.
There are other ways of marking a HANDLE as non-inheritable after it has
been opened. The simplest is SetHandleInformation(), which you can use
in conjunction with _fileno() to get the fd of the FILE * and
_get_osfhandle() to get the HANDLE of the fd:
if (!SetHandleInformation (_get_osfhandle (_fileno (f)),
HANDLE_FLAG_INHERIT,
0))
{
/* error */
}
The problem with this approach is that SetHandleInformation() is only
available on NT/2k/XP/2k3/Vista/2k8, not 9x/ME. For most people that's
not really an issue but it can be problematic.
Another method is to use DuplicateHandle() with the bInheritHandle
parameter set to FALSE. You then have a copy of the HANDLE that won't
be inherited, and you can close the original (or pass
DUPLICATE_CLOSE_SOURCE in dwOptions to do it in one step.) The problem
now is that you have to use this new HANDLE in place of the old. If
you're using the C fd API, you can accomplish this with
_open_osfhandle(); if you're using the C FILE * API, then you can then
further use _fdopen() to create a FILE * from that fd. This is rather
tedious, but it works on all versions of Windows:
HANDLE newh;
int newfd;
FILE *newf;
if (!DuplicateHandle (GetCurrentProcess (),
_get_osfhandle (_fileno (f)),
GetCurrentProcess (),
&newh,
0,
FALSE,
DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)
|| -1 == (newfd = _open_osfhandle (newh, _O_RDWR | _O_BINARY))
|| NULL == (newf = _fdopen (newfd, "w+b")))
{
/* error */
}
(Naturally, you'd have to use the correct file mode flags/string. Since
MSVCRT doesn't support fcntl (fd, F_GETFL) I don't think there's a way
to get them from the existing fd, sadly.)
Finally, the blunt-object approach is to simply call CreateProcess()
with bInheritHandles set to FALSE, which will override the individual
handle settings. But this is probably not all that useful as inheriting
handles is how things like _popen() are usually implemented.
> Yes, this is totally unlike Unix, but then nobody claimed Windows is like Unix.
On the contrary, I find it quite similar to unix in that when you
fork/exec to create a child process, all open file descriptors are
inherited. Of course in that case you have more fine grained control,
as you can close() any sensitive fds that you don't want the new process
to have access to in the period following fork() but before exec() on
the child side.
What is different is the fact that unix allows an unlink() on files and
directories with open handles (without the need for any
FILE_SHARE_DELETE bit), so the testcase would succeed. Of course the
unlinked file would continue to exist until all fds are closed, it would
just no longer be accessible through any directory entry.
Brian
|