]> sjero.net Git - wget/blobdiff - src/mswindows.c
[svn] Fix a possible race condition when opening files.
[wget] / src / mswindows.c
index 87eca5d50a87fc89de1e61339037cbe6dea98a3a..22605a95d8fa6b345824c28e6681a43c090117d5 100644 (file)
@@ -86,6 +86,129 @@ xsleep (double seconds)
 #endif /* not HAVE_USLEEP */
 }
 
+#if defined(__BORLANDC__) || (defined(_MSC_VER) && _MSC_VER < 1300)
+
+static inline int
+char_value (char c, int base)
+{
+  int value;
+  if (c < '0')
+    return -1;
+  if ('0' <= c && c <= '9')
+    value = c - '0';
+  else if ('a' <= c && c <= 'z')
+    value = c - 'a' + 10;
+  else if ('A' <= c && c <= 'Z')
+    value = c - 'A' + 10;
+  else
+    return -1;
+  if (value >= base)
+    return -1;
+  return value;
+}
+
+/* A fairly simple strtoll replacement for MS VC versions that don't
+   supply _strtoi64.  */
+
+__int64
+str_to_int64 (const char *nptr, char **endptr, int base)
+{
+#define OVERFLOW 9223372036854775807I64
+#define UNDERFLOW (-OVERFLOW - 1)
+
+  __int64 result = 0;
+  int negative;
+
+  if (base != 0 && (base < 2 || base > 36))
+    {
+      errno = EINVAL;
+      return 0;
+    }
+
+  while (*nptr == ' ' || *nptr == '\t')
+    ++nptr;
+  if (*nptr == '-')
+    {
+      negative = 1;
+      ++nptr;
+    }
+  else if (*nptr == '+')
+    {
+      negative = 0;
+      ++nptr;
+    }
+  else
+    negative = 0;
+
+  /* If base is 0, determine the real base based on the beginning on
+     the number; octal numbers begin with "0", hexadecimal with "0x",
+     and the others are considered octal.  */
+  if (*nptr == '0')
+    {
+      if ((base == 0 || base == 16)
+         &&
+         (*(nptr + 1) == 'x' || *(nptr + 1) == 'X'))
+       {
+         base = 16;
+         nptr += 2;
+       }
+      else if (base == 0)
+       base = 8;
+    }
+  else if (base == 0)
+    base = 10;
+
+  if (!negative)
+    {
+      /* Parse positive number, checking for overflow. */
+      int val;
+      for (; (val = char_value (*nptr, base)) != -1; ++nptr)
+       {
+         __int64 newresult = base * result + val;
+         if (newresult < result)
+           {
+             result = OVERFLOW;
+             errno = ERANGE;
+             break;
+           }
+         result = newresult;
+       }
+    }
+  else
+    {
+      /* Parse negative number, checking for underflow. */
+      int val;
+      for (; (val = char_value (*nptr, base)) != -1; ++nptr)
+       {
+         __int64 newresult = base * result - val;
+         if (newresult > result)
+           {
+             result = UNDERFLOW;
+             errno = ERANGE;
+             break;
+           }
+         result = newresult;
+       }
+    }
+  if (endptr)
+    *endptr = (char *) nptr;
+  return result;
+}
+
+#else  /* !defined(__BORLANDC__) && (!defined(_MSC_VER) || _MSC_VER >= 1300) */
+
+__int64
+str_to_int64 (const char *nptr, char **endptr, int base)
+{
+#ifdef _MSC_VER
+  return _strtoi64 (nptr, endptr, base);
+#else
+  return strtoll (nptr, endptr, base);
+#endif
+}
+
+#endif /* !defined(__BORLANDC__) && (!defined(_MSC_VER) || _MSC_VER >= 1300) */
+
 void
 windows_main_junk (int *argc, char **argv, char **exec_name)
 {
@@ -107,18 +230,7 @@ ws_cleanup (void)
 static void
 ws_hangup (const char *reason)
 {
-  /* Whether we arrange our own version of opt.lfilename here.  */
-  int changedp = 0;
-
-  if (!opt.lfilename)
-    {
-      opt.lfilename = unique_name (DEFAULT_LOGFILE, 0);
-      changedp = 1;
-    }
-  printf (_("Continuing in background.\n"));
-  if (changedp)
-    printf (_("Output will be written to `%s'.\n"), opt.lfilename);
-
+  fprintf (stderr, _("Continuing in background.\n"));
   log_request_redirect_output (reason);
 
   /* Detach process from the current console.  Under Windows 9x, if we
@@ -142,7 +254,7 @@ make_section_name (DWORD pid)
 struct fake_fork_info
 {
   HANDLE event;
-  int changedp;
+  int logfile_changed;
   char lfilename[MAX_PATH + 1];
 };
 
@@ -158,19 +270,15 @@ 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);
+  /* It seems that Windows 9x and NT set last-error inconsistently when
+     OpenFileMapping() fails; so we assume it failed because the section
+     object does not exist.  */
   if (!section)
-    {
-      if (le == ERROR_FILE_NOT_FOUND)
-        return 0;   /* Section object does not exist; we are the parent.  */
-      else
-        return -1;
-    }
+    return 0;                   /* We are the parent.  */
 
   info = MapViewOfFile (section, FILE_MAP_WRITE, 0, 0, 0);
   if (!info)
@@ -181,15 +289,19 @@ fake_fork_child (void)
 
   event = info->event;
 
+  info->logfile_changed = 0;
   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';
+      /* See utils:fork_to_background for explanation. */
+      FILE *new_log_fp = unique_create (DEFAULT_LOGFILE, 0, &opt.lfilename);
+      if (new_log_fp)
+       {
+         info->logfile_changed = 1;
+         strncpy (info->lfilename, opt.lfilename, sizeof (info->lfilename));
+         info->lfilename[sizeof (info->lfilename) - 1] = '\0';
+         fclose (new_log_fp);
+       }
     }
-  else
-    info->changedp = 0;
 
   UnmapViewOfFile (info);
   CloseHandle (section);
@@ -202,11 +314,17 @@ fake_fork_child (void)
   return 1;                     /* We are the child.  */
 }
 
