Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(41)

Side by Side Diff: base/utils.cc

Issue 624713003: Keep only base/extractor.[cc|h]. (Closed) Base URL: https://chromium.googlesource.com/external/omaha.git@master
Patch Set: Created 6 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « base/utils.h ('k') | base/utils_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2003-2010 Google Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 // ========================================================================
15
16 #include "omaha/base/utils.h"
17
18 #include <ras.h>
19 #include <regstr.h>
20 #include <urlmon.h>
21 #include <wincrypt.h>
22 #include <ATLComTime.h>
23 #include <atlpath.h>
24 #include <map>
25 #include <vector>
26 #include "base/basictypes.h"
27 #include "base/scoped_ptr.h"
28 #include "omaha/base/app_util.h"
29 #include "omaha/base/const_addresses.h"
30 #include "omaha/base/const_config.h"
31 #include "omaha/base/const_timeouts.h"
32 #include "omaha/base/const_object_names.h"
33 #include "omaha/base/debug.h"
34 #include "omaha/base/error.h"
35 #include "omaha/base/file.h"
36 #include "omaha/base/logging.h"
37 #include "omaha/base/process.h"
38 #include "omaha/base/reg_key.h"
39 #include "omaha/base/safe_format.h"
40 #include "omaha/base/scope_guard.h"
41 #include "omaha/base/shell.h"
42 #include "omaha/base/scoped_any.h"
43 #include "omaha/base/string.h"
44 #include "omaha/base/system.h"
45 #include "omaha/base/system_info.h"
46 #include "omaha/base/time.h"
47 #include "omaha/base/user_info.h"
48 #include "omaha/base/user_rights.h"
49 #include "omaha/base/vistautil.h"
50
51 namespace omaha {
52
53 namespace {
54
55 // Private object namespaces for Vista processes.
56 const TCHAR* const kGoopdateBoundaryDescriptor = _T("GoogleUpdate_BD");
57 const TCHAR* const kGoopdatePrivateNamespace = _T("GoogleUpdate");
58 const TCHAR* const kGoopdatePrivateNamespacePrefix = _T("GoogleUpdate\\");
59
60 // Helper for IsPrivateNamespaceAvailable().
61 // For simplicity, the handles opened here are leaked. We need these until
62 // process exit, at which point they will be cleaned up automatically by the OS.
63 bool EnsurePrivateNamespaceAvailable() {
64 HANDLE boundary_descriptor =
65 CreateBoundaryDescriptorWWrap(kGoopdateBoundaryDescriptor, 0);
66 if (NULL == boundary_descriptor) {
67 DWORD last_error(::GetLastError());
68 UTIL_LOG(LE, (_T("CreateBoundaryDescriptor failed[%d]"), last_error));
69 return false;
70 }
71
72 char sid[SECURITY_MAX_SID_SIZE] = {0};
73 DWORD size = sizeof(sid);
74 // Mark the boundary descriptor with the Admins Group SID. Consequently, all
75 // admins, including SYSTEM, will create objects in the same private
76 // namespace.
77 if (!::CreateWellKnownSid(WinBuiltinAdministratorsSid, NULL, sid, &size)) {
78 UTIL_LOG(LE, (_T("[::CreateWellKnownSid failed][%d]"), ::GetLastError()));
79 return false;
80 }
81 if (!AddSIDToBoundaryDescriptorWrap(&boundary_descriptor, sid)) {
82 UTIL_LOG(LE, (_T("[AddSIDToBoundaryDescriptor failed][%d]"),
83 ::GetLastError()));
84 return false;
85 }
86
87 NamedObjectAttributes attr;
88 GetAdminDaclSecurityAttributes(&attr.sa, GENERIC_ALL);
89 // The private namespace created here will be used to create objects of the
90 // form "GoogleUpdate\xyz". As the article "Object Namespaces" on MSDN
91 // explains, these kernel objects are safe from squatting attacks from lower
92 // integrity processes.
93 HANDLE namespace_handle =
94 CreatePrivateNamespaceWWrap(&attr.sa,
95 boundary_descriptor,
96 kGoopdatePrivateNamespace);
97 if (namespace_handle) {
98 return true;
99 }
100 ASSERT(ERROR_ALREADY_EXISTS == ::GetLastError(),
101 (_T("CreatePrivateNamespaceW failed: %d"), ::GetLastError()));
102
103 // Another process has already created the namespace. Attempt to open.
104 namespace_handle = OpenPrivateNamespaceWWrap(boundary_descriptor,
105 kGoopdatePrivateNamespace);
106 if (namespace_handle || ::GetLastError() == ERROR_DUP_NAME) {
107 // ERROR_DUP_NAME indicates that we have called CreatePrivateNamespaceWWrap
108 // or OpenPrivateNamespaceWWrap before in the same process. Either way, we
109 // can now create objects prefixed with our private namespace.
110 return true;
111 }
112
113 ASSERT(namespace_handle, (_T("[Could not open private namespace][%d]"),
114 ::GetLastError()));
115 return false;
116 }
117
118 } // namespace
119
120 // Returns 0 if an error occurs.
121 ULONGLONG VersionFromString(const CString& s) {
122 int pos(0);
123 unsigned int quad[4] = {0, 0, 0, 0};
124
125 for (int i = 0; i < 4; ++i) {
126 CString q = s.Tokenize(_T("."), pos);
127 if (pos == -1) {
128 return 0;
129 }
130
131 int quad_value(0);
132 if (!String_StringToDecimalIntChecked(q, &quad_value)) {
133 return 0;
134 }
135
136 quad[i] = static_cast<unsigned int>(quad_value);
137
138 if (kuint16max < quad[i]) {
139 return 0;
140 }
141 }
142
143 if (s.GetLength() + 1 != pos) {
144 return 0;
145 }
146
147 return MAKEDLLVERULL(quad[0], quad[1], quad[2], quad[3]);
148 }
149
150 CString StringFromVersion(ULONGLONG version) {
151 const WORD version_major = HIWORD(version >> 32);
152 const WORD version_minor = LOWORD(version >> 32);
153 const WORD version_build = HIWORD(version);
154 const WORD version_patch = LOWORD(version);
155
156 CString version_string;
157 version_string.Format((_T("%u.%u.%u.%u")),
158 version_major,
159 version_minor,
160 version_build,
161 version_patch);
162 return version_string;
163 }
164
165 CString GetCurrentDir() {
166 TCHAR cur_dir[MAX_PATH] = {0};
167 if (!::GetCurrentDirectory(MAX_PATH, cur_dir)) {
168 return CString(_T('.'));
169 }
170 return CString(cur_dir);
171 }
172
173 HRESULT GetNewFileNameInDirectory(const CString& dir, CString* file_name) {
174 ASSERT1(file_name);
175
176 GUID guid = {0};
177 HRESULT hr = ::CoCreateGuid(&guid);
178 if (FAILED(hr)) {
179 CORE_LOG(LEVEL_WARNING, (_T("[CoCreateGuid failed][0x%08x]"), hr));
180 return hr;
181 }
182
183 CString guid_file_name = GuidToString(guid);
184 CPath file_path(dir);
185 file_path.Append(guid_file_name);
186
187 *file_name = static_cast<const TCHAR*>(file_path);
188 return S_OK;
189 }
190
191 // determines if a time is in the distant past, present, or future
192 TimeCategory GetTimeCategory(const time64 system_time) {
193 time64 now = GetCurrent100NSTime();
194
195 // Times more than a few days in the future are wrong [I will allow a little
196 // leeway, since it could be set in another future time zone, or a program
197 // that likes UNC]]
198 if (system_time > (now + kDaysTo100ns * 5)) {
199 return FUTURE;
200 }
201
202 // times more than 40 years ago are wrong
203 if (system_time < (now - kDaysTo100ns * 365 * 40)) {
204 return PAST;
205 }
206
207 return PRESENT;
208 }
209
210 // Determine if a given time is probably valid
211 bool IsValidTime(const time64 t) {
212 return (GetTimeCategory(t) == PRESENT);
213 }
214
215 LARGE_INTEGER MSto100NSRelative(DWORD ms) {
216 const __int64 convert_ms_to_100ns_units = 1000 /*ms/us*/ * 10 /*us/100ns*/;
217 __int64 timeout_100ns = static_cast<__int64>(ms) * convert_ms_to_100ns_units;
218 LARGE_INTEGER timeout = {0};
219 timeout.QuadPart = -timeout_100ns;
220 return timeout;
221 }
222
223 // Local System and admins get admin_access_mask. Authenticated non-admins get
224 // non_admin_access_mask access.
225 void GetEveryoneDaclSecurityDescriptor(CSecurityDesc* sd,
226 ACCESS_MASK admin_access_mask,
227 ACCESS_MASK non_admin_access_mask) {
228 ASSERT1(sd);
229
230 CDacl dacl;
231 dacl.AddAllowedAce(Sids::System(), admin_access_mask);
232 dacl.AddAllowedAce(Sids::Admins(), admin_access_mask);
233 dacl.AddAllowedAce(Sids::Interactive(), non_admin_access_mask);
234
235 sd->SetDacl(dacl);
236 sd->MakeAbsolute();
237 }
238
239 void GetAdminDaclSecurityDescriptor(CSecurityDesc* sd, ACCESS_MASK accessmask) {
240 ASSERT1(sd);
241
242 CDacl dacl;
243 dacl.AddAllowedAce(Sids::System(), accessmask);
244 dacl.AddAllowedAce(Sids::Admins(), accessmask);
245
246 sd->SetOwner(Sids::Admins());
247 sd->SetGroup(Sids::Admins());
248 sd->SetDacl(dacl);
249 sd->MakeAbsolute();
250 }
251
252 void GetAdminDaclSecurityAttributes(CSecurityAttributes* sec_attr,
253 ACCESS_MASK accessmask) {
254 ASSERT1(sec_attr);
255 CSecurityDesc sd;
256 GetAdminDaclSecurityDescriptor(&sd, accessmask);
257 sec_attr->Set(sd);
258 }
259
260 HRESULT InitializeClientSecurity() {
261 return ::CoInitializeSecurity(
262 NULL,
263 -1,
264 NULL, // Let COM choose what authentication services to register.
265 NULL,
266 RPC_C_AUTHN_LEVEL_PKT_PRIVACY, // Data integrity and encryption.
267 RPC_C_IMP_LEVEL_IMPERSONATE, // Allow server to impersonate.
268 NULL,
269 EOAC_DYNAMIC_CLOAKING,
270 NULL);
271 }
272
273 HRESULT InitializeServerSecurity(bool allow_calls_from_medium) {
274 CSecurityDesc sd;
275 DWORD eole_auth_capabilities = EOAC_DYNAMIC_CLOAKING;
276 if (allow_calls_from_medium) {
277 GetEveryoneDaclSecurityDescriptor(&sd,
278 COM_RIGHTS_EXECUTE,
279 COM_RIGHTS_EXECUTE);
280 sd.SetOwner(Sids::Admins());
281 sd.SetGroup(Sids::Admins());
282 } else if (user_info::IsRunningAsSystem()) {
283 GetAdminDaclSecurityDescriptor(&sd, COM_RIGHTS_EXECUTE);
284 }
285
286 HRESULT hr = ::CoInitializeSecurity(
287 const_cast<SECURITY_DESCRIPTOR*>(sd.GetPSECURITY_DESCRIPTOR()),
288 -1,
289 NULL,
290 NULL,
291 RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
292 RPC_C_IMP_LEVEL_IDENTIFY,
293 NULL,
294 eole_auth_capabilities,
295 NULL);
296 ASSERT(SUCCEEDED(hr), (_T("[InitializeServerSecurity failed][0x%x]"), hr));
297 return hr;
298 }
299
300 // The IGlobalOptions interface is supported from Vista onwards. Callers
301 // should probably ignore the HRESULT returned, since it is not a critical error
302 // if turning off exception handling fails.
303 HRESULT DisableCOMExceptionHandling() {
304 CComPtr<IGlobalOptions> options;
305 HRESULT hr = options.CoCreateInstance(CLSID_GlobalOptions);
306 if (SUCCEEDED(hr)) {
307 hr = options->Set(COMGLB_EXCEPTION_HANDLING, COMGLB_EXCEPTION_DONOT_HANDLE);
308 }
309
310 if (FAILED(hr)) {
311 UTIL_LOG(LE, (_T("[DisableCOMExceptionHandling failed][0x%x]"), hr));
312 }
313
314 return hr;
315 }
316
317 // This function is not thread-safe.
318 bool IsPrivateNamespaceAvailable(bool is_machine) {
319 static bool is_initialized = false;
320 static bool is_available = false;
321
322 if (!is_machine) {
323 // TODO(Omaha): From a security viewpoint, private namespaces do not add
324 // much value for the User Omaha. But from a uniformity perspective, makes
325 // sense to use for both.
326 return false;
327 }
328
329 if (is_initialized) {
330 return is_available;
331 }
332
333 if (!SystemInfo::IsRunningOnVistaOrLater()) {
334 is_available = false;
335 is_initialized = true;
336 return false;
337 }
338
339 is_available = EnsurePrivateNamespaceAvailable();
340 is_initialized = true;
341 return is_available;
342 }
343
344
345 void GetNamedObjectAttributes(const TCHAR* base_name,
346 bool is_machine,
347 NamedObjectAttributes* attr) {
348 ASSERT1(base_name);
349 ASSERT1(attr);
350
351 // TODO(Omaha): Enable this code after we have a better understanding of
352 // Private Object Namespaces.
353 #if 0
354 if (IsPrivateNamespaceAvailable(is_machine)) {
355 attr->name = kGoopdatePrivateNamespacePrefix;
356 } else {
357 ASSERT1(!SystemInfo::IsRunningOnVistaOrLater());
358 #endif
359
360 attr->name = omaha::kGlobalPrefix;
361
362 if (!is_machine) {
363 CString user_sid;
364 VERIFY1(SUCCEEDED(omaha::user_info::GetProcessUser(NULL, NULL, &user_sid)));
365 attr->name += user_sid;
366 } else {
367 // Grant access to administrators and system.
368 GetAdminDaclSecurityAttributes(&attr->sa, GENERIC_ALL);
369 }
370
371 attr->name += base_name;
372 UTIL_LOG(L1, (_T("[GetNamedObjectAttributes][named_object=%s]"), attr->name));
373 }
374
375 // For now, required_ace_flags is only supported for SE_REGISTRY_KEY objects.
376 // INHERITED_ACE may be added to the read ACE flags, so it is excluded from
377 // the comparison with required_ace_flags.
378 HRESULT AddAllowedAce(const TCHAR* object_name,
379 SE_OBJECT_TYPE object_type,
380 const CSid& sid,
381 ACCESS_MASK required_permissions,
382 uint8 required_ace_flags) {
383 ASSERT1(SE_REGISTRY_KEY == object_type || !required_ace_flags);
384 ASSERT1(0 == (required_ace_flags & INHERITED_ACE));
385
386 CDacl dacl;
387 if (!AtlGetDacl(object_name, object_type, &dacl)) {
388 return HRESULTFromLastError();
389 }
390
391 int ace_count = dacl.GetAceCount();
392 for (int i = 0; i < ace_count; ++i) {
393 CSid sid_entry;
394 ACCESS_MASK existing_permissions = 0;
395 BYTE existing_ace_flags = 0;
396 dacl.GetAclEntry(i,
397 &sid_entry,
398 &existing_permissions,
399 NULL,
400 &existing_ace_flags);
401 if (sid_entry == sid &&
402 required_permissions == (existing_permissions & required_permissions) &&
403 required_ace_flags == (existing_ace_flags & ~INHERITED_ACE)) {
404 return S_OK;
405 }
406 }
407
408 if (!dacl.AddAllowedAce(sid, required_permissions, required_ace_flags) ||
409 !AtlSetDacl(object_name, object_type, dacl)) {
410 return HRESULTFromLastError();
411 }
412
413 return S_OK;
414 }
415
416 HRESULT CreateDir(const TCHAR* in_dir,
417 LPSECURITY_ATTRIBUTES security_attr) {
418 ASSERT1(in_dir);
419 CString path;
420 if (!PathCanonicalize(CStrBuf(path, MAX_PATH), in_dir)) {
421 return E_FAIL;
422 }
423 // Standardize path on backslash so Find works.
424 path.Replace(_T('/'), _T('\\'));
425 int next_slash = path.Find(_T('\\'));
426 while (true) {
427 int len = 0;
428 if (next_slash == -1) {
429 len = path.GetLength();
430 } else {
431 len = next_slash;
432 }
433 CString dir(path.Left(len));
434 // The check for File::Exists should not be needed. However in certain
435 // cases, i.e. when the program is run from a n/w drive or from the
436 // root drive location, the first CreateDirectory fails with an
437 // E_ACCESSDENIED instead of a ALREADY_EXISTS. Hence we protect the call
438 // with the exists.
439 if (!File::Exists(dir)) {
440 if (!::CreateDirectory(dir, security_attr)) {
441 DWORD error = ::GetLastError();
442 if (ERROR_FILE_EXISTS != error && ERROR_ALREADY_EXISTS != error) {
443 return HRESULT_FROM_WIN32(error);
444 }
445 }
446 }
447 if (next_slash == -1) {
448 break;
449 }
450 next_slash = path.Find(_T('\\'), next_slash + 1);
451 }
452
453 return S_OK;
454 }
455
456 HRESULT GetFolderPath(int csidl, CString* path) {
457 if (!path) {
458 return E_INVALIDARG;
459 }
460
461 TCHAR buffer[MAX_PATH] = {0};
462 HRESULT hr = ::SHGetFolderPath(NULL, csidl, NULL, SHGFP_TYPE_CURRENT, buffer);
463 if (FAILED(hr)) {
464 return hr;
465 }
466
467 *path = buffer;
468 return S_OK;
469 }
470
471 // Delete directory files. If failed, try to schedule deletion at next reboot
472 HRESULT DeleteDirectoryFiles(const TCHAR* dir_name) {
473 ASSERT1(dir_name);
474 return DeleteWildcardFiles(dir_name, _T("*"));
475 }
476
477 // Delete a set of wildcards within dir_name.
478 // If unable to delete immediately, try to schedule deletion at next reboot
479 HRESULT DeleteWildcardFiles(const TCHAR* dir_name, const TCHAR* wildcard_name) {
480 ASSERT1(dir_name);
481 ASSERT1(wildcard_name);
482
483 HRESULT hr = S_OK;
484
485 WIN32_FIND_DATA find_data;
486 SetZero(find_data);
487
488 CString find_file(dir_name);
489 find_file += _T('\\');
490 find_file += wildcard_name;
491
492 scoped_hfind hfind(::FindFirstFile(find_file, &find_data));
493 if (!hfind) {
494 if (::GetLastError() == ERROR_NO_MORE_FILES) {
495 return S_OK;
496 } else {
497 hr = HRESULTFromLastError();
498 UTIL_LOG(LEVEL_ERROR, (_T("[DeleteWildcardFiles]")
499 _T("[failed to get first file][0x%08x]"), hr));
500 return hr;
501 }
502 }
503
504 do {
505 if (!(find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
506 CString specific_file_name(dir_name);
507 specific_file_name += _T('\\');
508 specific_file_name += find_data.cFileName;
509 if (!::DeleteFile(specific_file_name)) {
510 if (!SUCCEEDED(hr = File::DeleteAfterReboot(specific_file_name))) {
511 UTIL_LOG(LEVEL_ERROR, (_T("[DeleteWildcardFiles]")
512 _T("[failed to delete after reboot]")
513 _T("[%s][0x%08x]"), specific_file_name, hr));
514 }
515 }
516 }
517 } while (::FindNextFile(get(hfind), &find_data));
518
519 if (::GetLastError() != ERROR_NO_MORE_FILES) {
520 hr = HRESULTFromLastError();
521 UTIL_LOG(LEVEL_ERROR, (_T("[DeleteWildcardFiles]")
522 _T("[failed to get next file][0x%08x]"), hr));
523 }
524
525 return hr;
526 }
527
528 // Delete directory and files within. If failed, try to schedule deletion at
529 // next reboot
530 // TODO(Omaha) - the code to delete the directory is complicated,
531 // especially the way the result code is built from hr and hr1. I wonder if we
532 // could simplify this by reimplementing it on top of SHFileOperation and
533 // also save a few tens of bytes in the process.
534 HRESULT DeleteDirectory(const TCHAR* dir_name) {
535 ASSERT1(dir_name);
536
537 if (!SafeDirectoryNameForDeletion(dir_name)) {
538 return E_FAIL;
539 }
540
541 // Make sure the directory exists (it is ok if it doesn't)
542 DWORD dir_attributes = ::GetFileAttributes(dir_name);
543 if (dir_attributes == INVALID_FILE_ATTRIBUTES) {
544 if (::GetLastError() == ERROR_FILE_NOT_FOUND)
545 return S_OK; // Ok if directory is missing
546 else
547 return HRESULTFromLastError();
548 }
549 // Confirm it is a directory
550 if (!(dir_attributes & FILE_ATTRIBUTE_DIRECTORY)) {
551 return E_FAIL;
552 }
553
554 // Try to delete all files at best effort
555 // Return the first HRESULT error encountered
556
557 // First delete all the normal files
558 HRESULT hr = DeleteDirectoryFiles(dir_name);
559
560 // Recursively delete any subdirectories
561
562 WIN32_FIND_DATA find_data = {0};
563
564 CString find_file(dir_name);
565 find_file += _T("\\*");
566
567 // Note that the follows are enclosed in a block because we need to close the
568 // find handle before deleting the directorty itself
569 {
570 scoped_hfind hfind(::FindFirstFile(find_file, &find_data));
571 if (!hfind) {
572 if (::GetLastError() == ERROR_NO_MORE_FILES) {
573 return hr;
574 } else {
575 HRESULT hr1 = HRESULTFromLastError();
576 UTIL_LOG(LEVEL_ERROR, (_T("[DeleteDirectory]")
577 _T("[failed to get first file][0x%08x]"), hr1));
578 return SUCCEEDED(hr) ? hr1 : hr;
579 }
580 }
581
582 do {
583 if (find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
584 if (String_StrNCmp(find_data.cFileName, _T("."), 2, false) == 0 ||
585 String_StrNCmp(find_data.cFileName, _T(".."), 3, false) == 0) {
586 continue;
587 }
588
589 CString sub_dir(dir_name);
590 sub_dir += _T("\\");
591 sub_dir += find_data.cFileName;
592 HRESULT hr1 = DeleteDirectory(sub_dir);
593 if (SUCCEEDED(hr) && FAILED(hr1)) {
594 hr = hr1;
595 }
596 }
597 }
598 while (::FindNextFile(get(hfind), &find_data));
599 }
600
601 // Delete the empty directory itself
602 if (!::RemoveDirectory(dir_name)) {
603 HRESULT hr1 = E_FAIL;
604 if (FAILED(hr1 = File::DeleteAfterReboot(dir_name))) {
605 UTIL_LOG(LE, (_T("[DeleteDirectory][failed to delete after reboot]")
606 _T("[%s][0x%08x]"), dir_name, hr1));
607 }
608
609 if (SUCCEEDED(hr) && FAILED(hr1)) {
610 hr = hr1;
611 }
612 }
613
614 return hr;
615 }
616
617 // Returns true if this directory name is 'safe' for deletion (doesn't contain
618 // "..", doesn't specify a drive root)
619 bool SafeDirectoryNameForDeletion(const TCHAR* dir_name) {
620 ASSERT1(dir_name);
621
622 // empty name isn't allowed
623 if (!(dir_name && *dir_name)) {
624 return false;
625 }
626
627 // require a character other than \/:. after the last :
628 // disallow anything with ".."
629 bool ok = false;
630 for (const TCHAR* s = dir_name; *s; ++s) {
631 if (*s != _T('\\') && *s != _T('/') && *s != _T(':') && *s != _T('.')) {
632 ok = true;
633 }
634 if (*s == _T('.') && s > dir_name && *(s-1) == _T('.')) {
635 return false;
636 }
637 if (*s == _T(':')) {
638 ok = false;
639 }
640 }
641 return ok;
642 }
643
644 // Utility function that deletes either a file or directory,
645 // before or after reboot
646 HRESULT DeleteBeforeOrAfterReboot(const TCHAR* targetname) {
647 if (!File::Exists(targetname)) {
648 return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
649 }
650
651 HRESULT hr = E_FAIL;
652 if (File::IsDirectory(targetname)) {
653 // DeleteDirectory will schedule deletion at next reboot if it cannot delete
654 // immediately.
655 hr = DeleteDirectory(targetname);
656 } else {
657 hr = File::Remove(targetname);
658 // If failed, schedule deletion at next reboot
659 if (FAILED(hr)) {
660 UTIL_LOG(L1, (_T("[DeleteBeforeOrAfterReboot]")
661 _T("[trying to delete after reboot][%s]"), targetname));
662 hr = File::DeleteAfterReboot(targetname);
663 }
664 }
665
666 if (FAILED(hr)) {
667 UTIL_LOG(L1, (_T("[DeleteBeforeOrAfterReboot]")
668 _T("[failed to delete][%s][0x%08x]"), targetname, hr));
669 }
670
671 return hr;
672 }
673
674
675 // Internal implementation of the safe version of getting size of all files in
676 // a directory. It is able to abort the counting if one of the maximum criteria
677 // is reached.
678 HRESULT InternalSafeGetDirectorySize(const TCHAR* dir_name,
679 uint64* size,
680 HANDLE shutdown_event,
681 uint64 max_size,
682 int curr_file_count,
683 int max_file_count,
684 int curr_depth,
685 int max_depth,
686 DWORD end_time_ms) {
687 ASSERT1(dir_name && *dir_name);
688 ASSERT1(size);
689
690 CString dir_find_name = String_MakeEndWith(dir_name, _T("\\"), false);
691 dir_find_name += _T("*");
692 WIN32_FIND_DATA find_data = {0};
693 scoped_hfind hfind(::FindFirstFile(dir_find_name, &find_data));
694 if (!hfind) {
695 return ::GetLastError() == ERROR_NO_MORE_FILES ? S_OK :
696 HRESULTFromLastError();
697 }
698
699 do {
700 // Bail out if shutting down
701 if (shutdown_event && IsHandleSignaled(shutdown_event)) {
702 return E_ABORT;
703 }
704
705 // Bail out if reaching maximum running time
706 if (end_time_ms && ::GetTickCount() >= end_time_ms) {
707 UTIL_LOG(L6, (_T("[InternalSafeGetDirectorySize]")
708 _T("[reaching max running time][%s][%u]"),
709 dir_name, end_time_ms));
710 return E_ABORT;
711 }
712
713 // Skip reparse point since it might be a hard link which could cause an
714 // infinite recursive directory loop.
715 if (find_data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
716 continue;
717 }
718
719 if (find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
720 // Skip . and ..
721 if (String_StrNCmp(find_data.cFileName, _T("."), 2, false) == 0 ||
722 String_StrNCmp(find_data.cFileName, _T(".."), 3, false) == 0) {
723 continue;
724 }
725
726 // Bail out if reaching maximum depth
727 if (max_depth && curr_depth + 1 >= max_depth) {
728 UTIL_LOG(L6, (_T("[InternalSafeGetDirectorySize]")
729 _T("[reaching max depth][%s][%u]"), dir_name, max_depth));
730 return E_ABORT;
731 }
732
733 // Walk over sub-directory
734 CString sub_dir_name = String_MakeEndWith(dir_name, _T("\\"), false);
735 sub_dir_name += find_data.cFileName;
736 RET_IF_FAILED(InternalSafeGetDirectorySize(sub_dir_name,
737 size,
738 shutdown_event,
739 max_size,
740 curr_file_count,
741 max_file_count,
742 curr_depth + 1,
743 max_depth,
744 end_time_ms));
745 } else {
746 // Bail out if reaching maximum number of files
747 ++curr_file_count;
748 if (max_file_count && curr_file_count >= max_file_count) {
749 UTIL_LOG(L6, (_T("[InternalSafeGetDirectorySize]")
750 _T("[reaching max file count][%s][%u]"),
751 dir_name, max_file_count));
752 return E_ABORT;
753 }
754
755 // Count the file size
756 uint64 file_size =
757 ((static_cast<uint64>((find_data.nFileSizeHigh)) << 32)) +
758 static_cast<uint64>(find_data.nFileSizeLow);
759 *size += file_size;
760
761 // Bail out if reaching maximum size
762 if (max_size && *size >= max_size) {
763 UTIL_LOG(L6, (_T("[InternalSafeGetDirectorySize]")
764 _T("[reaching max size][%s][%u]"), dir_name, max_size));
765 return E_ABORT;
766 }
767 }
768 } while (::FindNextFile(get(hfind), &find_data));
769
770 return ::GetLastError() == ERROR_NO_MORE_FILES ? S_OK :
771 HRESULTFromLastError();
772 }
773
774 // The safe version of getting size of all files in a directory
775 // It is able to abort the counting if one of the maximum criteria is reached
776 HRESULT SafeGetDirectorySize(const TCHAR* dir_name,
777 uint64* size,
778 HANDLE shutdown_event,
779 uint64 max_size,
780 int max_file_count,
781 int max_depth,
782 int max_running_time_ms) {
783 ASSERT1(dir_name && *dir_name);
784 ASSERT1(size);
785
786 *size = 0;
787
788 DWORD end_time = 0;
789 if (max_running_time_ms > 0) {
790 end_time = ::GetTickCount() + max_running_time_ms;
791 }
792 return InternalSafeGetDirectorySize(dir_name,
793 size,
794 shutdown_event,
795 max_size,
796 0,
797 max_file_count,
798 0,
799 max_depth,
800 end_time);
801 }
802
803 // Get size of all files in a directory
804 HRESULT GetDirectorySize(const TCHAR* dir_name, uint64* size) {
805 ASSERT1(dir_name && *dir_name);
806 ASSERT1(size);
807 return SafeGetDirectorySize(dir_name, size, NULL, 0, 0, 0, 0);
808 }
809
810 // Handles the logic to determine the handle that was signaled
811 // as a result of calling *WaitForMultipleObjects.
812 HRESULT GetSignaledObjectPosition(uint32 cnt, DWORD res, uint32* pos) {
813 ASSERT1(pos);
814
815 if (res == WAIT_FAILED) {
816 return S_FALSE;
817 }
818
819 #pragma warning(disable : 4296)
820 // C4296: '>=' : expression is always true
821 if ((res >= WAIT_OBJECT_0) && (res < WAIT_OBJECT_0 + cnt)) {
822 *pos = res - WAIT_OBJECT_0;
823 return S_OK;
824 }
825 #pragma warning(default : 4296)
826
827 if ((res >= WAIT_ABANDONED_0) && (res < WAIT_ABANDONED_0 + cnt)) {
828 *pos = res - WAIT_ABANDONED_0;
829 return S_OK;
830 }
831 return E_INVALIDARG;
832 }
833
834 // Supports all of the other WaitWithMessage* functions.
835 //
836 // Returns:
837 // S_OK when the message loop should continue.
838 // S_FALSE when it receives something that indicates the
839 // loop should quit.
840 // E_* only when GetMessage failed
841 //
842 // This function is not exposed outside of this file. Only
843 // friendly wrappers of it are.
844 HRESULT WaitWithMessageLoopAnyInternal(
845 const HANDLE* phandles,
846 uint32 cnt,
847 uint32* pos,
848 MessageHandlerInternalInterface* message_handler) {
849 ASSERT1(pos && message_handler);
850 // cnt and phandles are either both zero or both not zero.
851 ASSERT1(!cnt == !phandles);
852
853 // Loop until an error happens or the wait is satisfied by a signaled
854 // object or an abandoned mutex.
855 for (;;) {
856 MSG msg = {0};
857
858 // Process the messages in the input queue.
859 while (::PeekMessage(&msg, 0, 0, 0, PM_NOREMOVE)) {
860 BOOL ret = false;
861 if ((ret = ::GetMessage(&msg, NULL, 0, 0)) != 0) {
862 if (ret == -1) {
863 HRESULT hr = HRESULTFromLastError();
864 UTIL_LOG(LE, (_T("[WaitWithMessageLoopAnyInternal]")
865 _T("[GetMessage failed][0x%08x]"), hr));
866 return hr;
867 }
868 message_handler->Process(&msg, &phandles, &cnt);
869 } else {
870 // We need to re-post the quit message we retrieved so that it could
871 // propagate to the outer layer. Otherwise, the program will seem to
872 // "get stuck" in its shutdown code.
873 ::PostQuitMessage(msg.wParam);
874 return S_FALSE;
875 }
876
877 // WaitForMultipleObjects fails if cnt == 0.
878 if (cnt) {
879 // Briefly check the state of the handle array to see if something
880 // has signaled as we processed a message.
881 ASSERT1(phandles);
882 DWORD res = ::WaitForMultipleObjects(cnt, phandles, false, 0);
883 ASSERT1(res != WAIT_FAILED);
884 HRESULT hr = GetSignaledObjectPosition(cnt, res, pos);
885 if (SUCCEEDED(hr)) {
886 return hr;
887 }
888 }
889 }
890
891 // The wait with message. It is satisfied by either the objects getting
892 // signaled or when messages enter the message queue.
893 // TODO(omaha): implementing timeout is a little bit tricky since we
894 // want the timeout on the handles only and the native API does not
895 // have this semantic.
896 //
897 // TODO(omaha): use a waitable timer to implement the timeout.
898 //
899 // When cnt is zero then the execution flow waits here until messages
900 // arrive in the input queue. Unlike WaitForMultipleObjects,
901 // MsgWaitForMultipleObjects does not error out when cnt == 0.
902 const DWORD timeout = INFINITE;
903 DWORD res(::MsgWaitForMultipleObjects(cnt, phandles, false, timeout,
904 QS_ALLINPUT));
905 ASSERT((res != WAIT_FAILED),
906 (_T("[MsgWaitForMultipleObjects returned WAIT_FAILED][%u]"),
907 ::GetLastError()));
908
909 ASSERT1(res != WAIT_TIMEOUT);
910
911 HRESULT hr = GetSignaledObjectPosition(cnt, res, pos);
912 if (SUCCEEDED(hr)) {
913 return hr;
914 }
915 }
916 }
917
918 // The simplest implementation of a message processor
919 void BasicMessageHandler::Process(MSG* msg) {
920 ASSERT1(msg);
921 ::TranslateMessage(msg);
922 ::DispatchMessage(msg);
923 }
924
925 class BasicMessageHandlerInternal : public BasicMessageHandler,
926 public MessageHandlerInternalInterface {
927 public:
928 BasicMessageHandlerInternal() {}
929 virtual void Process(MSG* msg, const HANDLE**, uint32*) {
930 BasicMessageHandler::Process(msg);
931 }
932 private:
933 DISALLOW_EVIL_CONSTRUCTORS(BasicMessageHandlerInternal);
934 };
935
936
937 bool WaitWithMessageLoopAny(const std::vector<HANDLE>& handles, uint32* pos) {
938 BasicMessageHandlerInternal msg_handler;
939 return WaitWithMessageLoopAnyInternal(&handles.front(), handles.size(), pos,
940 &msg_handler) != S_FALSE;
941 }
942
943 bool WaitWithMessageLoopAll(const std::vector<HANDLE>& handles) {
944 // make a copy of the vector, as objects must be removed from the
945 // wait array as they get signaled.
946 std::vector<HANDLE> h(handles);
947
948 // The function is mainly implemented in terms of WaitWithMessageLoopAny
949
950 // loop until all objects are signaled.
951 while (!h.empty()) {
952 uint32 pos(static_cast<uint32>(-1));
953 if (!WaitWithMessageLoopAny(h, &pos)) return false;
954 ASSERT1(pos < h.size());
955 h.erase(h.begin() + pos); // remove the signaled object and loop
956 }
957
958 return true;
959 }
960
961 bool WaitWithMessageLoop(HANDLE h) {
962 BasicMessageHandlerInternal msg_handler;
963 uint32 pos(static_cast<uint32>(-1));
964 bool res =
965 WaitWithMessageLoopAnyInternal(&h, 1, &pos, &msg_handler) != S_FALSE;
966 if (res) {
967 // It's the first and the only handle that it is signaled.
968 ASSERT1(pos == 0);
969 }
970 return res;
971 }
972
973 // Wait with message loop for a certain period of time
974 bool WaitWithMessageLoopTimed(DWORD ms) {
975 scoped_timer timer(::CreateWaitableTimer(NULL,
976 true, // manual reset
977 NULL));
978 ASSERT1(get(timer));
979 LARGE_INTEGER timeout = MSto100NSRelative(ms);
980 BOOL timer_ok = ::SetWaitableTimer(get(timer),
981 &timeout,
982 0,
983 NULL,
984 NULL,
985 false);
986 ASSERT1(timer_ok);
987 return WaitWithMessageLoop(get(timer));
988 }
989
990 MessageLoopWithWait::MessageLoopWithWait() : message_handler_(NULL) {
991 }
992
993 void MessageLoopWithWait::set_message_handler(
994 MessageHandlerInterface* message_handler) {
995 message_handler_ = message_handler;
996 }
997
998 // The message loop and handle callback routine.
999 HRESULT MessageLoopWithWait::Process() {
1000 while (true) {
1001 ASSERT1(callback_handles_.size() == callbacks_.size());
1002
1003 // The implementation allows for an empty array of handles. Taking the
1004 // address of elements in an empty container is not allowed so we must
1005 // deal with this case here.
1006 size_t pos(0);
1007 HRESULT hr = WaitWithMessageLoopAnyInternal(
1008 callback_handles_.empty() ? NULL : &callback_handles_.front(),
1009 callback_handles_.size(),
1010 &pos,
1011 this);
1012
1013 // In addition to E_*, S_FALSE should cause a return to happen here.
1014 if (hr != S_OK) {
1015 return hr;
1016 }
1017
1018 ASSERT1(pos < callback_handles_.size());
1019 ASSERT1(callback_handles_.size() == callbacks_.size());
1020
1021 HANDLE signaled_handle = callback_handles_[pos];
1022 WaitCallbackInterface* callback_interface = callbacks_[pos];
1023 RemoveHandleAt(pos);
1024
1025 if (!callback_interface->HandleSignaled(signaled_handle)) {
1026 return S_OK;
1027 }
1028 }
1029 }
1030
1031 // Handles one messgae and adjust the handles and cnt as appropriate after
1032 // handling the message.
1033 void MessageLoopWithWait::Process(MSG* msg, const HANDLE** handles,
1034 uint32* cnt) {
1035 ASSERT1(msg && handles && cnt);
1036
1037 if (message_handler_) {
1038 message_handler_->Process(msg);
1039 }
1040
1041 // Set the handles and count again because they may have changed
1042 // while processing the message.
1043 *handles = callback_handles_.empty() ? NULL : &callback_handles_.front();
1044 *cnt = callback_handles_.size();
1045 }
1046 // Starts waiting on the given handle
1047 bool MessageLoopWithWait::RegisterWaitForSingleObject(
1048 HANDLE handle, WaitCallbackInterface* callback) {
1049 ASSERT1(callback_handles_.size() == callbacks_.size());
1050 ASSERT1(callback != NULL);
1051
1052 if (callback_handles_.size() >= MAXIMUM_WAIT_OBJECTS - 1) {
1053 return false;
1054 }
1055
1056 // In case the user is registering a handle, that they previous added
1057 // remove the previous one before adding it back into the array.
1058 UnregisterWait(handle);
1059 callback_handles_.push_back(handle);
1060 callbacks_.push_back(callback);
1061
1062 ASSERT1(callback_handles_.size() == callbacks_.size());
1063 return true;
1064 }
1065
1066 // Finds the given handle and stops waiting on it
1067 bool MessageLoopWithWait::UnregisterWait(HANDLE handle) {
1068 ASSERT1(callback_handles_.size() == callbacks_.size());
1069
1070 for (uint32 index = 0; index < callback_handles_.size() ; index++) {
1071 if (callback_handles_[index] == handle) {
1072 RemoveHandleAt(index);
1073 return true;
1074 }
1075 }
1076 return false;
1077 }
1078
1079 // Removes the wait handle at the given position
1080 void MessageLoopWithWait::RemoveHandleAt(uint32 pos) {
1081 ASSERT1(callback_handles_.size() == callbacks_.size());
1082 ASSERT1(pos < callback_handles_.size());
1083
1084 callback_handles_.erase(callback_handles_.begin() + pos);
1085 callbacks_.erase(callbacks_.begin() + pos);
1086
1087 ASSERT1(callback_handles_.size() == callbacks_.size());
1088 }
1089
1090 HRESULT CallEntryPoint0(const TCHAR* dll_path,
1091 const char* function_name,
1092 HRESULT* result) {
1093 ASSERT1(dll_path);
1094 ASSERT1(::lstrlen(dll_path) > 0);
1095 ASSERT1(function_name);
1096 ASSERT1(::strlen(function_name) > 0);
1097 ASSERT1(result);
1098
1099 scoped_library dll(::LoadLibrary(dll_path));
1100 if (!dll) {
1101 return HRESULTFromLastError();
1102 }
1103
1104 HRESULT (*proc)() = reinterpret_cast<HRESULT (*)()>(
1105 ::GetProcAddress(get(dll), function_name));
1106 if (!proc) {
1107 return HRESULT_FROM_WIN32(ERROR_INVALID_FUNCTION);
1108 }
1109
1110 *result = (proc)();
1111 return S_OK;
1112 }
1113
1114 // Register a DLL
1115 HRESULT RegisterDll(const TCHAR* dll_path) {
1116 HRESULT hr = S_OK;
1117 HRESULT hr_call = CallEntryPoint0(dll_path, "DllRegisterServer", &hr);
1118 if (SUCCEEDED(hr_call)) {
1119 return hr;
1120 }
1121 return hr_call;
1122 }
1123
1124 // Unregister a DLL
1125 HRESULT UnregisterDll(const TCHAR* dll_path) {
1126 HRESULT hr = S_OK;
1127 HRESULT hr_call = CallEntryPoint0(dll_path, "DllUnregisterServer", &hr);
1128 if (SUCCEEDED(hr_call)) {
1129 return hr;
1130 }
1131 return hr_call;
1132 }
1133
1134 // Register/unregister an EXE
1135 HRESULT RegisterOrUnregisterExe(const TCHAR* exe_path, const TCHAR* cmd_line) {
1136 ASSERT1(exe_path);
1137 ASSERT1(cmd_line);
1138
1139 // cmd_line parameter really contains the arguments to be passed
1140 // on the process creation command line.
1141 PROCESS_INFORMATION pi = {0};
1142 HRESULT hr = System::StartProcessWithArgsAndInfo(exe_path, cmd_line, &pi);
1143 if (FAILED(hr)) {
1144 UTIL_LOG(LEVEL_WARNING, (_T("[RegisterOrUnregisterExe]")
1145 _T("[failed to start process]")
1146 _T("[%s][%s][0x%08x]"), exe_path, cmd_line, hr));
1147 return hr;
1148 }
1149 // Take ownership of the handles for clean up.
1150 scoped_thread thread(pi.hThread);
1151 scoped_process process(pi.hProcess);
1152
1153 // ATL COM servers return an HRESULT on exit. There is a case in which they
1154 // return -1 which seems like a bug in ATL. It appears there is no
1155 // documented convention on what a local server would return for errors.
1156 // There is a possibility that a server would return Windows errors.
1157
1158 // Wait on the process to exit and return the exit code of the process.
1159 DWORD result(::WaitForSingleObject(get(process), INFINITE));
1160 DWORD exit_code(0);
1161 if (result == WAIT_OBJECT_0 &&
1162 ::GetExitCodeProcess(get(process), &exit_code)) {
1163 return static_cast<HRESULT>(exit_code);
1164 } else {
1165 return HRESULT_FROM_WIN32(ERROR_TIMEOUT);
1166 }
1167 }
1168
1169 // Register a COM Local Server
1170 HRESULT RegisterServer(const TCHAR* exe_path) {
1171 return RegisterOrUnregisterExe(exe_path, _T("/RegServer"));
1172 }
1173
1174 // Unregister a COM Local Server
1175 HRESULT UnregisterServer(const TCHAR* exe_path) {
1176 return RegisterOrUnregisterExe(exe_path, _T("/UnregServer"));
1177 }
1178
1179 // Register a Service
1180 HRESULT RegisterService(const TCHAR* exe_path) {
1181 return RegisterOrUnregisterExe(exe_path, _T("/Service"));
1182 }
1183
1184 // Unregister a Service
1185 HRESULT UnregisterService(const TCHAR* exe_path) {
1186 // Unregistering a service is via UnregServer
1187 return RegisterOrUnregisterExe(exe_path, _T("/UnregServer"));
1188 }
1189
1190 // Adapted from gds installer/install/work_list.cpp: InstallServiceExecutable
1191 HRESULT RunService(const TCHAR* service_name) {
1192 scoped_service manager(::OpenSCManager(NULL, // local machine
1193 NULL, // ServicesActive database
1194 STANDARD_RIGHTS_READ));
1195 ASSERT1(get(manager));
1196 if (!get(manager)) {
1197 return HRESULTFromLastError();
1198 }
1199
1200 scoped_service service(::OpenService(get(manager), service_name,
1201 SERVICE_START));
1202 ASSERT1(get(service));
1203 if (!get(service)) {
1204 return HRESULTFromLastError();
1205 }
1206
1207 UTIL_LOG(L2, (_T("start service")));
1208 if (!::StartService(get(service), 0, NULL)) {
1209 return HRESULTFromLastError();
1210 }
1211 return S_OK;
1212 }
1213
1214
1215 HRESULT ReadEntireFile(const TCHAR* filepath,
1216 uint32 max_len,
1217 std::vector<byte>* buffer_out) {
1218 return ReadEntireFileShareMode(filepath, max_len, 0, buffer_out);
1219 }
1220
1221 HRESULT ReadEntireFileShareMode(const TCHAR* filepath,
1222 uint32 max_len,
1223 DWORD share_mode,
1224 std::vector<byte>* buffer_out) {
1225 ASSERT1(filepath);
1226 ASSERT1(buffer_out);
1227
1228 File file;
1229 HRESULT hr = file.OpenShareMode(filepath, false, false, share_mode);
1230 if (FAILED(hr)) {
1231 // File missing.
1232 return hr;
1233 }
1234
1235 ON_SCOPE_EXIT_OBJ(file, &File::Close);
1236
1237 uint32 file_len = 0;
1238 hr = file.GetLength(&file_len);
1239 if (FAILED(hr)) {
1240 // Should never happen
1241 return hr;
1242 }
1243
1244 if (max_len != 0 && file_len > max_len) {
1245 // Too large to consider
1246 return MEM_E_INVALID_SIZE;
1247 }
1248
1249 if (file_len == 0) {
1250 buffer_out->clear();
1251 return S_OK;
1252 }
1253
1254 int old_size = buffer_out->size();
1255 buffer_out->resize(old_size + file_len);
1256
1257 uint32 bytes_read = 0;
1258 hr = file.ReadFromStartOfFile(file_len,
1259 &(*buffer_out)[old_size],
1260 &bytes_read);
1261 if (FAILED(hr)) {
1262 // I/O error of some kind
1263 return hr;
1264 }
1265
1266 if (bytes_read != file_len) {
1267 // Unexpected length. This could happen when reading a file someone else
1268 // is writing to such as log files.
1269 ASSERT1(false);
1270 return E_UNEXPECTED;
1271 }
1272
1273 // All's well that ends well
1274 return S_OK;
1275 }
1276
1277 HRESULT WriteEntireFile(const TCHAR * filepath,
1278 const std::vector<byte>& buffer_in) {
1279 ASSERT1(filepath);
1280
1281 // File::WriteAt doesn't implement clear-on-open-for-write semantics,
1282 // so just delete the file if it exists instead of writing into it.
1283
1284 if (File::Exists(filepath)) {
1285 HRESULT hr = File::Remove(filepath);
1286 if (FAILED(hr)) {
1287 return hr;
1288 }
1289 }
1290
1291 File file;
1292 HRESULT hr = file.Open(filepath, true, false);
1293 if (FAILED(hr)) {
1294 return hr;
1295 }
1296
1297 ON_SCOPE_EXIT_OBJ(file, &File::Close);
1298
1299 uint32 bytes_written = 0;
1300 hr = file.WriteAt(0, &buffer_in.front(), buffer_in.size(), 0, &bytes_written);
1301 if (FAILED(hr)) {
1302 return hr;
1303 }
1304 if (bytes_written != buffer_in.size()) {
1305 // This shouldn't happen, caller needs to investigate what's up.
1306 ASSERT1(false);
1307 return E_UNEXPECTED;
1308 }
1309
1310 return S_OK;
1311 }
1312
1313 // Conversions between a byte stream and a std::string
1314 HRESULT BufferToString(const std::vector<byte>& buffer_in, CStringA* str_out) {
1315 ASSERT1(str_out);
1316 str_out->Append(reinterpret_cast<const char*>(&buffer_in.front()),
1317 buffer_in.size());
1318 return S_OK;
1319 }
1320
1321 HRESULT StringToBuffer(const CStringA& str_in, std::vector<byte>* buffer_out) {
1322 ASSERT1(buffer_out);
1323 buffer_out->assign(str_in.GetString(),
1324 str_in.GetString() + str_in.GetLength());
1325 return S_OK;
1326 }
1327
1328 HRESULT BufferToString(const std::vector<byte>& buffer_in, CString* str_out) {
1329 ASSERT1(str_out);
1330
1331 size_t len2 = buffer_in.size();
1332 ASSERT1(len2 % 2 == 0);
1333 size_t len = len2 / 2;
1334
1335 str_out->Append(reinterpret_cast<const TCHAR*>(&buffer_in.front()), len);
1336
1337 return S_OK;
1338 }
1339
1340 HRESULT StringToBuffer(const CString& str_in, std::vector<byte>* buffer_out) {
1341 ASSERT1(buffer_out);
1342
1343 size_t len = str_in.GetLength();
1344 size_t len2 = len * 2;
1345
1346 buffer_out->resize(len2);
1347 ::memcpy(&buffer_out->front(), str_in.GetString(), len2);
1348
1349 return S_OK;
1350 }
1351
1352 HRESULT RegSplitKeyvalueName(const CString& keyvalue_name,
1353 CString* key_name,
1354 CString* value_name) {
1355 ASSERT1(key_name);
1356 ASSERT1(value_name);
1357
1358 const TCHAR kDefault[] = _T("\\(default)");
1359
1360 if (String_EndsWith(keyvalue_name, _T("\\"), false)) {
1361 key_name->SetString(keyvalue_name, keyvalue_name.GetLength() - 1);
1362 value_name->Empty();
1363 } else if (String_EndsWith(keyvalue_name, kDefault, true)) {
1364 key_name->SetString(keyvalue_name,
1365 keyvalue_name.GetLength() - TSTR_SIZE(kDefault));
1366 value_name->Empty();
1367 } else {
1368 int last_slash = String_ReverseFindChar(keyvalue_name, _T('\\'));
1369 if (last_slash == -1) {
1370 // No slash found - bizzare and wrong
1371 return E_FAIL;
1372 }
1373 key_name->SetString(keyvalue_name, last_slash);
1374 value_name->SetString(keyvalue_name.GetString() + last_slash + 1,
1375 keyvalue_name.GetLength() - last_slash - 1);
1376 }
1377
1378 return S_OK;
1379 }
1380
1381 HRESULT ExpandEnvLikeStrings(const TCHAR* src,
1382 const std::map<CString, CString>& keywords,
1383 CString* dest) {
1384 ASSERT1(src);
1385 ASSERT1(dest);
1386
1387 const TCHAR kMarker = _T('%');
1388
1389 dest->Empty();
1390
1391 // Loop while finding the marker in the string
1392 HRESULT hr = S_OK;
1393 int pos = 0;
1394 int marker_pos1 = -1;
1395 while ((marker_pos1 = String_FindChar(src, kMarker, pos)) != -1) {
1396 // Try to find the right marker
1397 int marker_pos2 = -1;
1398 const TCHAR* s = src + marker_pos1 + 1;
1399 for (; *s; ++s) {
1400 if (*s == kMarker) {
1401 marker_pos2 = s - src;
1402 break;
1403 }
1404 if (!String_IsIdentifierChar(*s)) {
1405 break;
1406 }
1407 }
1408 if (marker_pos2 == -1) {
1409 // Unmatched marker found, skip
1410 dest->Append(src + pos, marker_pos1 - pos + 1);
1411 pos = marker_pos1 + 1;
1412 continue;
1413 }
1414
1415 // Get the name - without the % markers on each end
1416 CString name(src + marker_pos1 + 1, marker_pos2 - marker_pos1 - 1);
1417
1418 bool found = false;
1419 for (std::map<CString, CString>::const_iterator it(keywords.begin());
1420 it != keywords.end();
1421 ++it) {
1422 if (_tcsicmp(it->first, name) == 0) {
1423 dest->Append(src + pos, marker_pos1 - pos);
1424 dest->Append(it->second);
1425 found = true;
1426 break;
1427 }
1428 }
1429 if (!found) {
1430 // No mapping found
1431 UTIL_LOG(LE, (_T("[ExpandEnvLikeStrings]")
1432 _T("[no mapping found for '%s' in '%s']"), name, src));
1433 dest->Append(src + pos, marker_pos2 - pos + 1);
1434 hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
1435 }
1436
1437 pos = marker_pos2 + 1;
1438 }
1439
1440 int len = _tcslen(src);
1441 if (pos < len) {
1442 dest->Append(src + pos, len - pos);
1443 }
1444
1445 return hr;
1446 }
1447
1448 bool IsRegistryPath(const TCHAR* path) {
1449 return String_StartsWith(path, _T("HKLM\\"), false) ||
1450 String_StartsWith(path, _T("HKCU\\"), false) ||
1451 String_StartsWith(path, _T("HKCR\\"), false) ||
1452 String_StartsWith(path, _T("HKEY_LOCAL_MACHINE\\"), false) ||
1453 String_StartsWith(path, _T("HKEY_CURRENT_USER\\"), false) ||
1454 String_StartsWith(path, _T("HKEY_CLASSES_ROOT\\"), false);
1455 }
1456
1457 bool IsUrl(const TCHAR* path) {
1458 // Currently we only check for "http://" and "https://"
1459 return String_StartsWith(path, kHttpProto, true) ||
1460 String_StartsWith(path, kHttpsProto, true);
1461 }
1462
1463
1464 CString GuidToString(const GUID& guid) {
1465 TCHAR guid_str[40] = {0};
1466 VERIFY1(::StringFromGUID2(guid, guid_str, arraysize(guid_str)));
1467 String_ToUpper(guid_str);
1468 return guid_str;
1469 }
1470
1471 HRESULT StringToGuidSafe(const CString& str, GUID* guid) {
1472 ASSERT1(guid);
1473 TCHAR* s = const_cast<TCHAR*>(str.GetString());
1474 return ::IIDFromString(s, guid);
1475 }
1476
1477 // Helper function to convert a variant containing a list of strings
1478 void VariantToStringList(VARIANT var, std::vector<CString>* list) {
1479 ASSERT1(list);
1480
1481 list->clear();
1482
1483 ASSERT1(V_VT(&var) == VT_DISPATCH);
1484 CComPtr<IDispatch> obj = V_DISPATCH(&var);
1485 ASSERT1(obj);
1486
1487 CComVariant var_length;
1488 VERIFY1(SUCCEEDED(obj.GetPropertyByName(_T("length"), &var_length)));
1489 ASSERT1(V_VT(&var_length) == VT_I4);
1490 int length = V_I4(&var_length);
1491
1492 for (int i = 0; i < length; ++i) {
1493 CComVariant value;
1494 VERIFY1(SUCCEEDED(obj.GetPropertyByName(itostr(i), &value)));
1495 if (V_VT(&value) == VT_BSTR) {
1496 list->push_back(V_BSTR(&value));
1497 } else {
1498 ASSERT1(false);
1499 }
1500 }
1501 }
1502
1503
1504 HRESULT GetCurrentProcessHandle(HANDLE* handle) {
1505 ASSERT1(handle);
1506 scoped_process real_handle;
1507 HANDLE pseudo_handle = ::GetCurrentProcess();
1508 bool res = ::DuplicateHandle(
1509 pseudo_handle, // this process pseudo-handle
1510 pseudo_handle, // handle to duplicate
1511 pseudo_handle, // the process receiving the handle
1512 address(real_handle), // this process real handle
1513 0, // ignored
1514 false, // don't inherit this handle
1515 DUPLICATE_SAME_ACCESS) != 0;
1516
1517 *handle = NULL;
1518 if (!res) {
1519 return HRESULTFromLastError();
1520 }
1521 *handle = release(real_handle);
1522 return S_OK;
1523 }
1524
1525 HRESULT DuplicateTokenIntoCurrentProcess(HANDLE source_process,
1526 HANDLE token_to_duplicate,
1527 CAccessToken* duplicated_token) {
1528 ASSERT1(source_process);
1529 ASSERT1(token_to_duplicate);
1530 ASSERT1(duplicated_token);
1531
1532 scoped_handle alt_token;
1533 bool res = ::DuplicateHandle(
1534 source_process, // Process whose handle needs duplicating.
1535 token_to_duplicate, // Handle to duplicate.
1536 ::GetCurrentProcess(), // Current process receives the handle.
1537 address(alt_token), // Duplicated handle.
1538 TOKEN_ALL_ACCESS, // Access requested for the new handle.
1539 false, // Do not inherit the new handle.
1540 DUPLICATE_SAME_ACCESS) != 0; // Same access as token_to_duplicate.
1541
1542 if (!res) {
1543 HRESULT hr = HRESULTFromLastError();
1544 CORE_LOG(LE, (_T("[DuplicateTokenIntoCurrentProcess failed][0x%x]"), hr));
1545 return hr;
1546 }
1547
1548 duplicated_token->Attach(release(alt_token));
1549 return S_OK;
1550 }
1551
1552
1553 // get a time64 value
1554 // NOTE: If the value is greater than the
1555 // max value, then SetValue will be called using the max_value.
1556 HRESULT GetLimitedTimeValue(const TCHAR* full_key_name, const TCHAR* value_name,
1557 time64 max_time, time64* value,
1558 bool* limited_value) {
1559 ASSERT1(full_key_name);
1560 ASSERT1(value);
1561 STATIC_ASSERT(sizeof(time64) == sizeof(DWORD64));
1562
1563 if (limited_value) {
1564 *limited_value = false;
1565 }
1566 HRESULT hr = RegKey::GetValue(full_key_name, value_name, value);
1567 if (SUCCEEDED(hr) && *value > max_time) {
1568 *value = max_time;
1569
1570 // Use a different hr for the setting of the value b/c
1571 // the returned hr should reflect the success/failure of reading the key
1572 HRESULT set_value_hr = RegKey::SetValue(full_key_name, value_name, *value);
1573 ASSERT(SUCCEEDED(set_value_hr),
1574 (_T("GetLimitedTimeValue - failed when setting a value: 0x%08x]"),
1575 set_value_hr));
1576 if (SUCCEEDED(set_value_hr) && limited_value) {
1577 *limited_value = true;
1578 }
1579 }
1580 return hr;
1581 }
1582
1583 // get a time64 value trying reg keys successively if there is a
1584 // failure in getting a value.
1585 HRESULT GetLimitedTimeValues(const TCHAR* full_key_names[],
1586 int key_names_length,
1587 const TCHAR* value_name,
1588 time64 max_time,
1589 time64* value,
1590 bool* limited_value) {
1591 ASSERT1(full_key_names);
1592 ASSERT1(value);
1593 ASSERT1(key_names_length > 0);
1594
1595 HRESULT hr = E_FAIL;
1596 for (int i = 0; i < key_names_length; ++i) {
1597 hr = GetLimitedTimeValue(full_key_names[i], value_name, max_time, value,
1598 limited_value);
1599 if (SUCCEEDED(hr)) {
1600 return hr;
1601 }
1602 }
1603 return hr;
1604 }
1605
1606 // Wininet.dll (and especially the version that comes with IE7, with 01/12/07
1607 // timestamp) incorrectly initializes Rasman.dll. As a result, there is a race
1608 // condition that causes double-free on a memory from process heap.
1609 // This causes memory corruption in the heap that may later produce a variety
1610 // of ill effects, most frequently a crash with a callstack that contains
1611 // wininet and rasman, or ntdll!RtlAllocHeap. The root cause is that
1612 // Rasapi32!LoadRasmanDllAndInit is not thread safe and can start very involved
1613 // process of initialization on 2 threads at the same time. It's a bug.
1614 // Solution: in the begining of the program, trigger synchronous load of
1615 // rasman dll. The easy way is to call a public ras api that does synchronous
1616 // initialization, which is what we do here.
1617 void EnsureRasmanLoaded() {
1618 RASENTRYNAME ras_entry_name = {0};
1619 DWORD size_bytes = sizeof(ras_entry_name);
1620 DWORD number_of_entries = 0;
1621 ras_entry_name.dwSize = size_bytes;
1622 // we don't really need results of this method,
1623 // it simply triggers RASAPI32!LoadRasmanDllAndInit() internally.
1624 ::RasEnumEntries(NULL,
1625 NULL,
1626 &ras_entry_name,
1627 &size_bytes,
1628 &number_of_entries);
1629 }
1630
1631 // Appends two reg keys. Handles the situation where there are traling
1632 // back slashes in one and leading back slashes in two.
1633 CString AppendRegKeyPath(const CString& one, const CString& two) {
1634 CString leftpart(one);
1635 int length = leftpart.GetLength();
1636 int i = 0;
1637 for (i = length - 1; i >= 0; --i) {
1638 if (leftpart[i] != _T('\\')) {
1639 break;
1640 }
1641 }
1642 leftpart = leftpart.Left(i+1);
1643
1644 CString rightpart(two);
1645 int lengthr = rightpart.GetLength();
1646 for (i = 0; i < lengthr; ++i) {
1647 if (rightpart[i] != _T('\\')) {
1648 break;
1649 }
1650 }
1651 rightpart = rightpart.Right(lengthr - i);
1652
1653 CString result;
1654 SafeCStringFormat(&result, _T("%s\\%s"), leftpart, rightpart);
1655 return result;
1656 }
1657
1658 CString AppendRegKeyPath(const CString& one, const CString& two,
1659 const CString& three) {
1660 CString result = AppendRegKeyPath(one, two);
1661 result = AppendRegKeyPath(result, three);
1662 return result;
1663 }
1664
1665
1666 HRESULT GetUserKeysFromHkeyUsers(std::vector<CString>* key_names) {
1667 ASSERT1(key_names);
1668 CORE_LOG(L3, (_T("[GetUserKeysFromHkeyUsers]")));
1669
1670 TCHAR user_key_name[MAX_PATH] = {0};
1671 int i = 0;
1672 while (::RegEnumKey(HKEY_USERS, i++, user_key_name, MAX_PATH) !=
1673 ERROR_NO_MORE_ITEMS) {
1674 byte sid_buffer[SECURITY_MAX_SID_SIZE] = {0};
1675 PSID sid = reinterpret_cast<PSID>(sid_buffer);
1676 if (::ConvertStringSidToSid(user_key_name, &sid) != 0) {
1677 // We could convert the string SID into a real SID. If not
1678 // we just ignore.
1679 DWORD size = MAX_PATH;
1680 DWORD size_domain = MAX_PATH;
1681 SID_NAME_USE sid_type = SidTypeComputer;
1682 TCHAR user_name[MAX_PATH] = {0};
1683 TCHAR domain_name[MAX_PATH] = {0};
1684
1685 if (::LookupAccountSid(NULL, sid, user_name, &size,
1686 domain_name, &size_domain, &sid_type) == 0) {
1687 HRESULT hr = HRESULTFromLastError();
1688 CORE_LOG(LW, (_T("[GetUserKeysFromHkeyUsers LookupAccountSid failed]")
1689 _T("[0x%08x]"), hr));
1690 continue;
1691 }
1692
1693 if (sid_type == SidTypeUser) {
1694 // Change the RunAs keys for the user goopdates to point to the
1695 // machine install.
1696 CString user_reg_key_name = AppendRegKeyPath(USERS_KEY, user_key_name);
1697 key_names->push_back(user_reg_key_name);
1698 }
1699 }
1700 }
1701
1702 return S_OK;
1703 }
1704
1705 HRESULT IsSystemProcess(bool* is_system_process) {
1706 CAccessToken current_process_token;
1707 if (!current_process_token.GetProcessToken(TOKEN_QUERY,
1708 ::GetCurrentProcess())) {
1709 HRESULT hr = HRESULTFromLastError();
1710 ASSERT(false, (_T("CAccessToken::GetProcessToken failed: 0x%08x"), hr));
1711 return hr;
1712 }
1713 CSid logon_sid;
1714 if (!current_process_token.GetUser(&logon_sid)) {
1715 HRESULT hr = HRESULTFromLastError();
1716 ASSERT(false, (_T("CAccessToken::GetUser failed: 0x%08x"), hr));
1717 return hr;
1718 }
1719 *is_system_process = logon_sid == Sids::System();
1720 return S_OK;
1721 }
1722
1723 HRESULT IsUserLoggedOn(bool* is_logged_on) {
1724 ASSERT1(is_logged_on);
1725 bool is_local_system(false);
1726 HRESULT hr = IsSystemProcess(&is_local_system);
1727 if (SUCCEEDED(hr) && is_local_system) {
1728 *is_logged_on = true;
1729 return S_OK;
1730 }
1731 return UserRights::UserIsLoggedOnInteractively(is_logged_on);
1732 }
1733
1734 bool IsClickOnceDisabled() {
1735 CComPtr<IInternetZoneManager> zone_mgr;
1736 HRESULT hr = zone_mgr.CoCreateInstance(CLSID_InternetZoneManager);
1737 if (FAILED(hr)) {
1738 UTIL_LOG(LE, (_T("[InternetZoneManager CreateInstance fail][0x%08x]"), hr));
1739 return true;
1740 }
1741
1742 DWORD policy = URLPOLICY_DISALLOW;
1743 size_t policy_size = sizeof(policy);
1744 hr = zone_mgr->GetZoneActionPolicy(URLZONE_INTERNET,
1745 URLACTION_MANAGED_UNSIGNED,
1746 reinterpret_cast<BYTE*>(&policy),
1747 policy_size,
1748 URLZONEREG_DEFAULT);
1749 if (FAILED(hr)) {
1750 UTIL_LOG(LE, (_T("[GetZoneActionPolicy failed][0x%08x]"), hr));
1751 return true;
1752 }
1753
1754 return policy == URLPOLICY_DISALLOW;
1755 }
1756
1757 // This function only uses kernel32, and it is safe to call from DllMain.
1758 HRESULT PinModuleIntoProcess(const CString& module_name) {
1759 ASSERT1(!module_name.IsEmpty());
1760 static HMODULE module_handle = NULL;
1761 typedef BOOL (WINAPI *Fun)(DWORD flags,
1762 LPCWSTR module_name,
1763 HMODULE* module_handle);
1764
1765 HINSTANCE kernel_instance = ::GetModuleHandle(_T("kernel32.dll"));
1766 ASSERT1(kernel_instance);
1767 Fun pfn = NULL;
1768 if (GPA(kernel_instance, "GetModuleHandleExW", &pfn)) {
1769 if ((*pfn)(GET_MODULE_HANDLE_EX_FLAG_PIN, module_name, &module_handle)) {
1770 return S_OK;
1771 }
1772 ASSERT(false, (_T("GetModuleHandleExW() failed: %d"), ::GetLastError()));
1773 }
1774
1775 module_handle = ::LoadLibrary(module_name);
1776 ASSERT(NULL != module_handle, (_T("LoadLibrary fail: %d"), ::GetLastError()));
1777 if (NULL == module_handle) {
1778 return HRESULTFromLastError();
1779 }
1780
1781 return S_OK;
1782 }
1783
1784 bool ShellExecuteExEnsureParent(LPSHELLEXECUTEINFO shell_exec_info) {
1785 UTIL_LOG(L3, (_T("[ShellExecuteExEnsureParent]")));
1786
1787 ASSERT1(shell_exec_info);
1788 bool shell_exec_succeeded(false);
1789 DWORD last_error(ERROR_SUCCESS);
1790
1791 {
1792 // hwnd_parent window is destroyed at the end of the scope when the
1793 // destructor of scoped_window calls ::DestroyWindow.
1794 scoped_window hwnd_parent;
1795
1796 if (!shell_exec_info->hwnd && vista_util::IsVistaOrLater()) {
1797 reset(hwnd_parent, CreateForegroundParentWindowForUAC());
1798
1799 if (!hwnd_parent) {
1800 last_error = ::GetLastError();
1801 UTIL_LOG(LE, (_T("[CreateDummyOverlappedWindow failed]")));
1802 // Restore last error in case the logging reset it.
1803 ::SetLastError(last_error);
1804 return false;
1805 }
1806
1807 shell_exec_info->hwnd = get(hwnd_parent);
1808
1809 // If elevation is required on Vista, call ::SetForegroundWindow(). This
1810 // will make sure that the elevation prompt, as well as the elevated
1811 // process window comes up in the foreground. It will also ensure that in
1812 // the case where the elevation prompt is cancelled, the error dialog
1813 // shown from this process comes up in the foreground.
1814 if (shell_exec_info->lpVerb &&
1815 _tcsicmp(shell_exec_info->lpVerb, _T("runas")) == 0) {
1816 if (!::SetForegroundWindow(get(hwnd_parent))) {
1817 UTIL_LOG(LW, (_T("[SetForegroundWindow failed][%d]"),
1818 ::GetLastError()));
1819 }
1820 }
1821 }
1822
1823 shell_exec_succeeded = !!::ShellExecuteEx(shell_exec_info);
1824
1825 if (shell_exec_succeeded) {
1826 if (shell_exec_info->hProcess) {
1827 DWORD pid = Process::GetProcessIdFromHandle(shell_exec_info->hProcess);
1828 OPT_LOG(L1, (_T("[Started process][%u]"), pid));
1829 if (!::AllowSetForegroundWindow(pid)) {
1830 UTIL_LOG(LW, (_T("[AllowSetForegroundWindow failed][%d]"),
1831 ::GetLastError()));
1832 }
1833 } else {
1834 OPT_LOG(L1, (_T("[Started process][PID unknown]")));
1835 }
1836 } else {
1837 last_error = ::GetLastError();
1838 UTIL_LOG(LE, (_T("[ShellExecuteEx failed][%s][%s][0x%08x]"),
1839 shell_exec_info->lpFile, shell_exec_info->lpParameters,
1840 last_error));
1841 }
1842 }
1843
1844 // The implicit ::DestroyWindow call from the scoped_window could have reset
1845 // the last error, so restore it.
1846 ::SetLastError(last_error);
1847
1848 return shell_exec_succeeded;
1849 }
1850
1851 // Loads and unloads advapi32.dll for every call. If performance is an issue
1852 // consider keeping the dll always loaded and holding the pointer to the
1853 // RtlGenRandom in a static variable.
1854 // Use the function with care. While the function is documented, it may be
1855 // altered or made unavailable in future versions of the operating system.
1856 bool GenRandom(void* buffer, size_t buffer_length) {
1857 ASSERT1(buffer);
1858 scoped_library lib(::LoadLibrary(_T("ADVAPI32.DLL")));
1859 if (lib) {
1860 typedef BOOLEAN (APIENTRY *RtlGenRandomType)(void*, ULONG);
1861 RtlGenRandomType rtl_gen_random = reinterpret_cast<RtlGenRandomType>(
1862 ::GetProcAddress(get(lib), "SystemFunction036"));
1863 return rtl_gen_random && rtl_gen_random(buffer, buffer_length);
1864 }
1865
1866 // Use CAPI to generate randomness for systems which do not support
1867 // RtlGenRandomType, for instance Windows 2000.
1868 const uint32 kCspFlags = CRYPT_VERIFYCONTEXT | CRYPT_SILENT;
1869 HCRYPTPROV csp = NULL;
1870 if (::CryptAcquireContext(&csp, NULL, NULL, PROV_RSA_FULL, kCspFlags)) {
1871 if (::CryptGenRandom(csp, buffer_length, static_cast<BYTE*>(buffer))) {
1872 return true;
1873 }
1874 }
1875 VERIFY1(::CryptReleaseContext(csp, 0));
1876 return false;
1877 }
1878
1879 // Assumes the path in command is properly enclosed if necessary.
1880 HRESULT ConfigureRunAtStartup(const CString& root_key_name,
1881 const CString& run_value_name,
1882 const CString& command,
1883 bool install) {
1884 UTIL_LOG(L3, (_T("[ConfigureRunAtStartup]")));
1885
1886 const CString key_path = AppendRegKeyPath(root_key_name, REGSTR_PATH_RUN);
1887 HRESULT hr(S_OK);
1888
1889 if (install) {
1890 hr = RegKey::SetValue(key_path, run_value_name, command);
1891 } else {
1892 hr = RegKey::DeleteValue(key_path, run_value_name);
1893 }
1894
1895 return hr;
1896 }
1897
1898 HRESULT GetExePathFromCommandLine(const TCHAR* command_line,
1899 CString* exe_path) {
1900 ASSERT1(exe_path);
1901 CString command_line_str(command_line);
1902 command_line_str.Trim(_T(' '));
1903 if (command_line_str.IsEmpty()) {
1904 // ::CommandLineToArgvW parses the current process command line for blank
1905 // strings. We do not want this behavior.
1906 return E_INVALIDARG;
1907 }
1908
1909 int argc = 0;
1910 wchar_t** argv = ::CommandLineToArgvW(command_line_str, &argc);
1911 if (argc == 0 || !argv) {
1912 HRESULT hr = HRESULTFromLastError();
1913 UTIL_LOG(LE, (_T("[::CommandLineToArgvW failed][0x%08x]"), hr));
1914 return hr;
1915 }
1916
1917 *exe_path = argv[0];
1918 ::LocalFree(argv);
1919 exe_path->Trim(_T(' '));
1920 ASSERT1(!exe_path->IsEmpty());
1921 return S_OK;
1922 }
1923
1924 // Tries to open the _MSIExecute mutex and tests its state. MSI sets the
1925 // mutex when processing sequence tables. This indicates MSI is busy.
1926 // The function returns S_OK if the mutex is not owned by MSI or the mutex has
1927 // not been created.
1928 HRESULT WaitForMSIExecute(int timeout_ms) {
1929 const TCHAR* mutex_name = _T("Global\\_MSIExecute");
1930 scoped_mutex mutex(::OpenMutex(SYNCHRONIZE, false, mutex_name));
1931 if (!mutex) {
1932 DWORD error = ::GetLastError();
1933 return (error == ERROR_FILE_NOT_FOUND) ? S_OK : HRESULT_FROM_WIN32(error);
1934 }
1935 UTIL_LOG(L3, (_T("[Wait for _MSIExecute]")));
1936 switch (::WaitForSingleObject(get(mutex), timeout_ms)) {
1937 case WAIT_OBJECT_0:
1938 case WAIT_ABANDONED:
1939 VERIFY1(::ReleaseMutex(get(mutex)));
1940 return S_OK;
1941 case WAIT_TIMEOUT:
1942 return HRESULT_FROM_WIN32(ERROR_TIMEOUT);
1943 case WAIT_FAILED:
1944 return HRESULTFromLastError();
1945 default:
1946 return E_FAIL;
1947 }
1948 }
1949
1950 CString GetEnvironmentVariableAsString(const TCHAR* name) {
1951 CString value;
1952 size_t value_length = ::GetEnvironmentVariable(name, NULL, 0);
1953 if (value_length) {
1954 VERIFY1(::GetEnvironmentVariable(name,
1955 CStrBuf(value, value_length),
1956 value_length));
1957 }
1958 return value;
1959 }
1960
1961 // States are documented at
1962 // http://technet.microsoft.com/en-us/library/cc721913.aspx.
1963 bool IsWindowsInstalling() {
1964 static const TCHAR kVistaSetupStateKey[] =
1965 _T("Software\\Microsoft\\Windows\\CurrentVersion\\Setup\\State");
1966 static const TCHAR kImageStateValueName[] = _T("ImageState");
1967 static const TCHAR kImageStateUnuseableValue[] =
1968 _T("IMAGE_STATE_UNDEPLOYABLE");
1969 static const TCHAR kImageStateGeneralAuditValue[] =
1970 _T("IMAGE_STATE_GENERALIZE_RESEAL_TO_AUDIT");
1971 static const TCHAR kImageStateSpecialAuditValue[] =
1972 _T("IMAGE_STATE_SPECIALIZE_RESEAL_TO_AUDIT");
1973
1974 static const TCHAR kXPSetupStateKey[] = _T("System\\Setup");
1975 static const TCHAR kAuditFlagValueName[] = _T("AuditInProgress");
1976
1977 if (vista_util::IsVistaOrLater()) {
1978 RegKey vista_setup_key;
1979 HRESULT hr =
1980 vista_setup_key.Open(HKEY_LOCAL_MACHINE, kVistaSetupStateKey, KEY_READ);
1981 if (SUCCEEDED(hr)) {
1982 CString state;
1983 hr = vista_setup_key.GetValue(kImageStateValueName, &state);
1984 if (SUCCEEDED(hr) &&
1985 !state.IsEmpty() &&
1986 (0 == state.CompareNoCase(kImageStateUnuseableValue) ||
1987 0 == state.CompareNoCase(kImageStateGeneralAuditValue) ||
1988 0 == state.CompareNoCase(kImageStateSpecialAuditValue)))
1989 return true; // Vista is still installing.
1990 }
1991 } else {
1992 RegKey xp_setup_key;
1993 HRESULT hr =
1994 xp_setup_key.Open(HKEY_LOCAL_MACHINE, kXPSetupStateKey, KEY_READ);
1995 if (SUCCEEDED(hr)) {
1996 DWORD audit_flag(0);
1997 hr = xp_setup_key.GetValue(kAuditFlagValueName, &audit_flag);
1998 if (SUCCEEDED(hr) && 0 != audit_flag)
1999 return true; // XP is still installing.
2000 }
2001 }
2002 return false;
2003 }
2004
2005 HRESULT GetGuid(CString* guid) {
2006 GUID guid_local = {0};
2007 HRESULT hr = ::CoCreateGuid(&guid_local);
2008 if (FAILED(hr)) {
2009 return hr;
2010 }
2011 *guid = GuidToString(guid_local);
2012 return S_OK;
2013 }
2014
2015 CString GetMessageForSystemErrorCode(DWORD error_code) {
2016 CORE_LOG(L3, (_T("[GetMessageForSystemErrorCode][%u]"), error_code));
2017
2018 TCHAR* system_allocated_buffer = NULL;
2019 const DWORD kFormatOptions = FORMAT_MESSAGE_ALLOCATE_BUFFER |
2020 FORMAT_MESSAGE_FROM_SYSTEM |
2021 FORMAT_MESSAGE_IGNORE_INSERTS |
2022 FORMAT_MESSAGE_MAX_WIDTH_MASK;
2023 DWORD tchars_written = ::FormatMessage(
2024 kFormatOptions,
2025 NULL,
2026 error_code,
2027 0,
2028 reinterpret_cast<LPWSTR>(&system_allocated_buffer),
2029 0,
2030 NULL);
2031
2032 CString message;
2033 if (tchars_written > 0) {
2034 message = system_allocated_buffer;
2035 } else {
2036 UTIL_LOG(LW, (_T("[::FormatMessage failed][%u]"), ::GetLastError()));
2037 }
2038
2039 VERIFY1(!::LocalFree(system_allocated_buffer));
2040
2041 return message;
2042 }
2043
2044 } // namespace omaha
OLDNEW
« no previous file with comments | « base/utils.h ('k') | base/utils_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698