Hrvoje Niksic wrote:
For now I'd start with applying David's patch, so that people can test
its functionality.  It is easy to fix the behavior of `wget -q -b'
later.

David, can I apply your patch now?

Sure.


The attached patch corrects a few minor formatting details but is otherwise identical to the previous one.

Index: src/mswindows.c
===================================================================
RCS file: /pack/anoncvs/wget/src/mswindows.c,v
retrieving revision 1.29
diff -u -r1.29 mswindows.c
--- src/mswindows.c     2004/03/19 23:54:27     1.29
+++ src/mswindows.c     2004/03/24 17:50:32
@@ -131,10 +131,240 @@
   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

Reply via email to