-
+/* Windows doesn't support the fork() call; so we fake it by invoking
+   another copy of Wget with the same arguments with which we were
+   invoked.  The child copy of Wget should perform the same initialization
+   sequence as the parent; so we should have two processes that are
+   essentially identical.  We create a specially named section object that
+   allows the child to distinguish itself from the parent and is used to
+   exchange information between the two processes.  We use an event object
+   for synchronization.  */
 static void
 fake_fork (void)
 {
-  char *cmdline, *args;
   char exe[MAX_PATH + 1];
   DWORD exe_len, le;
   SECURITY_ATTRIBUTES sa;
@@ -219,22 +337,6 @@ fake_fork (void)
 
   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));
@@ -251,12 +353,13 @@ fake_fork (void)
   if (!event)
     return;
 
-  /* Creat the child process detached form the current console and in a
+  /* Create 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);
+  rv = CreateProcess (exe, GetCommandLine (), NULL, NULL, TRUE,
+                      CREATE_SUSPENDED | DETACHED_PROCESS,
+                      NULL, NULL, &si, &pi);
   if (!rv)
     goto cleanup;
 
@@ -312,7 +415,7 @@ fake_fork (void)
     }
 
   /* Ensure string is properly terminated.  */
-  if (info->changedp &&
+  if (info->logfile_changed &&
       !memchr (info->lfilename, '\0', sizeof (info->lfilename)))
     {
       rv = FALSE;
@@ -320,7 +423,7 @@ fake_fork (void)
     }
 
   printf (_("Continuing in background, pid %lu.\n"), pi.dwProcessId);
-  if (info->changedp)
+  if (info->logfile_changed)
     printf (_("Output will be written to `%s'.\n"), info->lfilename);
 
   UnmapViewOfFile (info);
@@ -343,6 +446,8 @@ cleanup:
   /* We failed, return.  */
 }
 
+/* This is the corresponding Windows implementation of the
+   fork_to_background() function in utils.c.  */
 void
 fork_to_background (void)
 {