OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/test/test_file_util.h" | 5 #include "base/test/test_file_util.h" |
6 | 6 |
7 #include <aclapi.h> | 7 #include <aclapi.h> |
8 #include <shlwapi.h> | 8 #include <shlwapi.h> |
9 #include <windows.h> | 9 #include <windows.h> |
| 10 #include <shlobj.h> |
| 11 #include <propkey.h> |
| 12 #include <propvarutil.h> |
10 | 13 |
11 #include <vector> | 14 #include <vector> |
12 | 15 |
13 #include "base/file_path.h" | 16 #include "base/file_path.h" |
14 #include "base/file_util.h" | 17 #include "base/file_util.h" |
15 #include "base/logging.h" | 18 #include "base/logging.h" |
16 #include "base/string_split.h" | 19 #include "base/string_split.h" |
| 20 #include "base/win/scoped_comptr.h" |
17 #include "base/win/scoped_handle.h" | 21 #include "base/win/scoped_handle.h" |
| 22 #include "base/win/windows_version.h" |
18 #include "base/threading/platform_thread.h" | 23 #include "base/threading/platform_thread.h" |
19 | 24 |
| 25 // propsys.lib is required for PropvariantTo*(). |
| 26 #pragma comment(lib, "propsys.lib") |
| 27 |
20 namespace file_util { | 28 namespace file_util { |
21 | 29 |
22 static const ptrdiff_t kOneMB = 1024 * 1024; | 30 static const ptrdiff_t kOneMB = 1024 * 1024; |
23 | 31 |
24 namespace { | 32 namespace { |
25 | 33 |
26 struct PermissionInfo { | 34 struct PermissionInfo { |
27 PSECURITY_DESCRIPTOR security_descriptor; | 35 PSECURITY_DESCRIPTOR security_descriptor; |
28 ACL dacl; | 36 ACL dacl; |
29 }; | 37 }; |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
103 SE_FILE_OBJECT, DACL_SECURITY_INFORMATION, | 111 SE_FILE_OBJECT, DACL_SECURITY_INFORMATION, |
104 NULL, NULL, &perm->dacl, NULL); | 112 NULL, NULL, &perm->dacl, NULL); |
105 LocalFree(perm->security_descriptor); | 113 LocalFree(perm->security_descriptor); |
106 | 114 |
107 char* char_array = reinterpret_cast<char*>(info); | 115 char* char_array = reinterpret_cast<char*>(info); |
108 delete [] char_array; | 116 delete [] char_array; |
109 | 117 |
110 return rc == ERROR_SUCCESS; | 118 return rc == ERROR_SUCCESS; |
111 } | 119 } |
112 | 120 |
| 121 // Returns true if |actual_path|'s LongPathName case-insensitively matches |
| 122 // |expected_path|'s LongPathName. |
| 123 bool PathsAreEqual(const string16& expected_path, const string16& actual_path) { |
| 124 wchar_t long_expected_path_chars[MAX_PATH] = {0}; |
| 125 wchar_t long_actual_path_chars[MAX_PATH] = {0}; |
| 126 |
| 127 if (::GetLongPathName( |
| 128 expected_path.c_str(), long_expected_path_chars, MAX_PATH) == 0 || |
| 129 ::GetLongPathName( |
| 130 actual_path.c_str(), long_actual_path_chars, MAX_PATH) == 0) { |
| 131 return false; |
| 132 } |
| 133 |
| 134 FilePath long_expected_path(long_expected_path_chars); |
| 135 FilePath long_actual_path(long_actual_path_chars); |
| 136 if(long_expected_path.empty() || long_actual_path.empty()) |
| 137 return false; |
| 138 |
| 139 return long_expected_path == long_actual_path; |
| 140 } |
| 141 |
113 } // namespace | 142 } // namespace |
114 | 143 |
115 bool DieFileDie(const FilePath& file, bool recurse) { | 144 bool DieFileDie(const FilePath& file, bool recurse) { |
116 // It turns out that to not induce flakiness a long timeout is needed. | 145 // It turns out that to not induce flakiness a long timeout is needed. |
117 const int kIterations = 25; | 146 const int kIterations = 25; |
118 const base::TimeDelta kTimeout = base::TimeDelta::FromSeconds(10) / | 147 const base::TimeDelta kTimeout = base::TimeDelta::FromSeconds(10) / |
119 kIterations; | 148 kIterations; |
120 | 149 |
121 if (!file_util::PathExists(file)) | 150 if (!file_util::PathExists(file)) |
122 return true; | 151 return true; |
(...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
261 // This will prevent us from evicting from the cache, but these don't | 290 // This will prevent us from evicting from the cache, but these don't |
262 // matter anyway. | 291 // matter anyway. |
263 EvictFileFromSystemCache(cur_dest_path); | 292 EvictFileFromSystemCache(cur_dest_path); |
264 } | 293 } |
265 } while (FindNextFile(fh, &fd)); | 294 } while (FindNextFile(fh, &fd)); |
266 | 295 |
267 FindClose(fh); | 296 FindClose(fh); |
268 return true; | 297 return true; |
269 } | 298 } |
270 | 299 |
| 300 VerifyShortcutStatus VerifyShortcut(const string16& shortcut_path, |
| 301 const ShortcutProperties& properties) { |
| 302 base::win::ScopedComPtr<IShellLink> i_shell_link; |
| 303 base::win::ScopedComPtr<IPersistFile> i_persist_file; |
| 304 |
| 305 wchar_t read_target[MAX_PATH] = {0}; |
| 306 wchar_t read_working_dir[MAX_PATH] = {0}; |
| 307 wchar_t read_arguments[MAX_PATH] = {0}; |
| 308 wchar_t read_description[MAX_PATH] = {0}; |
| 309 wchar_t read_icon[MAX_PATH] = {0}; |
| 310 int read_icon_index = 0; |
| 311 |
| 312 // Initialize the shell interfaces. |
| 313 if (FAILED(i_shell_link.CreateInstance(CLSID_ShellLink, NULL, |
| 314 CLSCTX_INPROC_SERVER)) || |
| 315 FAILED(i_persist_file.QueryFrom(i_shell_link))) { |
| 316 return VERIFY_SHORTCUT_FAILURE_UNEXPECTED; |
| 317 } |
| 318 |
| 319 // Load the shortcut. |
| 320 if (FAILED(i_persist_file->Load(shortcut_path.c_str(), 0))) |
| 321 return VERIFY_SHORTCUT_FAILURE_FILE_NOT_FOUND; |
| 322 |
| 323 if ((properties.options & ShortcutProperties::PROPERTIES_TARGET) && |
| 324 (FAILED(i_shell_link->GetPath( |
| 325 read_target, MAX_PATH, NULL, SLGP_SHORTPATH)) || |
| 326 !PathsAreEqual(properties.target, read_target))) { |
| 327 return VERIFY_SHORTCUT_FAILURE_TARGET; |
| 328 } |
| 329 |
| 330 if ((properties.options & ShortcutProperties::PROPERTIES_WORKING_DIR) && |
| 331 (FAILED(i_shell_link->GetWorkingDirectory(read_working_dir, MAX_PATH)) || |
| 332 string16(read_working_dir) != properties.working_dir)) { |
| 333 return VERIFY_SHORTCUT_FAILURE_WORKING_DIR; |
| 334 } |
| 335 |
| 336 if ((properties.options & ShortcutProperties::PROPERTIES_ARGUMENTS) && |
| 337 (FAILED(i_shell_link->GetArguments(read_arguments, MAX_PATH)) || |
| 338 string16(read_arguments) != properties.arguments)) { |
| 339 return VERIFY_SHORTCUT_FAILURE_ARGUMENTS; |
| 340 } |
| 341 |
| 342 if ((properties.options & ShortcutProperties::PROPERTIES_DESCRIPTION) && |
| 343 (FAILED(i_shell_link->GetDescription(read_description, MAX_PATH)) || |
| 344 string16(read_description) != properties.description)) { |
| 345 return VERIFY_SHORTCUT_FAILURE_DESCRIPTION; |
| 346 } |
| 347 |
| 348 if ((properties.options & ShortcutProperties::PROPERTIES_ICON) && |
| 349 (FAILED(i_shell_link->GetIconLocation(read_icon, MAX_PATH, |
| 350 &read_icon_index)) || |
| 351 read_icon_index != properties.icon_index || |
| 352 !PathsAreEqual(properties.icon, read_icon))) { |
| 353 return VERIFY_SHORTCUT_FAILURE_ICON; |
| 354 } |
| 355 |
| 356 if(base::win::GetVersion() >= base::win::VERSION_WIN7) { |
| 357 base::win::ScopedComPtr<IPropertyStore> property_store; |
| 358 // Note that, as mentioned on MSDN at http://goo.gl/M8h9g, if a property is |
| 359 // not set, GetValue will return S_OK and the PROPVARIANT will be set to |
| 360 // VT_EMPTY. |
| 361 PROPVARIANT pv_app_id, pv_dual_mode; |
| 362 if (FAILED(property_store.QueryFrom(i_shell_link)) || |
| 363 property_store->GetValue(PKEY_AppUserModel_ID, &pv_app_id) != S_OK || |
| 364 property_store->GetValue(PKEY_AppUserModel_IsDualMode, |
| 365 &pv_dual_mode) != S_OK) { |
| 366 return VERIFY_SHORTCUT_FAILURE_UNEXPECTED; |
| 367 } |
| 368 |
| 369 // Note, as mentioned on MSDN at http://goo.gl/hZ3sO, if |pv_app_id| is a |
| 370 // VT_EMPTY it is successfully converted to the empty string. |
| 371 wchar_t read_app_id[MAX_PATH] = {0}; |
| 372 PropVariantToString(pv_app_id, read_app_id, MAX_PATH); |
| 373 if((properties.options & ShortcutProperties::PROPERTIES_APP_ID) && |
| 374 string16(read_app_id) != properties.app_id) { |
| 375 return VERIFY_SHORTCUT_FAILURE_APP_ID; |
| 376 } |
| 377 |
| 378 // Note, as mentioned on MSDN at http://goo.gl/9mBHB, if |pv_dual_mode| is a |
| 379 // VT_EMPTY it is successfully converted to false. |
| 380 BOOL read_dual_mode; |
| 381 PropVariantToBoolean(pv_dual_mode, &read_dual_mode); |
| 382 if((properties.options & ShortcutProperties::PROPERTIES_DUAL_MODE) && |
| 383 static_cast<bool>(read_dual_mode) != properties.dual_mode) { |
| 384 return VERIFY_SHORTCUT_FAILURE_DUAL_MODE; |
| 385 } |
| 386 } |
| 387 |
| 388 return VERIFY_SHORTCUT_SUCCESS; |
| 389 } |
| 390 |
271 // Checks if the volume supports Alternate Data Streams. This is required for | 391 // Checks if the volume supports Alternate Data Streams. This is required for |
272 // the Zone Identifier implementation. | 392 // the Zone Identifier implementation. |
273 bool VolumeSupportsADS(const FilePath& path) { | 393 bool VolumeSupportsADS(const FilePath& path) { |
274 wchar_t drive[MAX_PATH] = {0}; | 394 wchar_t drive[MAX_PATH] = {0}; |
275 wcscpy_s(drive, MAX_PATH, path.value().c_str()); | 395 wcscpy_s(drive, MAX_PATH, path.value().c_str()); |
276 | 396 |
277 if (!PathStripToRootW(drive)) | 397 if (!PathStripToRootW(drive)) |
278 return false; | 398 return false; |
279 | 399 |
280 DWORD fs_flags = 0; | 400 DWORD fs_flags = 0; |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
334 DCHECK(info_ != NULL); | 454 DCHECK(info_ != NULL); |
335 DCHECK_NE(0u, length_); | 455 DCHECK_NE(0u, length_); |
336 } | 456 } |
337 | 457 |
338 PermissionRestorer::~PermissionRestorer() { | 458 PermissionRestorer::~PermissionRestorer() { |
339 if (!RestorePermissionInfo(path_, info_, length_)) | 459 if (!RestorePermissionInfo(path_, info_, length_)) |
340 NOTREACHED(); | 460 NOTREACHED(); |
341 } | 461 } |
342 | 462 |
343 } // namespace file_util | 463 } // namespace file_util |
OLD | NEW |