Blame libarchive/filter_fork_windows.c

Packit Service 1d0348
/*-
Packit Service 1d0348
 * Copyright (c) 2009-2012 Michihiro NAKAJIMA
Packit Service 1d0348
 * All rights reserved.
Packit Service 1d0348
 *
Packit Service 1d0348
 * Redistribution and use in source and binary forms, with or without
Packit Service 1d0348
 * modification, are permitted provided that the following conditions
Packit Service 1d0348
 * are met:
Packit Service 1d0348
 * 1. Redistributions of source code must retain the above copyright
Packit Service 1d0348
 *    notice, this list of conditions and the following disclaimer.
Packit Service 1d0348
 * 2. Redistributions in binary form must reproduce the above copyright
Packit Service 1d0348
 *    notice, this list of conditions and the following disclaimer in the
Packit Service 1d0348
 *    documentation and/or other materials provided with the distribution.
Packit Service 1d0348
 *
Packit Service 1d0348
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
Packit Service 1d0348
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
Packit Service 1d0348
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
Packit Service 1d0348
 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
Packit Service 1d0348
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
Packit Service 1d0348
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
Packit Service 1d0348
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
Packit Service 1d0348
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
Packit Service 1d0348
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
Packit Service 1d0348
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Packit Service 1d0348
 */
