mirror of
https://github.com/moparisthebest/wget
synced 2024-07-03 16:38:41 -04:00
[svn] New Windows implementation of fork_to_background().
Submitted by David Fritz.
This commit is contained in:
parent
1b6479a39a
commit
03395ca801
@ -1,3 +1,9 @@
|
||||
2004-03-24 David Fritz <zeroxdf@att.net>
|
||||
|
||||
* mswindows.c (fake_fork): New function.
|
||||
|
||||
* mswindows.c (fork_to_background): Use it.
|
||||
|
||||
2004-03-19 David Fritz <zeroxdf@att.net>
|
||||
|
||||
* mswindows.c (ws_hangup): Incorporate old fork_to_background()
|
||||
|
234
src/mswindows.c
234
src/mswindows.c
@ -28,8 +28,6 @@ modify this file, you may extend this exception to your version of the
|
||||
file, but you are not obligated to do so. If you do not wish to do
|
||||
so, delete this exception statement from your version. */
|
||||
|
||||
/* #### Someone please document what these functions do! */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <stdio.h>
|
||||
@ -131,10 +129,240 @@ ws_hangup (const char *reason)
|
||||
FreeConsole ();
|
||||
}
|
||||
|
||||
/* Construct the name for a named section (a.k.a. `file mapping') object.
|
||||
The returned string is dynamically allocated and needs to be xfree()'d. */
|
||||
static char *
|
||||
make_section_name (DWORD pid)
|
||||
{
|
||||
return aprintf ("gnu_wget_fake_fork_%lu", pid);
|
||||
}
|
||||
|
||||
/* This structure is used to hold all the data that is exchanged between
|
||||
parent and child. */
|
||||
struct fake_fork_info
|
||||
{
|
||||
HANDLE event;
|
||||
int changedp;
|
||||
char lfilename[MAX_PATH + 1];
|
||||
};
|
||||
|
||||
/* Determines if we are the child and if so performs the child logic.
|
||||
Return values:
|
||||
< 0 error
|
||||
0 parent
|
||||
> 0 child
|
||||
*/
|
||||
static int
|
||||
fake_fork_child (void)
|
||||
{
|
||||
HANDLE section, event;
|
||||
struct fake_fork_info *info;
|
||||
char *name;
|
||||
DWORD le;
|
||||
|
||||
name = make_section_name (GetCurrentProcessId ());
|
||||
section = OpenFileMapping (FILE_MAP_WRITE, FALSE, name);
|
||||
le = GetLastError ();
|
||||
xfree (name);
|
||||
if (!section)
|
||||
{
|
||||
if (le == ERROR_FILE_NOT_FOUND)
|
||||
return 0; /* Section object does not exist; we are the parent. */
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
info = MapViewOfFile (section, FILE_MAP_WRITE, 0, 0, 0);
|
||||
if (!info)
|
||||
{
|
||||
CloseHandle (section);
|
||||
return -1;
|
||||
}
|
||||
|
||||
event = info->event;
|
||||
|
||||
if (!opt.lfilename)
|
||||
{
|
||||
opt.lfilename = unique_name (DEFAULT_LOGFILE, 0);
|
||||
info->changedp = 1;
|
||||
strncpy (info->lfilename, opt.lfilename, sizeof (info->lfilename));
|
||||
info->lfilename[sizeof (info->lfilename) - 1] = '\0';
|
||||
}
|
||||
else
|
||||
info->changedp = 0;
|
||||
|
||||
UnmapViewOfFile (info);
|
||||
CloseHandle (section);
|
||||
|
||||
/* Inform the parent that we've done our part. */
|
||||
if (!SetEvent (event))
|
||||
return -1;
|
||||
|
||||
CloseHandle (event);
|
||||
return 1; /* We are the child. */
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
fake_fork (void)
|
||||
{
|
||||
char *cmdline, *args;
|
||||
char exe[MAX_PATH + 1];
|
||||
DWORD exe_len, le;
|
||||
SECURITY_ATTRIBUTES sa;
|
||||
HANDLE section, event, h[2];
|
||||
STARTUPINFO si;
|
||||
PROCESS_INFORMATION pi;
|
||||
struct fake_fork_info *info;
|
||||
char *name;
|
||||
BOOL rv;
|
||||
|
||||
event = section = pi.hProcess = pi.hThread = NULL;
|
||||
|
||||
/* Get command line arguments to pass to the child process.
|
||||
We need to skip the name of the command (what amounts to argv[0]). */
|
||||
cmdline = GetCommandLine ();
|
||||
if (*cmdline == '"')
|
||||
{
|
||||
args = strchr (cmdline + 1, '"');
|
||||
if (args)
|
||||
++args;
|
||||
}
|
||||
else
|
||||
args = strchr (cmdline, ' ');
|
||||
|
||||
/* It's ok if args is NULL, that would mean there were no arguments
|
||||
after the command name. As it is now though, we would never get here
|
||||
if that were true. */
|
||||
|
||||
/* Get the fully qualified name of our executable. This is more reliable
|
||||
than using argv[0]. */
|
||||
exe_len = GetModuleFileName (GetModuleHandle (NULL), exe, sizeof (exe));
|
||||
if (!exe_len || (exe_len >= sizeof (exe)))
|
||||
return;
|
||||
|
||||
sa.nLength = sizeof (sa);
|
||||
sa.lpSecurityDescriptor = NULL;
|
||||
sa.bInheritHandle = TRUE;
|
||||
|
||||
/* Create an anonymous inheritable event object that starts out
|
||||
non-signaled. */
|
||||
event = CreateEvent (&sa, FALSE, FALSE, NULL);
|
||||
if (!event)
|
||||
return;
|
||||
|
||||
/* Creat the child process detached form the current console and in a
|
||||
suspended state. */
|
||||
memset (&si, 0, sizeof (si));
|
||||
si.cb = sizeof (si);
|
||||
rv = CreateProcess (exe, args, NULL, NULL, TRUE, CREATE_SUSPENDED |
|
||||
DETACHED_PROCESS, NULL, NULL, &si, &pi);
|
||||
if (!rv)
|
||||
goto cleanup;
|
||||
|
||||
/* Create a named section object with a name based on the process id of
|
||||
the child. */
|
||||
name = make_section_name (pi.dwProcessId);
|
||||
section =
|
||||
CreateFileMapping (INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0,
|
||||
sizeof (struct fake_fork_info), name);
|
||||
le = GetLastError();
|
||||
xfree (name);
|
||||
/* Fail if the section object already exists (should not happen). */
|
||||
if (!section || (le == ERROR_ALREADY_EXISTS))
|
||||
{
|
||||
rv = FALSE;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Copy the event handle into the section object. */
|
||||
info = MapViewOfFile (section, FILE_MAP_WRITE, 0, 0, 0);
|
||||
if (!info)
|
||||
{
|
||||
rv = FALSE;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
info->event = event;
|
||||
|
||||
UnmapViewOfFile (info);
|
||||
|
||||
/* Start the child process. */
|
||||
rv = ResumeThread (pi.hThread);
|
||||
if (!rv)
|
||||
{
|
||||
TerminateProcess (pi.hProcess, (DWORD) -1);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Wait for the child to signal to us that it has done its part. If it
|
||||
terminates before signaling us it's an error. */
|
||||
|
||||
h[0] = event;
|
||||
h[1] = pi.hProcess;
|
||||
rv = WAIT_OBJECT_0 == WaitForMultipleObjects (2, h, FALSE, 5 * 60 * 1000);
|
||||
if (!rv)
|
||||
goto cleanup;
|
||||
|
||||
info = MapViewOfFile (section, FILE_MAP_READ, 0, 0, 0);
|
||||
if (!info)
|
||||
{
|
||||
rv = FALSE;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Ensure string is properly terminated. */
|
||||
if (info->changedp &&
|
||||
!memchr (info->lfilename, '\0', sizeof (info->lfilename)))
|
||||
{
|
||||
rv = FALSE;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
printf (_("Continuing in background, pid %lu.\n"), pi.dwProcessId);
|
||||
if (info->changedp)
|
||||
printf (_("Output will be written to `%s'.\n"), info->lfilename);
|
||||
|
||||
UnmapViewOfFile (info);
|
||||
|
||||
cleanup:
|
||||
|
||||
if (event)
|
||||
CloseHandle (event);
|
||||
if (section)
|
||||
CloseHandle (section);
|
||||
if (pi.hThread)
|
||||
CloseHandle (pi.hThread);
|
||||
if (pi.hProcess)
|
||||
CloseHandle (pi.hProcess);
|
||||
|
||||
/* We're the parent. If all is well, terminate. */
|
||||
if (rv)
|
||||
exit (0);
|
||||
|
||||
/* We failed, return. */
|
||||
}
|
||||
|
||||
void
|
||||
fork_to_background (void)
|
||||
{
|
||||
ws_hangup ("fork");
|
||||
int rv;
|
||||
|
||||
rv = fake_fork_child ();
|
||||
if (rv < 0)
|
||||
{
|
||||
fprintf (stderr, "fake_fork_child() failed\n");
|
||||
abort ();
|
||||
}
|
||||
else if (rv == 0)
|
||||
{
|
||||
/* We're the parent. */
|
||||
fake_fork ();
|
||||
/* If fake_fork() returns, it failed. */
|
||||
fprintf (stderr, "fake_fork() failed\n");
|
||||
abort ();
|
||||
}
|
||||
/* If we get here, we're the child. */
|
||||
}
|
||||
|
||||
static BOOL WINAPI
|
||||
|
Loading…
Reference in New Issue
Block a user