glib/win32: introduce private g_win32_reopen_noninherited()

Used in following commits, including in some GIO experiments, so make it
a private API.

For now, this implementation is similar to the glib/gspawn-win32.c one,
with mroe error checking and better on error behaviour. A following
patch will also fix the case of duplicating sockets.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
This commit is contained in:
Marc-André Lureau
2022-04-07 17:53:54 +04:00
parent 982b074fa9
commit c984db650f
4 changed files with 71 additions and 0 deletions

View File

@@ -31,6 +31,7 @@
#include "glibconfig.h"
#include <glib/gstdio.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
@@ -1448,3 +1449,66 @@ g_win32_find_helper_executable_path (const gchar *executable_name, void *dll_han
return executable_path;
}
/*
* g_win32_reopen_noninherited:
* @fd: (transfer full): A file descriptor
* @mode: _open_osfhandle flags
* @error: A location to return an error of type %G_FILE_ERROR
*
* Reopen the given @fd with `_O_NOINHERIT`.
*
* The @fd is closed on success.
*
* Returns: (transfer full): The new file-descriptor, or -1 on error.
*/
int
g_win32_reopen_noninherited (int fd,
int mode,
GError **error)
{
HANDLE h;
HANDLE duph;
int dupfd, errsv;
h = (HANDLE) _get_osfhandle (fd);
errsv = errno;
if (h == INVALID_HANDLE_VALUE)
{
const char *emsg = g_strerror (errsv);
g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (errsv),
"_get_osfhandle() failed: %s", emsg);
return -1;
}
if (DuplicateHandle (GetCurrentProcess (), h,
GetCurrentProcess (), &duph,
0, FALSE, DUPLICATE_SAME_ACCESS) == 0)
{
char *emsg = g_win32_error_message (GetLastError ());
g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
"DuplicateHandle() failed: %s", emsg);
g_free (emsg);
return -1;
}
/* the duph ownership is transferred to dupfd */
dupfd = _open_osfhandle ((gintptr) duph, mode | _O_NOINHERIT);
if (dupfd < 0)
{
g_set_error_literal (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
"_open_osfhandle() failed");
CloseHandle (duph);
return -1;
}
if (!g_close (fd, error))
{
/* ignore extra errors in this case */
g_close (dupfd, NULL);
return -1;
}
return dupfd;
}