diff options
author | Jacek Antonelli | 2009-05-24 02:59:02 -0500 |
---|---|---|
committer | Jacek Antonelli | 2009-05-24 02:59:08 -0500 |
commit | 811454f47ea1f3c5cb8971f0fed0959b18bd0747 (patch) | |
tree | 1b8689df2dc8857cdc5a956a5233d5bf94b5c8d7 /linden/indra/win_updater | |
parent | Second Life viewer sources 1.23.0-RC (diff) | |
download | meta-impy-811454f47ea1f3c5cb8971f0fed0959b18bd0747.zip meta-impy-811454f47ea1f3c5cb8971f0fed0959b18bd0747.tar.gz meta-impy-811454f47ea1f3c5cb8971f0fed0959b18bd0747.tar.bz2 meta-impy-811454f47ea1f3c5cb8971f0fed0959b18bd0747.tar.xz |
Second Life viewer sources 1.23.1-RC
Diffstat (limited to 'linden/indra/win_updater')
-rw-r--r-- | linden/indra/win_updater/updater.cpp | 273 |
1 files changed, 157 insertions, 116 deletions
diff --git a/linden/indra/win_updater/updater.cpp b/linden/indra/win_updater/updater.cpp index e7adaf3..3937351 100644 --- a/linden/indra/win_updater/updater.cpp +++ b/linden/indra/win_updater/updater.cpp | |||
@@ -42,6 +42,11 @@ | |||
42 | #include <windows.h> | 42 | #include <windows.h> |
43 | #include <wininet.h> | 43 | #include <wininet.h> |
44 | #include <stdio.h> | 44 | #include <stdio.h> |
45 | #include <string> | ||
46 | #include <iostream> | ||
47 | #include <stdexcept> | ||
48 | #include <sstream> | ||
49 | #include <fstream> | ||
45 | 50 | ||
46 | #define BUFSIZE 8192 | 51 | #define BUFSIZE 8192 |
47 | 52 | ||
@@ -52,13 +57,16 @@ WCHAR gProgress[256]; | |||
52 | char* gUpdateURL = NULL; | 57 | char* gUpdateURL = NULL; |
53 | 58 | ||
54 | #if _DEBUG | 59 | #if _DEBUG |
55 | FILE* logfile = 0; | 60 | std::ofstream logfile; |
61 | #define DEBUG(expr) logfile << expr << std::endl | ||
62 | #else | ||
63 | #define DEBUG(expr) /**/ | ||
56 | #endif | 64 | #endif |
57 | 65 | ||
58 | char* wchars_to_utf8chars(WCHAR* in_chars) | 66 | char* wchars_to_utf8chars(const WCHAR* in_chars) |
59 | { | 67 | { |
60 | int tlen = 0; | 68 | int tlen = 0; |
61 | WCHAR* twc = in_chars; | 69 | const WCHAR* twc = in_chars; |
62 | while (*twc++ != 0) | 70 | while (*twc++ != 0) |
63 | { | 71 | { |
64 | tlen++; | 72 | tlen++; |
@@ -81,103 +89,128 @@ char* wchars_to_utf8chars(WCHAR* in_chars) | |||
81 | return res; | 89 | return res; |
82 | } | 90 | } |
83 | 91 | ||
84 | int WINAPI get_url_into_file(WCHAR *uri, char *path, int *cancelled) | 92 | class Fetcher |
93 | { | ||
94 | public: | ||
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 | |||
127 | private: | ||
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 | |||
152 | HINTERNET 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 | |||
160 | HINTERNET 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 | |||
167 | unsigned 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 | |||
176 | int WINAPI get_url_into_file(const std::wstring& uri, const std::string& path, int *cancelled) | ||
85 | { | 177 | { |
86 | int success = FALSE; | 178 | int success = FALSE; |
87 | *cancelled = FALSE; | 179 | *cancelled = FALSE; |
88 | 180 | ||
89 | HINTERNET hinet, hdownload; | 181 | DEBUG("Opening '" << path << "'"); |
90 | char data[BUFSIZE]; /* Flawfinder: ignore */ | ||
91 | unsigned long bytes_read; | ||
92 | |||
93 | #if _DEBUG | ||
94 | fprintf(logfile,"Opening '%s'\n",path); | ||
95 | fflush(logfile); | ||
96 | #endif | ||
97 | 182 | ||
98 | FILE* fp = fopen(path, "wb"); /* Flawfinder: ignore */ | 183 | FILE* fp = fopen(path.c_str(), "wb"); /* Flawfinder: ignore */ |
99 | 184 | ||
100 | if (!fp) | 185 | if (!fp) |
101 | { | 186 | { |
102 | #if _DEBUG | 187 | DEBUG("Failed to open '" << path << "'"); |
103 | fprintf(logfile,"Failed to open '%s'\n",path); | ||
104 | fflush(logfile); | ||
105 | #endif | ||
106 | return success; | ||
107 | } | ||
108 | |||
109 | #if _DEBUG | ||
110 | fprintf(logfile,"Calling InternetOpen\n"); | ||
111 | fflush(logfile); | ||
112 | #endif | ||
113 | // Init wininet subsystem | ||
114 | hinet = InternetOpen(L"LindenUpdater", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0); | ||
115 | if (hinet == NULL) | ||
116 | { | ||
117 | return success; | 188 | return success; |
118 | } | 189 | } |
119 | 190 | ||
120 | #if _DEBUG | 191 | // Note, ctor can throw, since it uses check() function. |
121 | fprintf(logfile,"Calling InternetOpenUrl: %s\n",wchars_to_utf8chars(uri)); | 192 | Fetcher fetcher(uri); |
122 | fflush(logfile); | 193 | gTotalBytes = fetcher.getTotalBytes(); |
123 | #endif | ||
124 | hdownload = InternetOpenUrl(hinet, uri, NULL, 0, INTERNET_FLAG_NEED_FILE, NULL); | ||
125 | if (hdownload == NULL) | ||
126 | { | ||
127 | #if _DEBUG | ||
128 | DWORD err = GetLastError(); | ||
129 | fprintf(logfile,"InternetOpenUrl Failed: %d\n",err); | ||
130 | fflush(logfile); | ||
131 | #endif | ||
132 | return success; | ||
133 | } | ||
134 | 194 | ||
135 | DWORD sizeof_total_bytes = sizeof(gTotalBytes); | 195 | /*==========================================================================*| |
136 | 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? |
137 | |||
138 | DWORD total_bytes = 0; | 197 | DWORD total_bytes = 0; |
139 | success = InternetQueryDataAvailable(hdownload, &total_bytes, 0, 0); | 198 | success = check("InternetQueryDataAvailable", |
140 | if (success == FALSE) | 199 | InternetQueryDataAvailable(hdownload, &total_bytes, 0, 0)); |
141 | { | 200 | |*==========================================================================*/ |
142 | #if _DEBUG | ||
143 | DWORD err = GetLastError(); | ||
144 | fprintf(logfile,"InternetQueryDataAvailable Failed: %d bytes Err:%d\n",total_bytes,err); | ||
145 | fflush(logfile); | ||
146 | #endif | ||
147 | return success; | ||
148 | } | ||
149 | 201 | ||
150 | success = FALSE; | 202 | success = FALSE; |
151 | while(!success && !(*cancelled)) | 203 | while(!success && !(*cancelled)) |
152 | { | 204 | { |
153 | MSG msg; | 205 | char data[BUFSIZE]; /* Flawfinder: ignore */ |
154 | 206 | unsigned long bytes_read = fetcher.read(data, sizeof(data)); | |
155 | #if _DEBUG | ||
156 | fprintf(logfile,"Calling InternetReadFile\n"); | ||
157 | fflush(logfile); | ||
158 | #endif | ||
159 | if (!InternetReadFile(hdownload, data, BUFSIZE, &bytes_read)) | ||
160 | { | ||
161 | #if _DEBUG | ||
162 | fprintf(logfile,"InternetReadFile Failed.\n"); | ||
163 | fflush(logfile); | ||
164 | #endif | ||
165 | // ...an error occurred | ||
166 | return FALSE; | ||
167 | } | ||
168 | 207 | ||
169 | #if _DEBUG | ||
170 | if (!bytes_read) | 208 | if (!bytes_read) |
171 | { | 209 | { |
172 | fprintf(logfile,"InternetReadFile Read 0 bytes.\n"); | 210 | DEBUG("InternetReadFile Read " << bytes_read << " bytes."); |
173 | fflush(logfile); | ||
174 | } | 211 | } |
175 | #endif | ||
176 | 212 | ||
177 | #if _DEBUG | 213 | DEBUG("Reading Data, bytes_read = " << bytes_read); |
178 | fprintf(logfile,"Reading Data, bytes_read = %d\n",bytes_read); | ||
179 | fflush(logfile); | ||
180 | #endif | ||
181 | 214 | ||
182 | if (bytes_read == 0) | 215 | if (bytes_read == 0) |
183 | { | 216 | { |
@@ -200,25 +233,17 @@ int WINAPI get_url_into_file(WCHAR *uri, char *path, int *cancelled) | |||
200 | 233 | ||
201 | } | 234 | } |
202 | 235 | ||
203 | #if _DEBUG | 236 | DEBUG("Calling InvalidateRect"); |
204 | fprintf(logfile,"Calling InvalidateRect\n"); | ||
205 | fflush(logfile); | ||
206 | #endif | ||
207 | 237 | ||
208 | // Mark the window as needing redraw (of the whole thing) | 238 | // Mark the window as needing redraw (of the whole thing) |
209 | InvalidateRect(gWindow, NULL, TRUE); | 239 | InvalidateRect(gWindow, NULL, TRUE); |
210 | 240 | ||
211 | // Do the redraw | 241 | // Do the redraw |
212 | #if _DEBUG | 242 | DEBUG("Calling UpdateWindow"); |
213 | fprintf(logfile,"Calling UpdateWindow\n"); | ||
214 | fflush(logfile); | ||
215 | #endif | ||
216 | UpdateWindow(gWindow); | 243 | UpdateWindow(gWindow); |
217 | 244 | ||
218 | #if _DEBUG | 245 | DEBUG("Calling PeekMessage"); |
219 | fprintf(logfile,"Calling PeekMessage\n"); | 246 | MSG msg; |
220 | fflush(logfile); | ||
221 | #endif | ||
222 | while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) | 247 | while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) |
223 | { | 248 | { |
224 | TranslateMessage(&msg); | 249 | TranslateMessage(&msg); |
@@ -232,15 +257,7 @@ int WINAPI get_url_into_file(WCHAR *uri, char *path, int *cancelled) | |||
232 | } | 257 | } |
233 | } | 258 | } |
234 | 259 | ||
235 | #if _DEBUG | ||
236 | fprintf(logfile,"Calling InternetCloseHandle\n"); | ||
237 | fclose(logfile); | ||
238 | #endif | ||
239 | |||
240 | fclose(fp); | 260 | fclose(fp); |
241 | InternetCloseHandle(hdownload); | ||
242 | InternetCloseHandle(hinet); | ||
243 | |||
244 | return success; | 261 | return success; |
245 | } | 262 | } |
246 | 263 | ||
@@ -306,9 +323,8 @@ WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nSho | |||
306 | char* argv[MAX_ARGS]; /* Flawfinder: ignore */ | 323 | char* argv[MAX_ARGS]; /* Flawfinder: ignore */ |
307 | 324 | ||
308 | #if _DEBUG | 325 | #if _DEBUG |
309 | logfile = _wfopen(TEXT("updater.log"),TEXT("wt")); | 326 | logfile.open("updater.log", std::ios_base::out); |
310 | fprintf(logfile,"Parsing command arguments\n"); | 327 | DEBUG("Parsing command arguments"); |
311 | fflush(logfile); | ||
312 | #endif | 328 | #endif |
313 | 329 | ||
314 | char *token = NULL; | 330 | char *token = NULL; |
@@ -346,10 +362,7 @@ WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nSho | |||
346 | // Process command line arguments | 362 | // Process command line arguments |
347 | // | 363 | // |
348 | 364 | ||
349 | #if _DEBUG | 365 | DEBUG("Processing command arguments"); |
350 | fprintf(logfile,"Processing command arguments\n"); | ||
351 | fflush(logfile); | ||
352 | #endif | ||
353 | 366 | ||
354 | // | 367 | // |
355 | // Parse the command line arguments | 368 | // Parse the command line arguments |
@@ -358,7 +371,6 @@ WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nSho | |||
358 | 371 | ||
359 | WNDCLASSEX wndclassex = { 0 }; | 372 | WNDCLASSEX wndclassex = { 0 }; |
360 | //DEVMODE dev_mode = { 0 }; | 373 | //DEVMODE dev_mode = { 0 }; |
361 | char update_exec_path[MAX_PATH]; /* Flawfinder: ignore */ | ||
362 | 374 | ||
363 | const int WINDOW_WIDTH = 250; | 375 | const int WINDOW_WIDTH = 250; |
364 | const int WINDOW_HEIGHT = 100; | 376 | const int WINDOW_HEIGHT = 100; |
@@ -407,26 +419,34 @@ WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nSho | |||
407 | } | 419 | } |
408 | 420 | ||
409 | // Can't feed GetTempPath into GetTempFile directly | 421 | // Can't feed GetTempPath into GetTempFile directly |
410 | if (0 == GetTempPathA(MAX_PATH - 14, update_exec_path)) | 422 | char temp_path[MAX_PATH]; /* Flawfinder: ignore */ |
423 | if (0 == GetTempPathA(sizeof(temp_path), temp_path)) | ||
411 | { | 424 | { |
412 | MessageBox(gWindow, L"Problem with GetTempPath()", | 425 | MessageBox(gWindow, L"Problem with GetTempPath()", |
413 | L"Error", MB_OK); | 426 | L"Error", MB_OK); |
414 | return 1; | 427 | return 1; |
415 | } | 428 | } |
416 | strcat(update_exec_path, "Second_Life_Updater.exe"); | 429 | std::string update_exec_path(temp_path); |
430 | update_exec_path.append("Second_Life_Updater.exe"); | ||
417 | 431 | ||
418 | WCHAR update_uri[4096]; | 432 | WCHAR update_uri[4096]; |
419 | mbstowcs(update_uri, gUpdateURL, 4096); | 433 | mbstowcs(update_uri, gUpdateURL, sizeof(update_uri)); |
420 | 434 | ||
421 | int success = 0; | 435 | int success = 0; |
422 | int cancelled = 0; | 436 | int cancelled = 0; |
423 | 437 | ||
424 | // Actually do the download | 438 | // Actually do the download |
425 | #if _DEBUG | 439 | try |
426 | fprintf(logfile,"Calling get_url_into_file\n"); | 440 | { |
427 | fflush(logfile); | 441 | DEBUG("Calling get_url_into_file"); |
428 | #endif | 442 | success = get_url_into_file(update_uri, update_exec_path, &cancelled); |
429 | success = get_url_into_file(update_uri, update_exec_path, &cancelled); | 443 | } |
444 | catch (const Fetcher::InetError& e) | ||
445 | { | ||
446 | (void)e; | ||
447 | success = FALSE; | ||
448 | DEBUG("Caught: " << e.what()); | ||
449 | } | ||
430 | 450 | ||
431 | // WinInet can't tell us if we got a 404 or not. Therefor, we check | 451 | // WinInet can't tell us if we got a 404 or not. Therefor, we check |
432 | // for the size of the downloaded file, and assume that our installer | 452 | // for the size of the downloaded file, and assume that our installer |
@@ -466,10 +486,31 @@ WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nSho | |||
466 | // L"Download Complete", | 486 | // L"Download Complete", |
467 | // MB_OK); | 487 | // MB_OK); |
468 | 488 | ||
469 | if (32 >= (int) ShellExecuteA(gWindow, "open", update_exec_path, NULL, | 489 | /*==========================================================================*| |
490 | // DEV-31680: ShellExecuteA() causes McAfee-GW-Edition and AntiVir | ||
491 | // scanners to flag this executable as a probable virus vector. | ||
492 | // Less than or equal to 32 means failure | ||
493 | if (32 >= (int) ShellExecuteA(gWindow, "open", update_exec_path.c_str(), NULL, | ||
470 | "C:\\", SW_SHOWDEFAULT)) | 494 | "C:\\", SW_SHOWDEFAULT)) |
495 | |*==========================================================================*/ | ||
496 | // from http://msdn.microsoft.com/en-us/library/ms682512(VS.85).aspx | ||
497 | STARTUPINFOA si; | ||
498 | PROCESS_INFORMATION pi; | ||
499 | ZeroMemory(&si, sizeof(si)); | ||
500 | si.cb = sizeof(si); | ||
501 | ZeroMemory(&pi, sizeof(pi)); | ||
502 | |||
503 | if (! CreateProcessA(update_exec_path.c_str(), // executable file | ||
504 | NULL, // command line | ||
505 | NULL, // process cannot be inherited | ||
506 | NULL, // thread cannot be inherited | ||
507 | FALSE, // do not inherit existing handles | ||
508 | 0, // process creation flags | ||
509 | NULL, // inherit parent's environment | ||
510 | NULL, // inherit parent's current dir | ||
511 | &si, // STARTUPINFO | ||
512 | &pi)) // PROCESS_INFORMATION | ||
471 | { | 513 | { |
472 | // Less than or equal to 32 means failure | ||
473 | MessageBox(gWindow, L"Update failed. Please try again later.", NULL, MB_OK); | 514 | MessageBox(gWindow, L"Update failed. Please try again later.", NULL, MB_OK); |
474 | return 1; | 515 | return 1; |
475 | } | 516 | } |