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

Side by Side Diff: base/test/test_file_util_win.cc

Issue 10914109: Refactoring and tests for the highly undertested file_util::CreateOrUpdateShortcutLink() method. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: better path matching Created 8 years, 3 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 | Annotate | Revision Log
OLDNEW
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
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
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
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
OLDNEW
« base/file_util.h ('K') | « base/test/test_file_util.h ('k') | base/win/win_util.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698