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. */
31 /* #### Someone please document what these functions do! */
42 #ifdef HACK_BCC_UTIME_BUG
48 # ifdef HAVE_SYS_UTIME_H
49 # include <sys/utime.h>
61 #ifndef ES_SYSTEM_REQUIRED
62 #define ES_SYSTEM_REQUIRED 0x00000001
66 #define ES_CONTINUOUS 0x80000000
70 /* Defined in log.c. */
71 void log_request_redirect_output PARAMS ((const char *));
73 static DWORD set_sleep_mode (DWORD mode);
75 static DWORD pwr_mode = 0;
76 static int windows_nt_p;
78 /* Windows version of xsleep in utils.c. */
81 xsleep (double seconds)
86 /* Explained in utils.c. */
88 seconds -= (long) seconds;
90 usleep (seconds * 1000000L);
91 #else /* not HAVE_USLEEP */
92 SleepEx (seconds * 1000, FALSE);
93 #endif /* not HAVE_USLEEP */
97 windows_main_junk (int *argc, char **argv, char **exec_name)
101 /* Remove .EXE from filename if it has one. */
102 *exec_name = xstrdup (*exec_name);
103 p = strrchr (*exec_name, '.');
113 set_sleep_mode (pwr_mode);
120 log_request_redirect_output ("CTRL+Break");
124 fork_to_background (void)
126 /* Whether we arrange our own version of opt.lfilename here. */
131 opt.lfilename = unique_name (DEFAULT_LOGFILE, 0);
134 printf (_("Continuing in background.\n"));
136 printf (_("Output will be written to `%s'.\n"), opt.lfilename);
144 ws_handler (DWORD dwEvent)
151 #ifdef CTRLBREAK_BACKGND
152 case CTRL_BREAK_EVENT:
154 fork_to_background ();
156 case CTRL_SHUTDOWN_EVENT:
157 case CTRL_CLOSE_EVENT:
158 case CTRL_LOGOFF_EVENT:
166 static char *title_buf = NULL;
167 static char *curr_url = NULL;
168 static int num_urls = 0;
171 ws_changetitle (const char *url, int nurl)
181 title_buf = (char *)xmalloc (strlen (url) + 20);
182 curr_url = xstrdup(url);
183 sprintf(title_buf, "Wget %s%s", url, nurl == 1 ? "" : " ...");
184 SetConsoleTitle(title_buf);
188 ws_percenttitle (double percent)
190 if (num_urls == 1 && title_buf && curr_url && fabs(percent) <= 100.0)
192 sprintf (title_buf, "Wget [%.0f%%] %s", percent, curr_url);
193 SetConsoleTitle (title_buf);
197 /* Returns a pointer to the fully qualified name of the directory that
198 contains the Wget binary (wget.exe). The returned path does not have a
199 trailing path separator. Returns NULL on failure. */
203 static char *wspathsave = NULL;
207 char buf[MAX_PATH + 1];
211 len = GetModuleFileName (GetModuleHandle (NULL), buf, sizeof (buf));
212 if (!len || (len >= sizeof (buf)))
215 p = strrchr (buf, PATH_SEPARATOR);
220 wspathsave = xstrdup (buf);
226 /* Perform Windows specific initialization. */
235 if (GetVersionEx (&os) == TRUE
236 && os.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
239 requested = MAKEWORD (1, 1);
240 err = WSAStartup (requested, &data);
243 fprintf (stderr, _("%s: Couldn't find usable socket driver.\n"),
248 if (data.wVersion < requested)
250 fprintf (stderr, _("%s: Couldn't find usable socket driver.\n"),
257 pwr_mode = set_sleep_mode (0);
258 SetConsoleCtrlHandler (ws_handler, TRUE);
261 /* Replacement utime function for buggy Borland C++Builder 5.5 compiler.
262 (The Borland utime function only works on Windows NT.) */
264 #ifdef HACK_BCC_UTIME_BUG
266 borland_utime (const char *path, const struct utimbuf *times)
273 if ((fd = open (path, O_RDWR)) < 0)
276 ptr_tm = localtime (×->modtime);
277 ft.ft_tsec = ptr_tm->tm_sec >> 1;
278 ft.ft_min = ptr_tm->tm_min;
279 ft.ft_hour = ptr_tm->tm_hour;
280 ft.ft_day = ptr_tm->tm_mday;
281 ft.ft_month = ptr_tm->tm_mon + 1;
282 ft.ft_year = ptr_tm->tm_year - 80;
283 res = setftime (fd, &ft);
289 /* Prevent Windows entering sleep/hibernation-mode while Wget is doing
290 a lengthy transfer. Windows does not, by default, consider network
291 activity in console-programs as activity! Works on Win-98/ME/2K
294 set_sleep_mode (DWORD mode)
296 HMODULE mod = LoadLibrary ("kernel32.dll");
297 DWORD (WINAPI *_SetThreadExecutionState) (DWORD) = NULL;
298 DWORD rc = (DWORD)-1;
301 (void *)_SetThreadExecutionState
302 = GetProcAddress ((HINSTANCE)mod, "SetThreadExecutionState");
304 if (_SetThreadExecutionState)
306 if (mode == 0) /* first time */
307 mode = (ES_SYSTEM_REQUIRED | ES_CONTINUOUS);
308 rc = (*_SetThreadExecutionState) (mode);
312 DEBUGP (("set_sleep_mode(): mode 0x%08lX, rc 0x%08lX\n", mode, rc));
316 /* run_with_timeout Windows implementation. */
318 /* Stack size 0 uses default thread stack-size (reserve+commit).
319 Determined by what's in the PE header. */
320 #define THREAD_STACK_SIZE 0
324 void (*fun) (void *);
329 /* The callback that runs FUN(ARG) in a separate thread. This
330 function exists for two reasons: a) to not require FUN to be
331 declared WINAPI/__stdcall[1], and b) to retrieve Winsock errors,
332 which are per-thread. The latter is useful when FUN calls Winsock
333 functions, which is how run_with_timeout is used in Wget.
335 [1] MSVC can use __fastcall globally (cl /Gr) and on Watcom this is
336 the default (wcc386 -3r). */
339 thread_helper (void *arg)
341 struct thread_data *td = (struct thread_data *) arg;
343 /* Initialize Winsock error to what it was in the parent. That way
344 the subsequent call to WSAGetLastError will return the same value
345 if td->fun doesn't change Winsock error state. */
346 WSASetLastError (td->ws_error);
350 /* Return Winsock error to the caller, in case FUN ran Winsock
352 td->ws_error = WSAGetLastError ();
356 /* Call FUN(ARG), but don't allow it to run for more than TIMEOUT
357 seconds. Returns non-zero if the function was interrupted with a
358 timeout, zero otherwise.
360 This works by running FUN in a separate thread and terminating the
361 thread if it doesn't finish in the specified time. */
364 run_with_timeout (double seconds, void (*fun) (void *), void *arg)
366 static HANDLE thread_hnd = NULL;
367 struct thread_data thread_arg;
371 DEBUGP (("seconds %.2f, ", seconds));
380 /* Should never happen, but test for recursivety anyway. */
381 assert (thread_hnd == NULL);
383 thread_arg.fun = fun;
384 thread_arg.arg = arg;
385 thread_arg.ws_error = WSAGetLastError ();
386 thread_hnd = CreateThread (NULL, THREAD_STACK_SIZE, thread_helper,
387 &thread_arg, 0, &thread_id);
390 DEBUGP (("CreateThread() failed; %s\n", strerror (GetLastError ())));
391 goto blocking_fallback;
394 if (WaitForSingleObject (thread_hnd, (DWORD)(1000 * seconds))
397 /* Propagate error state (which is per-thread) to this thread,
398 so the caller can inspect it. */
399 WSASetLastError (thread_arg.ws_error);
400 DEBUGP (("Winsock error: %d\n", WSAGetLastError ()));
405 TerminateThread (thread_hnd, 1);
409 CloseHandle (thread_hnd); /* Clear-up after TerminateThread(). */