Packit Service 1d0348
Packit Service 1d0348
#include "archive_platform.h"
Packit Service 1d0348
Packit Service 1d0348
#if defined(_WIN32) && !defined(__CYGWIN__)
Packit Service 1d0348
#include "archive_cmdline_private.h"
Packit Service 1d0348
#include "archive_string.h"
Packit Service 1d0348
Packit Service 1d0348
#include "filter_fork.h"
Packit Service 1d0348
Packit Service 1d0348
pid_t
Packit Service 1d0348
__archive_create_child(const char *cmd, int *child_stdin, int *child_stdout)
Packit Service 1d0348
{
Packit Service 1d0348
	HANDLE childStdout[2], childStdin[2],childStderr;
Packit Service 1d0348
	SECURITY_ATTRIBUTES secAtts;
Packit Service 1d0348
	STARTUPINFOA staInfo;
Packit Service 1d0348
	PROCESS_INFORMATION childInfo;
Packit Service 1d0348
	struct archive_string cmdline;
Packit Service 1d0348
	struct archive_string fullpath;
Packit Service 1d0348
	struct archive_cmdline *acmd;
Packit Service 1d0348
	char *arg0, *ext;
Packit Service 1d0348
	int i, l;
Packit Service 1d0348
	DWORD fl, fl_old;
Packit Service 1d0348
Packit Service 1d0348
	childStdout[0] = childStdout[1] = INVALID_HANDLE_VALUE;
Packit Service 1d0348
	childStdin[0] = childStdin[1] = INVALID_HANDLE_VALUE;
Packit Service 1d0348
	childStderr = INVALID_HANDLE_VALUE;
Packit Service 1d0348
	archive_string_init(&cmdline);
Packit Service 1d0348
	archive_string_init(&fullpath);
Packit Service 1d0348
Packit Service 1d0348
	acmd = __archive_cmdline_allocate();
Packit Service 1d0348
	if (acmd == NULL)
Packit Service 1d0348
		goto fail;
Packit Service 1d0348
	if (__archive_cmdline_parse(acmd, cmd) != ARCHIVE_OK)
Packit Service 1d0348
		goto fail;
Packit Service 1d0348
Packit Service 1d0348
	/*
Packit Service 1d0348
	 * Search the full path of 'path'.
Packit Service 1d0348
	 * NOTE: This does not need if we give CreateProcessA 'path' as
Packit Service 1d0348
	 * a part of the cmdline and give CreateProcessA NULL as first
Packit Service 1d0348
	 * parameter, but I do not like that way.
Packit Service 1d0348
	 */
Packit Service 1d0348
	ext = strrchr(acmd->path, '.');
Packit Service 1d0348
	if (ext == NULL || strlen(ext) > 4)
Packit Service 1d0348
		/* 'path' does not have a proper extension, so we have to
Packit Service 1d0348
		 * give SearchPath() ".exe" as the extension. */
Packit Service 1d0348
		ext = ".exe";
Packit Service 1d0348
	else
Packit Service 1d0348
		ext = NULL;/* 'path' has an extension. */
Packit Service 1d0348
Packit Service 1d0348
	fl = MAX_PATH;
Packit Service 1d0348
	do {
Packit Service 1d0348
		if (archive_string_ensure(&fullpath, fl) == NULL)
Packit Service 1d0348
			goto fail;
Packit Service 1d0348
		fl_old = fl;
Packit Service 1d0348
		fl = SearchPathA(NULL, acmd->path, ext, fl, fullpath.s,
Packit Service 1d0348
			&arg0);
Packit Service 1d0348
	} while (fl != 0 && fl > fl_old);
Packit Service 1d0348
	if (fl == 0)
Packit Service 1d0348
		goto fail;
Packit Service 1d0348
Packit Service 1d0348
	/*
Packit Service 1d0348
	 * Make a command line.
Packit Service 1d0348
	 */
Packit Service 1d0348
	for (l = 0, i = 0;  acmd->argv[i] != NULL; i++) {
Packit Service 1d0348
		if (i == 0)
Packit Service 1d0348
			continue;
Packit Service 1d0348
		l += (int)strlen(acmd->argv[i]) + 1;
Packit Service 1d0348
	}
Packit Service 1d0348
	if (archive_string_ensure(&cmdline, l + 1) == NULL)
Packit Service 1d0348
		goto fail;
Packit Service 1d0348
	for (i = 0;  acmd->argv[i] != NULL; i++) {
Packit Service 1d0348
		if (i == 0) {
Packit Service 1d0348
			const char *p, *sp;
Packit Service 1d0348
Packit Service 1d0348
			if ((p = strchr(acmd->argv[i], '/')) != NULL ||
Packit Service 1d0348
			    (p = strchr(acmd->argv[i], '\\')) != NULL)
Packit Service 1d0348
				p++;
Packit Service 1d0348
			else
Packit Service 1d0348
				p = acmd->argv[i];
Packit Service 1d0348
			if ((sp = strchr(p, ' ')) != NULL)
Packit Service 1d0348
				archive_strappend_char(&cmdline, '"');
Packit Service 1d0348
			archive_strcat(&cmdline, p);
Packit Service 1d0348
			if (sp != NULL)
Packit Service 1d0348
				archive_strappend_char(&cmdline, '"');
Packit Service 1d0348
		} else {
Packit Service 1d0348
			archive_strappend_char(&cmdline, ' ');
Packit Service 1d0348
			archive_strcat(&cmdline, acmd->argv[i]);
Packit Service 1d0348
		}
Packit Service 1d0348
	}
Packit Service 1d0348
	if (i <= 1) {
Packit Service 1d0348
		const char *sp;
Packit Service 1d0348
Packit Service 1d0348
		if ((sp = strchr(arg0, ' ')) != NULL)
Packit Service 1d0348
			archive_strappend_char(&cmdline, '"');
Packit Service 1d0348
		archive_strcat(&cmdline, arg0);
Packit Service 1d0348
		if (sp != NULL)
Packit Service 1d0348
			archive_strappend_char(&cmdline, '"');
Packit Service 1d0348
	}
Packit Service 1d0348
Packit Service 1d0348
	secAtts.nLength = sizeof(SECURITY_ATTRIBUTES);
Packit Service 1d0348
	secAtts.bInheritHandle = TRUE;
Packit Service 1d0348
	secAtts.lpSecurityDescriptor = NULL;
Packit Service 1d0348
	if (CreatePipe(&childStdout[0], &childStdout[1], &secAtts, 0) == 0)
Packit Service 1d0348
		goto fail;
Packit Service 1d0348
	if (!SetHandleInformation(childStdout[0], HANDLE_FLAG_INHERIT, 0))
Packit Service 1d0348
		goto fail;
Packit Service 1d0348
	if (CreatePipe(&childStdin[0], &childStdin[1], &secAtts, 0) == 0)
Packit Service 1d0348
		goto fail;
Packit Service 1d0348
	if (!SetHandleInformation(childStdin[1], HANDLE_FLAG_INHERIT, 0))
Packit Service 1d0348
		goto fail;
Packit Service 1d0348
	if (DuplicateHandle(GetCurrentProcess(), GetStdHandle(STD_ERROR_HANDLE),
Packit Service 1d0348
	    GetCurrentProcess(), &childStderr, 0, TRUE,
Packit Service 1d0348
	    DUPLICATE_SAME_ACCESS) == 0)
Packit Service 1d0348
		goto fail;
Packit Service 1d0348
Packit Service 1d0348
	memset(&staInfo, 0, sizeof(staInfo));
Packit Service 1d0348
	staInfo.cb = sizeof(staInfo);
Packit Service 1d0348
	staInfo.hStdError = childStderr;
Packit Service 1d0348
	staInfo.hStdOutput = childStdout[1];
Packit Service 1d0348
	staInfo.hStdInput = childStdin[0];
Packit Service 1d0348
	staInfo.wShowWindow = SW_HIDE;
Packit Service 1d0348
	staInfo.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
Packit Service 1d0348
	if (CreateProcessA(fullpath.s, cmdline.s, NULL, NULL, TRUE, 0,
Packit Service 1d0348
	      NULL, NULL, &staInfo, &childInfo) == 0)
Packit Service 1d0348
		goto fail;
Packit Service 1d0348
	WaitForInputIdle(childInfo.hProcess, INFINITE);
Packit Service 1d0348
	CloseHandle(childInfo.hProcess);
Packit Service 1d0348
	CloseHandle(childInfo.hThread);
Packit Service 1d0348
Packit Service 1d0348
	*child_stdout = _open_osfhandle((intptr_t)childStdout[0], _O_RDONLY);
Packit Service 1d0348
	*child_stdin = _open_osfhandle((intptr_t)childStdin[1], _O_WRONLY);
Packit Service 1d0348
	
Packit Service 1d0348
	CloseHandle(childStdout[1]);
Packit Service 1d0348
	CloseHandle(childStdin[0]);
Packit Service 1d0348
Packit Service 1d0348
	archive_string_free(&cmdline);
Packit Service 1d0348
	archive_string_free(&fullpath);
Packit Service 1d0348
	__archive_cmdline_free(acmd);
Packit Service 1d0348
	return (childInfo.dwProcessId);
Packit Service 1d0348
Packit Service 1d0348
fail:
Packit Service 1d0348
	if (childStdout[0] != INVALID_HANDLE_VALUE)
Packit Service 1d0348
		CloseHandle(childStdout[0]);
Packit Service 1d0348
	if (childStdout[1] != INVALID_HANDLE_VALUE)
Packit Service 1d0348
		CloseHandle(childStdout[1]);
Packit Service 1d0348
	if (childStdin[0] != INVALID_HANDLE_VALUE)
Packit Service 1d0348
		CloseHandle(childStdin[0]);
Packit Service 1d0348
	if (childStdin[1] != INVALID_HANDLE_VALUE)
Packit Service 1d0348
		CloseHandle(childStdin[1]);
Packit Service 1d0348
	if (childStderr != INVALID_HANDLE_VALUE)
Packit Service 1d0348
		CloseHandle(childStderr);
Packit Service 1d0348
	archive_string_free(&cmdline);
Packit Service 1d0348
	archive_string_free(&fullpath);
Packit Service 1d0348
	__archive_cmdline_free(acmd);
Packit Service 1d0348
	return (-1);
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
void
Packit Service 1d0348
__archive_check_child(int in, int out)
Packit Service 1d0348
{
Packit Service 1d0348
	(void)in; /* UNUSED */
Packit Service 1d0348
	(void)out; /* UNUSED */
Packit Service 1d0348
	Sleep(100);
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
#endif /* _WIN32 && !__CYGWIN__ */