1 /* mswindows.c -- Windows-specific support
2 Copyright (C) 1995, 1996, 1997, 1998, 2004
3 Free Software Foundation, Inc.
5 This file is part of GNU Wget.
7 GNU Wget is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 GNU Wget is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with Wget; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 In addition, as a special exception, the Free Software Foundation
22 gives permission to link the code of its release of Wget with the
23 OpenSSL project's "OpenSSL" library (or with modified versions of it
24 that use the same license as the "OpenSSL" library), and distribute
25 the linked executables. You must obey the GNU General Public License
26 in all respects for all of the code used other than "OpenSSL". If you
27 modify this file, you may extend this exception to your version of the
28 file, but you are not obligated to do so. If you do not wish to do
29 so, delete this exception statement from your version. */
40 #ifdef HACK_BCC_UTIME_BUG
46 # ifdef HAVE_SYS_UTIME_H
47 # include <sys/utime.h>
59 #ifndef ES_SYSTEM_REQUIRED
60 #define ES_SYSTEM_REQUIRED 0x00000001
64 #define ES_CONTINUOUS 0x80000000
68 /* Defined in log.c. */
69 void log_request_redirect_output PARAMS ((const char *));
71 /* Windows version of xsleep in utils.c. */
74 xsleep (double seconds)
79 /* Explained in utils.c. */
81 seconds -= (long) seconds;
83 usleep (seconds * 1000000L);
84 #else /* not HAVE_USLEEP */
85 SleepEx (seconds * 1000, FALSE);
86 #endif /* not HAVE_USLEEP */
89 #if defined(_MSC_VER) && _MSC_VER < 1300
92 char_value (char c, int base)
97 if ('0' <= c && c <= '9')
99 else if ('a' <= c && c <= 'z')
100 value = c - 'a' + 10;
101 else if ('A' <= c && c <= 'Z')
102 value = c - 'A' + 10;
110 /* A fairly simple strtoll replacement for MS VC versions that don't
114 str_to_int64 (const char *nptr, char **endptr, int base)
116 #define OVERFLOW 9223372036854775807I64
117 #define UNDERFLOW (-OVERFLOW - 1)
122 if (base != 0 && (base < 2 || base > 36))
128 while (*nptr == ' ' || *nptr == '\t')
135 else if (*nptr == '+')
143 /* If base is 0, determine the real base based on the beginning on
144 the number; octal numbers begin with "0", hexadecimal with "0x",
145 and the others are considered octal. */
148 if ((base == 0 || base == 16)
150 (*(nptr + 1) == 'x' || *(nptr + 1) == 'X'))
163 /* Parse positive number, checking for overflow. */
165 for (; (val = char_value (*nptr, base)) != -1; ++nptr)
167 __int64 newresult = base * result + val;
168 if (newresult < result)
179 /* Parse negative number, checking for underflow. */
181 for (; (val = char_value (*nptr, base)) != -1; ++nptr)
183 __int64 newresult = base * result - val;
184 if (newresult > result)
194 *endptr = (char *) nptr;
198 #else /* !defined(_MSC_VER) || _MSC_VER >= 1300 */
201 str_to_int64 (const char *nptr, char **endptr, int base)
204 return _strtoi64 (nptr, endptr, base);
206 return strtoll (nptr, endptr, base);
210 #endif /* !defined(_MSC_VER) || _MSC_VER >= 1300 */
212 /* A simple clone of ftello. The normal ftell doesn't work for large
213 files, so this is needed, and used by file_size(), which is itself
214 used for the --post-file option.
216 This function uses fgetpos incorrectly and should be considered a
217 hack until a better way to tell the stream position is found. */
220 wget_ftello (FILE *fp)
223 if (fgetpos (fp, &pos) != 0)
230 windows_main_junk (int *argc, char **argv, char **exec_name)
234 /* Remove .EXE from filename if it has one. */
235 *exec_name = xstrdup (*exec_name);
236 p = strrchr (*exec_name, '.');
248 ws_hangup (const char *reason)
250 /* Whether we arrange our own version of opt.lfilename here. */
255 opt.lfilename = unique_name (DEFAULT_LOGFILE, 0);
258 printf (_("Continuing in background.\n"));
260 printf (_("Output will be written to `%s'.\n"), opt.lfilename);
262 log_request_redirect_output (reason);
264 /* Detach process from the current console. Under Windows 9x, if we
265 were launched from a 16-bit process (which is usually the case;
266 command.com is 16-bit) the parent process should resume right away.
267 Under NT or if launched from a 32-process under 9x, this is a futile
268 gesture as the parent will wait for us to terminate before resuming. */
272 /* Construct the name for a named section (a.k.a. `file mapping') object.
273 The returned string is dynamically allocated and needs to be xfree()'d. */
275 make_section_name (DWORD pid)
277 return aprintf ("gnu_wget_fake_fork_%lu", pid);
280 /* This structure is used to hold all the data that is exchanged between
282 struct fake_fork_info
286 char lfilename[MAX_PATH + 1];
289 /* Determines if we are the child and if so performs the child logic.
296 fake_fork_child (void)
298 HANDLE section, event;
299 struct fake_fork_info *info;
302 name = make_section_name (GetCurrentProcessId ());
303 section = OpenFileMapping (FILE_MAP_WRITE, FALSE, name);
305 /* It seems that Windows 9x and NT set last-error inconsistently when
306 OpenFileMapping() fails; so we assume it failed because the section
307 object does not exist. */
309 return 0; /* We are the parent. */
311 info = MapViewOfFile (section, FILE_MAP_WRITE, 0, 0, 0);
314 CloseHandle (section);
322 opt.lfilename = unique_name (DEFAULT_LOGFILE, 0);
324 strncpy (info->lfilename, opt.lfilename, sizeof (info->lfilename));
325 info->lfilename[sizeof (info->lfilename) - 1] = '\0';
330 UnmapViewOfFile (info);
331 CloseHandle (section);
333 /* Inform the parent that we've done our part. */
334 if (!SetEvent (event))
338 return 1; /* We are the child. */
341 /* Windows doesn't support the fork() call; so we fake it by invoking
342 another copy of Wget with the same arguments with which we were
343 invoked. The child copy of Wget should perform the same initialization
344 sequence as the parent; so we should have two processes that are
345 essentially identical. We create a specially named section object that
346 allows the child to distinguish itself from the parent and is used to
347 exchange information between the two processes. We use an event object
348 for synchronization. */
352 char exe[MAX_PATH + 1];
354 SECURITY_ATTRIBUTES sa;
355 HANDLE section, event, h[2];
357 PROCESS_INFORMATION pi;
358 struct fake_fork_info *info;
362 event = section = pi.hProcess = pi.hThread = NULL;
364 /* Get the fully qualified name of our executable. This is more reliable
365 than using argv[0]. */
366 exe_len = GetModuleFileName (GetModuleHandle (NULL), exe, sizeof (exe));
367 if (!exe_len || (exe_len >= sizeof (exe)))
370 sa.nLength = sizeof (sa);
371 sa.lpSecurityDescriptor = NULL;
372 sa.bInheritHandle = TRUE;
374 /* Create an anonymous inheritable event object that starts out
376 event = CreateEvent (&sa, FALSE, FALSE, NULL);
380 /* Create the child process detached form the current console and in a
382 memset (&si, 0, sizeof (si));
384 rv = CreateProcess (exe, GetCommandLine (), NULL, NULL, TRUE,
385 CREATE_SUSPENDED | DETACHED_PROCESS,
386 NULL, NULL, &si, &pi);
390 /* Create a named section object with a name based on the process id of
392 name = make_section_name (pi.dwProcessId);
394 CreateFileMapping (INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0,
395 sizeof (struct fake_fork_info), name);
398 /* Fail if the section object already exists (should not happen). */
399 if (!section || (le == ERROR_ALREADY_EXISTS))
405 /* Copy the event handle into the section object. */
406 info = MapViewOfFile (section, FILE_MAP_WRITE, 0, 0, 0);
415 UnmapViewOfFile (info);
417 /* Start the child process. */
418 rv = ResumeThread (pi.hThread);
421 TerminateProcess (pi.hProcess, (DWORD) -1);
425 /* Wait for the child to signal to us that it has done its part. If it
426 terminates before signaling us it's an error. */
430 rv = WAIT_OBJECT_0 == WaitForMultipleObjects (2, h, FALSE, 5 * 60 * 1000);
434 info = MapViewOfFile (section, FILE_MAP_READ, 0, 0, 0);
441 /* Ensure string is properly terminated. */
442 if (info->changedp &&
443 !memchr (info->lfilename, '\0', sizeof (info->lfilename)))
449 printf (_("Continuing in background, pid %lu.\n"), pi.dwProcessId);
451 printf (_("Output will be written to `%s'.\n"), info->lfilename);
453 UnmapViewOfFile (info);
460 CloseHandle (section);
462 CloseHandle (pi.hThread);
464 CloseHandle (pi.hProcess);
466 /* We're the parent. If all is well, terminate. */
470 /* We failed, return. */
473 /* This is the corresponding Windows implementation of the
474 fork_to_background() function in utils.c. */
476 fork_to_background (void)
480 rv = fake_fork_child ();
483 fprintf (stderr, "fake_fork_child() failed\n");
488 /* We're the parent. */
490 /* If fake_fork() returns, it failed. */
491 fprintf (stderr, "fake_fork() failed\n");
494 /* If we get here, we're the child. */
498 ws_handler (DWORD dwEvent)
504 ws_hangup ("CTRL+C");
507 #ifdef CTRLBREAK_BACKGND
508 case CTRL_BREAK_EVENT:
509 ws_hangup ("CTRL+Break");
517 static char *title_buf = NULL;
518 static char *curr_url = NULL;
519 static int old_percentage = -1;
521 /* Updates the console title with the URL of the current file being
524 ws_changetitle (const char *url)
526 xfree_null (title_buf);
527 xfree_null (curr_url);
528 title_buf = (char *)xmalloc (strlen (url) + 20);
529 curr_url = xstrdup (url);
531 sprintf (title_buf, "Wget %s", curr_url);
532 SetConsoleTitle (title_buf);
535 /* Updates the console title with the percentage of the current file
538 ws_percenttitle (double percentage_float)
542 if (!title_buf || !curr_url)
545 percentage = (int) percentage_float;
547 /* Clamp percentage value. */
550 if (percentage > 100)
553 /* Only update the title when the percentage has changed. */
554 if (percentage == old_percentage)
557 old_percentage = percentage;
559 sprintf (title_buf, "Wget [%d%%] %s", percentage, curr_url);
560 SetConsoleTitle (title_buf);
563 /* Returns a pointer to the fully qualified name of the directory that
564 contains the Wget binary (wget.exe). The returned path does not have a
565 trailing path separator. Returns NULL on failure. */
569 static char *wspathsave = NULL;
573 char buf[MAX_PATH + 1];
577 len = GetModuleFileName (GetModuleHandle (NULL), buf, sizeof (buf));
578 if (!len || (len >= sizeof (buf)))
581 p = strrchr (buf, PATH_SEPARATOR);
586 wspathsave = xstrdup (buf);
592 /* Prevent Windows entering sleep/hibernation-mode while Wget is doing
593 a lengthy transfer. Windows does not, by default, consider network
594 activity in console-programs as activity! Works on Win-98/ME/2K
597 set_sleep_mode (void)
599 typedef DWORD (WINAPI *func_t) (DWORD);
600 func_t set_exec_state;
603 (func_t) GetProcAddress (GetModuleHandle ("KERNEL32.DLL"),
604 "SetThreadExecutionState");
607 set_exec_state (ES_SYSTEM_REQUIRED | ES_CONTINUOUS);
610 /* Perform Windows specific initialization. */
618 requested = MAKEWORD (1, 1);
619 err = WSAStartup (requested, &data);
622 fprintf (stderr, _("%s: Couldn't find usable socket driver.\n"),
627 if (data.wVersion < requested)
629 fprintf (stderr, _("%s: Couldn't find usable socket driver.\n"),
637 SetConsoleCtrlHandler (ws_handler, TRUE);
640 /* Replacement utime function for buggy Borland C++Builder 5.5 compiler.
641 (The Borland utime function only works on Windows NT.) */
643 #ifdef HACK_BCC_UTIME_BUG
645 borland_utime (const char *path, const struct utimbuf *times)
652 if ((fd = open (path, O_RDWR)) < 0)
655 ptr_tm = localtime (×->modtime);
656 ft.ft_tsec = ptr_tm->tm_sec >> 1;
657 ft.ft_min = ptr_tm->tm_min;
658 ft.ft_hour = ptr_tm->tm_hour;
659 ft.ft_day = ptr_tm->tm_mday;
660 ft.ft_month = ptr_tm->tm_mon + 1;
661 ft.ft_year = ptr_tm->tm_year - 80;
662 res = setftime (fd, &ft);
668 /* run_with_timeout Windows implementation. */
670 /* Stack size 0 uses default thread stack-size (reserve+commit).
671 Determined by what's in the PE header. */
672 #define THREAD_STACK_SIZE 0
676 void (*fun) (void *);
681 /* The callback that runs FUN(ARG) in a separate thread. This
682 function exists for two reasons: a) to not require FUN to be
683 declared WINAPI/__stdcall[1], and b) to retrieve Winsock errors,
684 which are per-thread. The latter is useful when FUN calls Winsock
685 functions, which is how run_with_timeout is used in Wget.
687 [1] MSVC can use __fastcall globally (cl /Gr) and on Watcom this is
688 the default (wcc386 -3r). */
691 thread_helper (void *arg)
693 struct thread_data *td = (struct thread_data *) arg;
695 /* Initialize Winsock error to what it was in the parent. That way
696 the subsequent call to WSAGetLastError will return the same value
697 if td->fun doesn't change Winsock error state. */
698 WSASetLastError (td->ws_error);
702 /* Return Winsock error to the caller, in case FUN ran Winsock
704 td->ws_error = WSAGetLastError ();
708 /* Call FUN(ARG), but don't allow it to run for more than TIMEOUT
709 seconds. Returns non-zero if the function was interrupted with a
710 timeout, zero otherwise.
712 This works by running FUN in a separate thread and terminating the
713 thread if it doesn't finish in the specified time. */
716 run_with_timeout (double seconds, void (*fun) (void *), void *arg)
718 static HANDLE thread_hnd = NULL;
719 struct thread_data thread_arg;
723 DEBUGP (("seconds %.2f, ", seconds));
732 /* Should never happen, but test for recursivety anyway. */
733 assert (thread_hnd == NULL);
735 thread_arg.fun = fun;
736 thread_arg.arg = arg;
737 thread_arg.ws_error = WSAGetLastError ();
738 thread_hnd = CreateThread (NULL, THREAD_STACK_SIZE, thread_helper,
739 &thread_arg, 0, &thread_id);
742 DEBUGP (("CreateThread() failed; %s\n", strerror (GetLastError ())));
743 goto blocking_fallback;
746 if (WaitForSingleObject (thread_hnd, (DWORD)(1000 * seconds))
749 /* Propagate error state (which is per-thread) to this thread,
750 so the caller can inspect it. */
751 WSASetLastError (thread_arg.ws_error);
752 DEBUGP (("Winsock error: %d\n", WSAGetLastError ()));
757 TerminateThread (thread_hnd, 1);
761 CloseHandle (thread_hnd); /* Clear-up after TerminateThread(). */