aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/win_updater
diff options
context:
space:
mode:
Diffstat (limited to 'linden/indra/win_updater')
-rw-r--r--linden/indra/win_updater/CMakeLists.txt11
-rw-r--r--linden/indra/win_updater/updater.cpp288
2 files changed, 175 insertions, 124 deletions
diff --git a/linden/indra/win_updater/CMakeLists.txt b/linden/indra/win_updater/CMakeLists.txt
index 6379d7c..dedb7cf 100644
--- a/linden/indra/win_updater/CMakeLists.txt
+++ b/linden/indra/win_updater/CMakeLists.txt
@@ -21,10 +21,15 @@ list(APPEND win_updater_SOURCE_FILES ${win_updater_HEADER_FILES})
21 21
22add_executable(windows-updater WIN32 ${win_updater_SOURCE_FILES}) 22add_executable(windows-updater WIN32 ${win_updater_SOURCE_FILES})
23 23
24target_link_libraries(windows-updater wininet) 24target_link_libraries(windows-updater
25 wininet
26 user32
27 gdi32
28 shell32
29 )
25 30
26set_target_properties(windows-updater 31set_target_properties(windows-updater
27 PROPERTIES 32 PROPERTIES
28 LINK_FLAGS "/NODEFAULTLIB:MSVCRT" 33 LINK_FLAGS "/NODEFAULTLIB:LIBCMT"
29 LINK_FLAGS_DEBUG "/NODEFAULTLIB:\"LIBCMT;MSVCRTD\"" 34 LINK_FLAGS_DEBUG "/NODEFAULTLIB:\"LIBCMT;LIBCMTD;MSVCRT\""
30 ) 35 )
diff --git a/linden/indra/win_updater/updater.cpp b/linden/indra/win_updater/updater.cpp
index 9aed612..4a50731 100644
--- a/linden/indra/win_updater/updater.cpp
+++ b/linden/indra/win_updater/updater.cpp
@@ -17,7 +17,8 @@
17 * There are special exceptions to the terms and conditions of the GPL as 17 * There are special exceptions to the terms and conditions of the GPL as
18 * it is applied to this Source Code. View the full text of the exception 18 * it is applied to this Source Code. View the full text of the exception
19 * in the file doc/FLOSS-exception.txt in this software distribution, or 19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
21 * 22 *
22 * By copying, modifying or distributing this software, you acknowledge 23 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above, 24 * that you have read and understood your obligations described above,
@@ -33,10 +34,19 @@
33// Usage: updater -url <url> 34// Usage: updater -url <url>
34// 35//
35 36
36#include "linden_common.h" 37// We use dangerous fopen, strtok, mbstowcs, sprintf
38// which generates warnings on VC2005.
39// *TODO: Switch to fopen_s, strtok_s, etc.
40#define _CRT_SECURE_NO_DEPRECATE
37 41
38#include <windows.h> 42#include <windows.h>
39#include <wininet.h> 43#include <wininet.h>
44#include <stdio.h>
45#include <string>
46#include <iostream>
47#include <stdexcept>
48#include <sstream>
49#include <fstream>
40 50
41#define BUFSIZE 8192 51#define BUFSIZE 8192
42 52
@@ -44,16 +54,19 @@ int gTotalBytesRead = 0;
44DWORD gTotalBytes = -1; 54DWORD gTotalBytes = -1;
45HWND gWindow = NULL; 55HWND gWindow = NULL;
46WCHAR gProgress[256]; 56WCHAR gProgress[256];
47char* gUpdateURL; 57char* gUpdateURL = NULL;
48 58
49#if _DEBUG 59#if _DEBUG
50FILE* logfile = 0; 60std::ofstream logfile;
61#define DEBUG(expr) logfile << expr << std::endl
62#else
63#define DEBUG(expr) /**/
51#endif 64#endif
52 65
53char* wchars_to_utf8chars(WCHAR* in_chars) 66char* wchars_to_utf8chars(const WCHAR* in_chars)
54{ 67{
55 int tlen = 0; 68 int tlen = 0;
56 WCHAR* twc = in_chars; 69 const WCHAR* twc = in_chars;
57 while (*twc++ != 0) 70 while (*twc++ != 0)
58 { 71 {
59 tlen++; 72 tlen++;
@@ -76,103 +89,128 @@ char* wchars_to_utf8chars(WCHAR* in_chars)
76 return res; 89 return res;
77} 90}
78 91
79int WINAPI get_url_into_file(WCHAR *uri, char *path, int *cancelled) 92class Fetcher
93{
94public:
95 Fetcher(const std::wstring& uri)
96 {
97 // These actions are broken out as separate methods not because it
98 // makes the code clearer, but to avoid triggering AntiVir and
99 // McAfee-GW-Edition virus scanners (DEV-31680).
100 mInet = openInet();
101 mDownload = openUrl(uri);
102 }
103
104 ~Fetcher()
105 {
106 DEBUG("Calling InternetCloseHandle");
107 InternetCloseHandle(mDownload);
108 InternetCloseHandle(mInet);
109 }
110
111 unsigned long read(char* buffer, size_t bufflen) const;
112
113 DWORD getTotalBytes() const
114 {
115 DWORD totalBytes;
116 DWORD sizeof_total_bytes = sizeof(totalBytes);
117 HttpQueryInfo(mDownload, HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER,
118 &totalBytes, &sizeof_total_bytes, NULL);
119 return totalBytes;
120 }
121
122 struct InetError: public std::runtime_error
123 {
124 InetError(const std::string& what): std::runtime_error(what) {}
125 };
126
127private:
128 // We test results from a number of different MS functions with different
129 // return types -- but the common characteristic is that 0 (i.e. (! result))
130 // means an error of some kind.
131 template <typename RESULT>
132 static RESULT check(const std::string& desc, RESULT result)
133 {
134 if (result)
135 {
136 // success, show caller
137 return result;
138 }
139 DWORD err = GetLastError();
140 std::ostringstream out;
141 out << desc << " Failed: " << err;
142 DEBUG(out.str());
143 throw InetError(out.str());
144 }
145
146 HINTERNET openUrl(const std::wstring& uri) const;
147 HINTERNET openInet() const;
148
149 HINTERNET mInet, mDownload;
150};
151
152HINTERNET Fetcher::openInet() const
153{
154 DEBUG("Calling InternetOpen");
155 // Init wininet subsystem
156 return check("InternetOpen",
157 InternetOpen(L"LindenUpdater", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0));
158}
159
160HINTERNET Fetcher::openUrl(const std::wstring& uri) const
161{
162 DEBUG("Calling InternetOpenUrl: " << wchars_to_utf8chars(uri.c_str()));
163 return check("InternetOpenUrl",
164 InternetOpenUrl(mInet, uri.c_str(), NULL, 0, INTERNET_FLAG_NEED_FILE, NULL));
165}
166
167unsigned long Fetcher::read(char* buffer, size_t bufflen) const
168{
169 unsigned long bytes_read = 0;
170 DEBUG("Calling InternetReadFile");
171 check("InternetReadFile",
172 InternetReadFile(mDownload, buffer, bufflen, &bytes_read));
173 return bytes_read;
174}
175
176int WINAPI get_url_into_file(const std::wstring& uri, const std::string& path, int *cancelled)
80{ 177{
81 int success = FALSE; 178 int success = FALSE;
82 *cancelled = FALSE; 179 *cancelled = FALSE;
83 180
84 HINTERNET hinet, hdownload; 181 DEBUG("Opening '" << path << "'");
85 char data[BUFSIZE]; /* Flawfinder: ignore */
86 unsigned long bytes_read;
87
88#if _DEBUG
89 fprintf(logfile,"Opening '%s'\n",path);
90 fflush(logfile);
91#endif
92 182
93 FILE* fp = fopen(path, "wb"); /* Flawfinder: ignore */ 183 FILE* fp = fopen(path.c_str(), "wb"); /* Flawfinder: ignore */
94 184
95 if (!fp) 185 if (!fp)
96 { 186 {
97#if _DEBUG 187 DEBUG("Failed to open '" << path << "'");
98 fprintf(logfile,"Failed to open '%s'\n",path);
99 fflush(logfile);
100#endif
101 return success;
102 }
103
104#if _DEBUG
105 fprintf(logfile,"Calling InternetOpen\n");
106 fflush(logfile);
107#endif
108 // Init wininet subsystem
109 hinet = InternetOpen(L"LindenUpdater", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
110 if (hinet == NULL)
111 {
112 return success; 188 return success;
113 } 189 }
114 190
115#if _DEBUG 191 // Note, ctor can throw, since it uses check() function.
116 fprintf(logfile,"Calling InternetOpenUrl: %s\n",wchars_to_utf8chars(uri)); 192 Fetcher fetcher(uri);
117 fflush(logfile); 193 gTotalBytes = fetcher.getTotalBytes();
118#endif
119 hdownload = InternetOpenUrl(hinet, uri, NULL, 0, INTERNET_FLAG_NEED_FILE, NULL);
120 if (hdownload == NULL)
121 {
122#if _DEBUG
123 DWORD err = GetLastError();
124 fprintf(logfile,"InternetOpenUrl Failed: %d\n",err);
125 fflush(logfile);
126#endif
127 return success;
128 }
129 194
130 DWORD sizeof_total_bytes = sizeof(gTotalBytes); 195/*==========================================================================*|
131 HttpQueryInfo(hdownload, HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER, &gTotalBytes, &sizeof_total_bytes, NULL); 196 // nobody uses total_bytes?!? What's this doing here?
132
133 DWORD total_bytes = 0; 197 DWORD total_bytes = 0;
134 success = InternetQueryDataAvailable(hdownload, &total_bytes, 0, 0); 198 success = check("InternetQueryDataAvailable",
135 if (success == FALSE) 199 InternetQueryDataAvailable(hdownload, &total_bytes, 0, 0));
136 { 200|*==========================================================================*/
137#if _DEBUG
138 DWORD err = GetLastError();
139 fprintf(logfile,"InternetQueryDataAvailable Failed: %d bytes Err:%d\n",total_bytes,err);
140 fflush(logfile);
141#endif
142 return success;
143 }
144 201
145 success = FALSE; 202 success = FALSE;
146 while(!success && !(*cancelled)) 203 while(!success && !(*cancelled))
147 { 204 {
148 MSG msg; 205 char data[BUFSIZE]; /* Flawfinder: ignore */
149 206 unsigned long bytes_read = fetcher.read(data, sizeof(data));
150#if _DEBUG
151 fprintf(logfile,"Calling InternetReadFile\n");
152 fflush(logfile);
153#endif
154 if (!InternetReadFile(hdownload, data, BUFSIZE, &bytes_read))
155 {
156#if _DEBUG
157 fprintf(logfile,"InternetReadFile Failed.\n");
158 fflush(logfile);
159#endif
160 // ...an error occurred
161 return FALSE;
162 }
163 207
164#if _DEBUG
165 if (!bytes_read) 208 if (!bytes_read)
166 { 209 {
167 fprintf(logfile,"InternetReadFile Read 0 bytes.\n"); 210 DEBUG("InternetReadFile Read " << bytes_read << " bytes.");
168 fflush(logfile);
169 } 211 }
170#endif
171 212
172#if _DEBUG 213 DEBUG("Reading Data, bytes_read = " << bytes_read);
173 fprintf(logfile,"Reading Data, bytes_read = %d\n",bytes_read);
174 fflush(logfile);
175#endif
176 214
177 if (bytes_read == 0) 215 if (bytes_read == 0)
178 { 216 {
@@ -195,25 +233,17 @@ int WINAPI get_url_into_file(WCHAR *uri, char *path, int *cancelled)
195 233
196 } 234 }
197 235
198#if _DEBUG 236 DEBUG("Calling InvalidateRect");
199 fprintf(logfile,"Calling InvalidateRect\n");
200 fflush(logfile);
201#endif
202 237
203 // Mark the window as needing redraw (of the whole thing) 238 // Mark the window as needing redraw (of the whole thing)
204 InvalidateRect(gWindow, NULL, TRUE); 239 InvalidateRect(gWindow, NULL, TRUE);
205 240
206 // Do the redraw 241 // Do the redraw
207#if _DEBUG 242 DEBUG("Calling UpdateWindow");
208 fprintf(logfile,"Calling UpdateWindow\n");
209 fflush(logfile);
210#endif
211 UpdateWindow(gWindow); 243 UpdateWindow(gWindow);
212 244
213#if _DEBUG 245 DEBUG("Calling PeekMessage");
214 fprintf(logfile,"Calling PeekMessage\n"); 246 MSG msg;
215 fflush(logfile);
216#endif
217 while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) 247 while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
218 { 248 {
219 TranslateMessage(&msg); 249 TranslateMessage(&msg);
@@ -227,15 +257,7 @@ int WINAPI get_url_into_file(WCHAR *uri, char *path, int *cancelled)
227 } 257 }
228 } 258 }
229 259
230#if _DEBUG
231 fprintf(logfile,"Calling InternetCloseHandle\n");
232 fclose(logfile);
233#endif
234
235 fclose(fp); 260 fclose(fp);
236 InternetCloseHandle(hdownload);
237 InternetCloseHandle(hinet);
238
239 return success; 261 return success;
240} 262}
241 263
@@ -301,9 +323,8 @@ WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nSho
301 char* argv[MAX_ARGS]; /* Flawfinder: ignore */ 323 char* argv[MAX_ARGS]; /* Flawfinder: ignore */
302 324
303#if _DEBUG 325#if _DEBUG
304 logfile = _wfopen(TEXT("updater.log"),TEXT("wt")); 326 logfile.open("updater.log", std::ios_base::out);
305 fprintf(logfile,"Parsing command arguments\n"); 327 DEBUG("Parsing command arguments");
306 fflush(logfile);
307#endif 328#endif
308 329
309 char *token = NULL; 330 char *token = NULL;
@@ -341,10 +362,7 @@ WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nSho
341 // Process command line arguments 362 // Process command line arguments
342 // 363 //
343 364
344#if _DEBUG 365 DEBUG("Processing command arguments");
345 fprintf(logfile,"Processing command arguments\n");
346 fflush(logfile);
347#endif
348 366
349 // 367 //
350 // Parse the command line arguments 368 // Parse the command line arguments
@@ -362,8 +380,7 @@ WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nSho
362 } 380 }
363 381
364 WNDCLASSEX wndclassex = { 0 }; 382 WNDCLASSEX wndclassex = { 0 };
365 DEVMODE dev_mode = { 0 }; 383 //DEVMODE dev_mode = { 0 };
366 char update_exec_path[MAX_PATH]; /* Flawfinder: ignore */
367 384
368 const int WINDOW_WIDTH = 250; 385 const int WINDOW_WIDTH = 250;
369 const int WINDOW_HEIGHT = 100; 386 const int WINDOW_HEIGHT = 100;
@@ -381,7 +398,7 @@ WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nSho
381 RegisterClassEx(&wndclassex); 398 RegisterClassEx(&wndclassex);
382 399
383 // Get the size of the screen 400 // Get the size of the screen
384 EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev_mode); 401 //EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev_mode);
385 402
386 gWindow = CreateWindowEx(NULL, win_class_name, 403 gWindow = CreateWindowEx(NULL, win_class_name,
387 L"Second Life Updater", 404 L"Second Life Updater",
@@ -412,26 +429,34 @@ WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nSho
412 } 429 }
413 430
414 // Can't feed GetTempPath into GetTempFile directly 431 // Can't feed GetTempPath into GetTempFile directly
415 if (0 == GetTempPathA(MAX_PATH - 14, update_exec_path)) 432 char temp_path[MAX_PATH]; /* Flawfinder: ignore */
433 if (0 == GetTempPathA(sizeof(temp_path), temp_path))
416 { 434 {
417 MessageBox(gWindow, L"Problem with GetTempPath()", 435 MessageBox(gWindow, L"Problem with GetTempPath()",
418 L"Error", MB_OK); 436 L"Error", MB_OK);
419 return 1; 437 return 1;
420 } 438 }
421 strcat(update_exec_path, "Second_Life_Updater.exe"); 439 std::string update_exec_path(temp_path);
440 update_exec_path.append("Second_Life_Updater.exe");
422 441
423 WCHAR update_uri[4096]; 442 WCHAR update_uri[4096];
424 mbstowcs(update_uri, gUpdateURL, 4096); 443 mbstowcs(update_uri, gUpdateURL, sizeof(update_uri));
425 444
426 int success = 0; 445 int success = 0;
427 int cancelled = 0; 446 int cancelled = 0;
428 447
429 // Actually do the download 448 // Actually do the download
430#if _DEBUG 449 try
431 fprintf(logfile,"Calling get_url_into_file\n"); 450 {
432 fflush(logfile); 451 DEBUG("Calling get_url_into_file");
433#endif 452 success = get_url_into_file(update_uri, update_exec_path, &cancelled);
434 success = get_url_into_file(update_uri, update_exec_path, &cancelled); 453 }
454 catch (const Fetcher::InetError& e)
455 {
456 (void)e;
457 success = FALSE;
458 DEBUG("Caught: " << e.what());
459 }
435 460
436 // WinInet can't tell us if we got a 404 or not. Therefor, we check 461 // WinInet can't tell us if we got a 404 or not. Therefor, we check
437 // for the size of the downloaded file, and assume that our installer 462 // for the size of the downloaded file, and assume that our installer
@@ -471,10 +496,31 @@ WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nSho
471 // L"Download Complete", 496 // L"Download Complete",
472 // MB_OK); 497 // MB_OK);
473 498
474 if (32 >= (int) ShellExecuteA(gWindow, "open", update_exec_path, NULL, 499/*==========================================================================*|
500 // DEV-31680: ShellExecuteA() causes McAfee-GW-Edition and AntiVir
501 // scanners to flag this executable as a probable virus vector.
502 // Less than or equal to 32 means failure
503 if (32 >= (int) ShellExecuteA(gWindow, "open", update_exec_path.c_str(), NULL,
475 "C:\\", SW_SHOWDEFAULT)) 504 "C:\\", SW_SHOWDEFAULT))
505|*==========================================================================*/
506 // from http://msdn.microsoft.com/en-us/library/ms682512(VS.85).aspx
507 STARTUPINFOA si;
508 PROCESS_INFORMATION pi;
509 ZeroMemory(&si, sizeof(si));
510 si.cb = sizeof(si);
511 ZeroMemory(&pi, sizeof(pi));
512
513 if (! CreateProcessA(update_exec_path.c_str(), // executable file
514 NULL, // command line
515 NULL, // process cannot be inherited
516 NULL, // thread cannot be inherited
517 FALSE, // do not inherit existing handles
518 0, // process creation flags
519 NULL, // inherit parent's environment
520 NULL, // inherit parent's current dir
521 &si, // STARTUPINFO
522 &pi)) // PROCESS_INFORMATION
476 { 523 {
477 // Less than or equal to 32 means failure
478 MessageBox(gWindow, L"Update failed. Please try again later.", NULL, MB_OK); 524 MessageBox(gWindow, L"Update failed. Please try again later.", NULL, MB_OK);
479 return 1; 525 return 1;
480 } 526 }