[vlc-commits] [Git][videolan/vlc][master] win32: spawn: add vlc_spawn() vlc_spawnp() vlc_waitpid() wrappers
Steve Lhomme (@robUx4)
gitlab at videolan.org
Fri Oct 21 11:29:14 UTC 2022
Steve Lhomme pushed to branch master at VideoLAN / VLC
Commits:
c317c2a1 by Louis Regnier at 2022-10-21T10:11:01+00:00
win32: spawn: add vlc_spawn() vlc_spawnp() vlc_waitpid() wrappers
- - - - -
3 changed files:
- src/Makefile.am
- src/missing.c
- + src/win32/spawn.c
Changes:
=====================================
src/Makefile.am
=====================================
@@ -430,7 +430,7 @@ libvlccore_la_SOURCES += \
if HAVE_WINSTORE
libvlccore_la_SOURCES += posix/timer.c win32/dirs-uap.c
else
-libvlccore_la_SOURCES += win32/timer.c win32/dirs.c
+libvlccore_la_SOURCES += win32/timer.c win32/dirs.c win32/spawn.c
libvlccore_la_LIBADD += -lwinmm
endif
libvlccore_la_LIBADD += -lbcrypt
=====================================
src/missing.c
=====================================
@@ -279,6 +279,7 @@ noreturn void vlc_control_cancel (vlc_cleanup_t *cleaner)
#include <errno.h>
#include <vlc_spawn.h>
+#if !defined(_WIN32) || defined(VLC_WINSTORE_APP)
VLC_WEAK
int vlc_spawn(pid_t *pid, const char *file, const int *fds,
const char *const *args)
@@ -301,3 +302,4 @@ int vlc_waitpid(pid_t pid)
(void) pid;
vlc_assert_unreachable();
}
+#endif
=====================================
src/win32/spawn.c
=====================================
@@ -0,0 +1,258 @@
+/*****************************************************************************
+ * spawn.c
+ *****************************************************************************
+ * Copyright (C) 2022 VLC authors and VideoLAN
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <windows.h>
+#include <assert.h>
+#include <fcntl.h>
+
+#include <vlc_common.h>
+#include <vlc_fs.h>
+#include <vlc_spawn.h>
+#include <vlc_memstream.h>
+
+static LPPROC_THREAD_ATTRIBUTE_LIST allow_hstd_inherit(HANDLE *handles)
+{
+ size_t attribute_list_size;
+ InitializeProcThreadAttributeList(NULL, 1, 0, &attribute_list_size);
+
+ LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList = malloc(attribute_list_size);
+ if (unlikely(!lpAttributeList))
+ return NULL;
+
+ BOOL result;
+ result = InitializeProcThreadAttributeList(lpAttributeList, 1, 0,
+ &attribute_list_size);
+ if (unlikely(!result))
+ goto error;
+
+ /* duplicated handles in authorized list will cause CreateProcess() failure */
+ int nb_handles = handles[2] == INVALID_HANDLE_VALUE ? 2 : 3;
+ if (handles[0] == handles[nb_handles - 1])
+ --nb_handles;
+ if (nb_handles > 2 && (handles[1] == handles[2]))
+ --nb_handles;
+ if (nb_handles > 1 && (handles[0] == handles[1])) {
+ ++handles;
+ --nb_handles;
+ }
+
+ result = UpdateProcThreadAttribute(lpAttributeList, 0,
+ PROC_THREAD_ATTRIBUTE_HANDLE_LIST, handles,
+ sizeof(*handles) * nb_handles, NULL, NULL);
+ if (unlikely(!result))
+ goto error;
+
+ return lpAttributeList;
+
+error:
+ if (lpAttributeList)
+ free(lpAttributeList);
+ return NULL;
+}
+
+static HANDLE dup_handle_from_fd(const int fd)
+{
+ HANDLE vlc_handle = (HANDLE)_get_osfhandle(fd);
+ if (vlc_handle == INVALID_HANDLE_VALUE)
+ return vlc_handle;
+
+ if (vlc_handle == (HANDLE)-2)
+ return INVALID_HANDLE_VALUE;
+
+ HANDLE dup_inheritable_handle;
+ BOOL result = DuplicateHandle(GetCurrentProcess(), vlc_handle, GetCurrentProcess(),
+ &dup_inheritable_handle, 0, TRUE, DUPLICATE_SAME_ACCESS);
+ if (!result)
+ return INVALID_HANDLE_VALUE;
+
+ return dup_inheritable_handle;
+}
+
+static int vlc_spawn_inner(pid_t *restrict pid, const char *path,
+ const int fdv[4], const char *const *argv,
+ bool search)
+{
+ assert(pid != NULL);
+ assert(path != NULL);
+ assert(fdv != NULL);
+ assert(argv != NULL);
+
+ int ret = -1;
+ int nulfd = -1;
+ HANDLE nul_handle = INVALID_HANDLE_VALUE;
+ PROCESS_INFORMATION pi = {0};
+ STARTUPINFOEXA siEx = {
+ .StartupInfo = {
+ .cb = sizeof(siEx),
+ .hStdInput = INVALID_HANDLE_VALUE,
+ .hStdOutput = INVALID_HANDLE_VALUE,
+ .hStdError = INVALID_HANDLE_VALUE,
+ .dwFlags = STARTF_USESTDHANDLES
+ }
+ };
+
+ struct vlc_memstream application_name;
+ struct vlc_memstream cmdline;
+ {
+ int error;
+ error = vlc_memstream_open(&application_name);
+ error |= vlc_memstream_open(&cmdline);
+ if (unlikely(error))
+ goto error;
+ }
+
+ if (fdv[0] == -1 || fdv[1] == -1) {
+ nulfd = vlc_open("\\\\.\\NUL", O_RDWR);
+ if (unlikely(nulfd == -1))
+ goto error;
+
+ nul_handle = dup_handle_from_fd(nulfd);
+ if (unlikely(nul_handle == INVALID_HANDLE_VALUE))
+ goto error;
+
+ if (fdv[0] == -1)
+ siEx.StartupInfo.hStdInput = nul_handle;
+ if (fdv[1] == -1)
+ siEx.StartupInfo.hStdOutput = nul_handle;
+ }
+
+ if (fdv[0] != -1) {
+ siEx.StartupInfo.hStdInput = dup_handle_from_fd(fdv[0]);
+ if (unlikely(siEx.StartupInfo.hStdInput == INVALID_HANDLE_VALUE))
+ goto error;
+ }
+ if (fdv[1] != -1) {
+ siEx.StartupInfo.hStdOutput = dup_handle_from_fd(fdv[1]);
+ if (unlikely(siEx.StartupInfo.hStdOutput == INVALID_HANDLE_VALUE))
+ goto error;
+ }
+ if (fdv[2] != -1) {
+ siEx.StartupInfo.hStdError = dup_handle_from_fd(fdv[2]);
+ if (unlikely(siEx.StartupInfo.hStdError == INVALID_HANDLE_VALUE))
+ goto error;
+ }
+
+ HANDLE handles[3] = {
+ siEx.StartupInfo.hStdInput,
+ siEx.StartupInfo.hStdOutput,
+ siEx.StartupInfo.hStdError
+ };
+ siEx.lpAttributeList = allow_hstd_inherit(handles);
+ if (unlikely(!siEx.lpAttributeList))
+ goto error;
+
+ if (search) {
+ if (!SetSearchPathMode(BASE_SEARCH_PATH_ENABLE_SAFE_SEARCHMODE))
+ goto error;
+
+ char *const application_path = malloc(MAX_PATH);
+ if (unlikely(!application_path))
+ goto error;
+
+ if (!SearchPathA(NULL, path, NULL, MAX_PATH, application_path, NULL)) {
+ free(application_path);
+ goto error;
+ }
+
+ vlc_memstream_printf(&application_name, "%s", application_path);
+ free(application_path);
+
+ } else {
+ vlc_memstream_printf(&application_name, "%s", path);
+ }
+
+ if (likely(argv[0])) {
+ vlc_memstream_printf(&cmdline, "%s", argv[0]);
+ for (int argc = 1; argv[argc]; ++argc)
+ vlc_memstream_printf(&cmdline, " %s", argv[argc]);
+ }
+
+ BOOL bSuccess = CreateProcessA(application_name.ptr, cmdline.ptr, NULL,
+ NULL, TRUE, EXTENDED_STARTUPINFO_PRESENT,
+ NULL, NULL, &siEx.StartupInfo, &pi);
+ if (!bSuccess)
+ goto error;
+
+ pid_t id = GetProcessId(pi.hProcess);
+ if (unlikely(!id))
+ goto error;
+ *pid = id;
+
+ CloseHandle(pi.hProcess);
+ CloseHandle(pi.hThread);
+
+ ret = 0;
+
+error:
+ if (nulfd != -1)
+ vlc_close(nulfd);
+ if (nul_handle != INVALID_HANDLE_VALUE)
+ CloseHandle(nul_handle);
+
+ if (fdv[0] != -1 && siEx.StartupInfo.hStdInput != INVALID_HANDLE_VALUE)
+ CloseHandle(siEx.StartupInfo.hStdInput);
+ if (fdv[1] != -1 && siEx.StartupInfo.hStdOutput != INVALID_HANDLE_VALUE)
+ CloseHandle(siEx.StartupInfo.hStdOutput);
+ if (siEx.StartupInfo.hStdError != INVALID_HANDLE_VALUE)
+ CloseHandle(siEx.StartupInfo.hStdError);
+
+ if (siEx.lpAttributeList) {
+ DeleteProcThreadAttributeList(siEx.lpAttributeList);
+ free(siEx.lpAttributeList);
+ }
+
+ if (!vlc_memstream_close(&application_name))
+ free(application_name.ptr);
+ if (!vlc_memstream_close(&cmdline))
+ free(cmdline.ptr);
+
+ return ret;
+}
+
+int vlc_spawnp(pid_t *restrict pid, const char *path,
+ const int *fdv, const char *const *argv)
+{
+ return vlc_spawn_inner(pid, path, fdv, argv, true);
+}
+
+int vlc_spawn(pid_t *restrict pid, const char *file,
+ const int *fdv, const char *const *argv)
+{
+ return vlc_spawn_inner(pid, file, fdv, argv, false);
+}
+
+int vlc_waitpid(pid_t pid)
+{
+ HANDLE process = OpenProcess(SYNCHRONIZE | PROCESS_QUERY_INFORMATION, FALSE, pid);
+ if (!process)
+ return -1;
+
+ WaitForSingleObject(process, INFINITE);
+
+ DWORD exit_code = -1;
+ GetExitCodeProcess(process, &exit_code);
+
+ CloseHandle(process);
+ return exit_code;
+}
View it on GitLab: https://code.videolan.org/videolan/vlc/-/commit/c317c2a16cc626b505ab93fb968c5a0f21bc0342
--
View it on GitLab: https://code.videolan.org/videolan/vlc/-/commit/c317c2a16cc626b505ab93fb968c5a0f21bc0342
You're receiving this email because of your account on code.videolan.org.
VideoLAN code repository instance
More information about the vlc-commits
mailing list