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);
225 ws_help (const char *name)
227 char *mypath = ws_mypath ();
232 char *buf = (char *)alloca (strlen (mypath) + strlen (name) + 4 + 1);
233 sprintf (buf, "%s%s.HLP", mypath, name);
234 if (stat (buf, &sbuf) == 0)
236 printf (_("Starting WinHelp %s\n"), buf);
237 WinHelp (NULL, buf, HELP_INDEX, 0);
241 printf ("%s: %s\n", buf, strerror (errno));
254 if (GetVersionEx (&os) == TRUE
255 && os.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
258 requested = MAKEWORD (1, 1);
259 err = WSAStartup (requested, &data);
263 fprintf (stderr, _("%s: Couldn't find usable socket driver.\n"),
268 if (data.wVersion < requested)
270 fprintf (stderr, _("%s: Couldn't find usable socket driver.\n"),
276 pwr_mode = set_sleep_mode (0);
277 SetConsoleCtrlHandler (ws_handler, TRUE);
280 /* Replacement utime function for buggy Borland C++Builder 5.5 compiler.
281 (The Borland utime function only works on Windows NT.) */
283 #ifdef HACK_BCC_UTIME_BUG
285 borland_utime (const char *path, const struct utimbuf *times)
292 if ((fd = open (path, O_RDWR)) < 0)
295 ptr_tm = localtime (×->modtime);
296 ft.ft_tsec = ptr_tm->tm_sec >> 1;
297 ft.ft_min = ptr_tm->tm_min;
298 ft.ft_hour = ptr_tm->tm_hour;
299 ft.ft_day = ptr_tm->tm_mday;
300 ft.ft_month = ptr_tm->tm_mon + 1;
301 ft.ft_year = ptr_tm->tm_year - 80;
302 res = setftime (fd, &ft);
309 * Prevent Windows entering sleep/hibernation-mode while wget is doing
310 * a lengthy transfer. Windows does by default not consider network
311 * activity in console-programs as activity ! Works on Win-98/ME/2K
315 set_sleep_mode (DWORD mode)
317 HMODULE mod = LoadLibrary ("kernel32.dll");
318 DWORD (WINAPI *_SetThreadExecutionState) (DWORD) = NULL;
319 DWORD rc = (DWORD)-1;
322 (void *)_SetThreadExecutionState
323 = GetProcAddress ((HINSTANCE)mod, "SetThreadExecutionState");
325 if (_SetThreadExecutionState)
327 if (mode == 0) /* first time */
328 mode = (ES_SYSTEM_REQUIRED | ES_CONTINUOUS);
329 rc = (*_SetThreadExecutionState) (mode);
333 DEBUGP (("set_sleep_mode(): mode 0x%08lX, rc 0x%08lX\n", mode, rc));
337 /* run_with_timeout Windows implementation. */
339 /* Stack size 0 uses default thread stack-size (reserve+commit).
340 * Determined by what's in the PE header.
342 #define THREAD_STACK_SIZE 0
345 void (*fun) (void *);
350 /* The callback that runs FUN(ARG) in a separate thread. This
351 function exists for two reasons: a) to not require FUN to be
352 declared WINAPI/__stdcall[1], and b) to retrieve Winsock errors,
353 which are per-thread. The latter is useful when FUN calls Winsock
354 functions, which is how run_with_timeout is used in Wget.
356 [1] MSVC can use __fastcall globally (cl /Gr) and on Watcom this is
357 the default (wcc386 -3r). */
360 thread_helper (void *arg)
362 struct thread_data *td = (struct thread_data *) arg;
364 /* Initialize Winsock error to what it was in the parent. That way
365 the subsequent call to WSAGetLastError will return the same value
366 if td->fun doesn't change Winsock error state. */
367 WSASetLastError (td->ws_error);
371 /* Return Winsock error to the caller, in case FUN ran Winsock
373 td->ws_error = WSAGetLastError ();
377 /* Call FUN(ARG), but don't allow it to run for more than TIMEOUT
378 seconds. Returns non-zero if the function was interrupted with a
379 timeout, zero otherwise.
381 This works by running FUN in a separate thread and terminating the
382 thread if it doesn't finish in the specified time. */
385 run_with_timeout (double seconds, void (*fun) (void *), void *arg)
387 static HANDLE thread_hnd = NULL;
388 struct thread_data thread_arg;
392 DEBUGP (("seconds %.2f, ", seconds));
401 /* Should never happen, but test for recursivety anyway */
402 assert (thread_hnd == NULL);
404 thread_arg.fun = fun;
405 thread_arg.arg = arg;
406 thread_arg.ws_error = WSAGetLastError ();
407 thread_hnd = CreateThread (NULL, THREAD_STACK_SIZE, thread_helper,
408 &thread_arg, 0, &thread_id);
411 DEBUGP (("CreateThread() failed; %s\n", strerror (GetLastError ())));
412 goto blocking_fallback;
415 if (WaitForSingleObject (thread_hnd, (DWORD)(1000 * seconds))
418 /* Propagate error state (which is per-thread) to this thread,
419 so the caller can inspect it. */
420 WSASetLastError (thread_arg.ws_error);
421 DEBUGP (("Winsock error: %d\n", WSAGetLastError ()));
426 TerminateThread (thread_hnd, 1);
430 CloseHandle (thread_hnd); /* clear-up after TerminateThread() */