1 /* mswindows.c -- Windows-specific support
2 Copyright (C) 1995, 1996, 1997, 1998, 2004 Free Software Foundation, Inc.
4 This file is part of GNU Wget.
6 GNU Wget is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 GNU Wget is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with Wget; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 In addition, as a special exception, the Free Software Foundation
21 gives permission to link the code of its release of Wget with the
22 OpenSSL project's "OpenSSL" library (or with modified versions of it
23 that use the same license as the "OpenSSL" library), and distribute
24 the linked executables. You must obey the GNU General Public License
25 in all respects for all of the code used other than "OpenSSL". If you
26 modify this file, you may extend this exception to your version of the
27 file, but you are not obligated to do so. If you do not wish to do
28 so, delete this exception statement from your version. */
30 /* #### Someone please document what these functions do! */
41 #ifdef HACK_BCC_UTIME_BUG
47 # ifdef HAVE_SYS_UTIME_H
48 # include <sys/utime.h>
60 #ifndef ES_SYSTEM_REQUIRED
61 #define ES_SYSTEM_REQUIRED 0x00000001
65 #define ES_CONTINUOUS 0x80000000
69 /* Defined in log.c. */
70 void log_request_redirect_output PARAMS ((const char *));
72 static DWORD set_sleep_mode (DWORD mode);
74 static DWORD pwr_mode = 0;
75 static int windows_nt_p;
77 /* Windows version of xsleep in utils.c. */
80 xsleep (double seconds)
85 /* Explained in utils.c. */
87 seconds -= (long) seconds;
89 usleep (seconds * 1000000L);
90 #else /* not HAVE_USLEEP */
91 SleepEx (seconds * 1000, FALSE);
92 #endif /* not HAVE_USLEEP */
96 windows_main_junk (int *argc, char **argv, char **exec_name)
100 /* Remove .EXE from filename if it has one. */
101 *exec_name = xstrdup (*exec_name);
102 p = strrchr (*exec_name, '.');
114 set_sleep_mode (pwr_mode);
121 log_request_redirect_output ("CTRL+Break");
125 fork_to_background (void)
127 /* Whether we arrange our own version of opt.lfilename here. */
132 opt.lfilename = unique_name (DEFAULT_LOGFILE, 0);
135 printf (_("Continuing in background.\n"));
137 printf (_("Output will be written to `%s'.\n"), opt.lfilename);
145 ws_handler (DWORD dwEvent)
152 #ifdef CTRLBREAK_BACKGND
153 case CTRL_BREAK_EVENT:
155 fork_to_background ();
157 case CTRL_SHUTDOWN_EVENT:
158 case CTRL_CLOSE_EVENT:
159 case CTRL_LOGOFF_EVENT:
167 static char *title_buf = NULL;
168 static char *curr_url = NULL;
169 static int num_urls = 0;
172 ws_changetitle (const char *url, int nurl)
182 title_buf = (char *)xmalloc (strlen (url) + 20);
183 curr_url = xstrdup(url);
184 sprintf(title_buf, "Wget %s%s", url, nurl == 1 ? "" : " ...");
185 SetConsoleTitle(title_buf);
189 ws_percenttitle (double percent)
191 if (num_urls == 1 && title_buf && curr_url && fabs(percent) <= 100.0)
193 sprintf (title_buf, "Wget [%.0f%%] %s", percent, curr_url);
194 SetConsoleTitle (title_buf);
201 static char *wspathsave = NULL;
205 char buf[MAX_PATH + 1];
209 len = GetModuleFileName (GetModuleHandle (NULL), buf, sizeof (buf));
210 if (!len || (len >= sizeof (buf)))
213 p = strrchr (buf, PATH_SEPARATOR);
218 wspathsave = xstrdup (buf);
232 if (GetVersionEx (&os) == TRUE
233 && os.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
236 requested = MAKEWORD (1, 1);
237 err = WSAStartup (requested, &data);
241 fprintf (stderr, _("%s: Couldn't find usable socket driver.\n"),
246 if (data.wVersion < requested)
248 fprintf (stderr, _("%s: Couldn't find usable socket driver.\n"),
254 pwr_mode = set_sleep_mode (0);
255 SetConsoleCtrlHandler (ws_handler, TRUE);
258 /* Replacement utime function for buggy Borland C++Builder 5.5 compiler.
259 (The Borland utime function only works on Windows NT.) */
261 #ifdef HACK_BCC_UTIME_BUG
263 borland_utime (const char *path, const struct utimbuf *times)
270 if ((fd = open (path, O_RDWR)) < 0)
273 ptr_tm = localtime (×->modtime);
274 ft.ft_tsec = ptr_tm->tm_sec >> 1;
275 ft.ft_min = ptr_tm->tm_min;
276 ft.ft_hour = ptr_tm->tm_hour;
277 ft.ft_day = ptr_tm->tm_mday;
278 ft.ft_month = ptr_tm->tm_mon + 1;
279 ft.ft_year = ptr_tm->tm_year - 80;
280 res = setftime (fd, &ft);
287 * Prevent Windows entering sleep/hibernation-mode while wget is doing
288 * a lengthy transfer. Windows does by default not consider network
289 * activity in console-programs as activity ! Works on Win-98/ME/2K
293 set_sleep_mode (DWORD mode)
295 HMODULE mod = LoadLibrary ("kernel32.dll");
296 DWORD (WINAPI *_SetThreadExecutionState) (DWORD) = NULL;
297 DWORD rc = (DWORD)-1;
300 (void *)_SetThreadExecutionState
301 = GetProcAddress ((HINSTANCE)mod, "SetThreadExecutionState");
303 if (_SetThreadExecutionState)
305 if (mode == 0) /* first time */
306 mode = (ES_SYSTEM_REQUIRED | ES_CONTINUOUS);
307 rc = (*_SetThreadExecutionState) (mode);
311 DEBUGP (("set_sleep_mode(): mode 0x%08lX, rc 0x%08lX\n", mode, rc));
315 /* run_with_timeout Windows implementation. */
317 /* Stack size 0 uses default thread stack-size (reserve+commit).
318 * Determined by what's in the PE header.
320 #define THREAD_STACK_SIZE 0
323 void (*fun) (void *);
328 /* The callback that runs FUN(ARG) in a separate thread. This
329 function exists for two reasons: a) to not require FUN to be
330 declared WINAPI/__stdcall[1], and b) to retrieve Winsock errors,
331 which are per-thread. The latter is useful when FUN calls Winsock
332 functions, which is how run_with_timeout is used in Wget.
334 [1] MSVC can use __fastcall globally (cl /Gr) and on Watcom this is
335 the default (wcc386 -3r). */
338 thread_helper (void *arg)
340 struct thread_data *td = (struct thread_data *) arg;
342 /* Initialize Winsock error to what it was in the parent. That way
343 the subsequent call to WSAGetLastError will return the same value
344 if td->fun doesn't change Winsock error state. */
345 WSASetLastError (td->ws_error);
349 /* Return Winsock error to the caller, in case FUN ran Winsock
351 td->ws_error = WSAGetLastError ();
355 /* Call FUN(ARG), but don't allow it to run for more than TIMEOUT
356 seconds. Returns non-zero if the function was interrupted with a
357 timeout, zero otherwise.
359 This works by running FUN in a separate thread and terminating the
360 thread if it doesn't finish in the specified time. */
363 run_with_timeout (double seconds, void (*fun) (void *), void *arg)
365 static HANDLE thread_hnd = NULL;
366 struct thread_data thread_arg;
370 DEBUGP (("seconds %.2f, ", seconds));
379 /* Should never happen, but test for recursivety anyway */
380 assert (thread_hnd == NULL);
382 thread_arg.fun = fun;
383 thread_arg.arg = arg;
384 thread_arg.ws_error = WSAGetLastError ();
385 thread_hnd = CreateThread (NULL, THREAD_STACK_SIZE, thread_helper,
386 &thread_arg, 0, &thread_id);
389 DEBUGP (("CreateThread() failed; %s\n", strerror (GetLastError ())));
390 goto blocking_fallback;
393 if (WaitForSingleObject (thread_hnd, (DWORD)(1000 * seconds))
396 /* Propagate error state (which is per-thread) to this thread,
397 so the caller can inspect it. */
398 WSASetLastError (thread_arg.ws_error);
399 DEBUGP (("Winsock error: %d\n", WSAGetLastError ()));
404 TerminateThread (thread_hnd, 1);
408 CloseHandle (thread_hnd); /* clear-up after TerminateThread() */