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 | 10 |
(...skipping 11 matching lines...) Expand all Loading... |
22 static const ptrdiff_t kOneMB = 1024 * 1024; | 22 static const ptrdiff_t kOneMB = 1024 * 1024; |
23 | 23 |
24 namespace { | 24 namespace { |
25 | 25 |
26 struct PermissionInfo { | 26 struct PermissionInfo { |
27 PSECURITY_DESCRIPTOR security_descriptor; | 27 PSECURITY_DESCRIPTOR security_descriptor; |
28 ACL dacl; | 28 ACL dacl; |
29 }; | 29 }; |
30 | 30 |
31 // Deny |permission| on the file |path|, for the current user. | 31 // Deny |permission| on the file |path|, for the current user. |
32 bool DenyFilePermission(const FilePath& path, DWORD permission) { | 32 bool DenyFilePermission(const base::FilePath& path, DWORD permission) { |
33 PACL old_dacl; | 33 PACL old_dacl; |
34 PSECURITY_DESCRIPTOR security_descriptor; | 34 PSECURITY_DESCRIPTOR security_descriptor; |
35 if (GetNamedSecurityInfo(const_cast<wchar_t*>(path.value().c_str()), | 35 if (GetNamedSecurityInfo(const_cast<wchar_t*>(path.value().c_str()), |
36 SE_FILE_OBJECT, | 36 SE_FILE_OBJECT, |
37 DACL_SECURITY_INFORMATION, NULL, NULL, &old_dacl, | 37 DACL_SECURITY_INFORMATION, NULL, NULL, &old_dacl, |
38 NULL, &security_descriptor) != ERROR_SUCCESS) { | 38 NULL, &security_descriptor) != ERROR_SUCCESS) { |
39 return false; | 39 return false; |
40 } | 40 } |
41 | 41 |
42 EXPLICIT_ACCESS change; | 42 EXPLICIT_ACCESS change; |
(...skipping 17 matching lines...) Expand all Loading... |
60 NULL, NULL, new_dacl, NULL); | 60 NULL, NULL, new_dacl, NULL); |
61 LocalFree(security_descriptor); | 61 LocalFree(security_descriptor); |
62 LocalFree(new_dacl); | 62 LocalFree(new_dacl); |
63 | 63 |
64 return rc == ERROR_SUCCESS; | 64 return rc == ERROR_SUCCESS; |
65 } | 65 } |
66 | 66 |
67 // Gets a blob indicating the permission information for |path|. | 67 // Gets a blob indicating the permission information for |path|. |
68 // |length| is the length of the blob. Zero on failure. | 68 // |length| is the length of the blob. Zero on failure. |
69 // Returns the blob pointer, or NULL on failure. | 69 // Returns the blob pointer, or NULL on failure. |
70 void* GetPermissionInfo(const FilePath& path, size_t* length) { | 70 void* GetPermissionInfo(const base::FilePath& path, size_t* length) { |
71 DCHECK(length != NULL); | 71 DCHECK(length != NULL); |
72 *length = 0; | 72 *length = 0; |
73 PACL dacl = NULL; | 73 PACL dacl = NULL; |
74 PSECURITY_DESCRIPTOR security_descriptor; | 74 PSECURITY_DESCRIPTOR security_descriptor; |
75 if (GetNamedSecurityInfo(const_cast<wchar_t*>(path.value().c_str()), | 75 if (GetNamedSecurityInfo(const_cast<wchar_t*>(path.value().c_str()), |
76 SE_FILE_OBJECT, | 76 SE_FILE_OBJECT, |
77 DACL_SECURITY_INFORMATION, NULL, NULL, &dacl, | 77 DACL_SECURITY_INFORMATION, NULL, NULL, &dacl, |
78 NULL, &security_descriptor) != ERROR_SUCCESS) { | 78 NULL, &security_descriptor) != ERROR_SUCCESS) { |
79 return NULL; | 79 return NULL; |
80 } | 80 } |
81 DCHECK(dacl != NULL); | 81 DCHECK(dacl != NULL); |
82 | 82 |
83 *length = sizeof(PSECURITY_DESCRIPTOR) + dacl->AclSize; | 83 *length = sizeof(PSECURITY_DESCRIPTOR) + dacl->AclSize; |
84 PermissionInfo* info = reinterpret_cast<PermissionInfo*>(new char[*length]); | 84 PermissionInfo* info = reinterpret_cast<PermissionInfo*>(new char[*length]); |
85 info->security_descriptor = security_descriptor; | 85 info->security_descriptor = security_descriptor; |
86 memcpy(&info->dacl, dacl, dacl->AclSize); | 86 memcpy(&info->dacl, dacl, dacl->AclSize); |
87 | 87 |
88 return info; | 88 return info; |
89 } | 89 } |
90 | 90 |
91 // Restores the permission information for |path|, given the blob retrieved | 91 // Restores the permission information for |path|, given the blob retrieved |
92 // using |GetPermissionInfo()|. | 92 // using |GetPermissionInfo()|. |
93 // |info| is the pointer to the blob. | 93 // |info| is the pointer to the blob. |
94 // |length| is the length of the blob. | 94 // |length| is the length of the blob. |
95 // Either |info| or |length| may be NULL/0, in which case nothing happens. | 95 // Either |info| or |length| may be NULL/0, in which case nothing happens. |
96 bool RestorePermissionInfo(const FilePath& path, void* info, size_t length) { | 96 bool RestorePermissionInfo(const base::FilePath& path, |
| 97 void* info, size_t length) { |
97 if (!info || !length) | 98 if (!info || !length) |
98 return false; | 99 return false; |
99 | 100 |
100 PermissionInfo* perm = reinterpret_cast<PermissionInfo*>(info); | 101 PermissionInfo* perm = reinterpret_cast<PermissionInfo*>(info); |
101 | 102 |
102 DWORD rc = SetNamedSecurityInfo(const_cast<wchar_t*>(path.value().c_str()), | 103 DWORD rc = SetNamedSecurityInfo(const_cast<wchar_t*>(path.value().c_str()), |
103 SE_FILE_OBJECT, DACL_SECURITY_INFORMATION, | 104 SE_FILE_OBJECT, DACL_SECURITY_INFORMATION, |
104 NULL, NULL, &perm->dacl, NULL); | 105 NULL, NULL, &perm->dacl, NULL); |
105 LocalFree(perm->security_descriptor); | 106 LocalFree(perm->security_descriptor); |
106 | 107 |
107 char* char_array = reinterpret_cast<char*>(info); | 108 char* char_array = reinterpret_cast<char*>(info); |
108 delete [] char_array; | 109 delete [] char_array; |
109 | 110 |
110 return rc == ERROR_SUCCESS; | 111 return rc == ERROR_SUCCESS; |
111 } | 112 } |
112 | 113 |
113 } // namespace | 114 } // namespace |
114 | 115 |
115 bool DieFileDie(const FilePath& file, bool recurse) { | 116 bool DieFileDie(const base::FilePath& file, bool recurse) { |
116 // It turns out that to not induce flakiness a long timeout is needed. | 117 // It turns out that to not induce flakiness a long timeout is needed. |
117 const int kIterations = 25; | 118 const int kIterations = 25; |
118 const base::TimeDelta kTimeout = base::TimeDelta::FromSeconds(10) / | 119 const base::TimeDelta kTimeout = base::TimeDelta::FromSeconds(10) / |
119 kIterations; | 120 kIterations; |
120 | 121 |
121 if (!file_util::PathExists(file)) | 122 if (!file_util::PathExists(file)) |
122 return true; | 123 return true; |
123 | 124 |
124 // Sometimes Delete fails, so try a few more times. Divide the timeout | 125 // Sometimes Delete fails, so try a few more times. Divide the timeout |
125 // into short chunks, so that if a try succeeds, we won't delay the test | 126 // into short chunks, so that if a try succeeds, we won't delay the test |
126 // for too long. | 127 // for too long. |
127 for (int i = 0; i < kIterations; ++i) { | 128 for (int i = 0; i < kIterations; ++i) { |
128 if (file_util::Delete(file, recurse)) | 129 if (file_util::Delete(file, recurse)) |
129 return true; | 130 return true; |
130 base::PlatformThread::Sleep(kTimeout); | 131 base::PlatformThread::Sleep(kTimeout); |
131 } | 132 } |
132 return false; | 133 return false; |
133 } | 134 } |
134 | 135 |
135 bool EvictFileFromSystemCache(const FilePath& file) { | 136 bool EvictFileFromSystemCache(const base::FilePath& file) { |
136 // Request exclusive access to the file and overwrite it with no buffering. | 137 // Request exclusive access to the file and overwrite it with no buffering. |
137 base::win::ScopedHandle file_handle( | 138 base::win::ScopedHandle file_handle( |
138 CreateFile(file.value().c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL, | 139 CreateFile(file.value().c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL, |
139 OPEN_EXISTING, FILE_FLAG_NO_BUFFERING, NULL)); | 140 OPEN_EXISTING, FILE_FLAG_NO_BUFFERING, NULL)); |
140 if (!file_handle) | 141 if (!file_handle) |
141 return false; | 142 return false; |
142 | 143 |
143 // Get some attributes to restore later. | 144 // Get some attributes to restore later. |
144 BY_HANDLE_FILE_INFORMATION bhi = {0}; | 145 BY_HANDLE_FILE_INFORMATION bhi = {0}; |
145 CHECK(::GetFileInformationByHandle(file_handle, &bhi)); | 146 CHECK(::GetFileInformationByHandle(file_handle, &bhi)); |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
210 | 211 |
211 // Restore the file attributes. | 212 // Restore the file attributes. |
212 CHECK(::SetFileTime(file_handle, &bhi.ftCreationTime, &bhi.ftLastAccessTime, | 213 CHECK(::SetFileTime(file_handle, &bhi.ftCreationTime, &bhi.ftLastAccessTime, |
213 &bhi.ftLastWriteTime)); | 214 &bhi.ftLastWriteTime)); |
214 | 215 |
215 return true; | 216 return true; |
216 } | 217 } |
217 | 218 |
218 // Like CopyFileNoCache but recursively copies all files and subdirectories | 219 // Like CopyFileNoCache but recursively copies all files and subdirectories |
219 // in the given input directory to the output directory. | 220 // in the given input directory to the output directory. |
220 bool CopyRecursiveDirNoCache(const FilePath& source_dir, | 221 bool CopyRecursiveDirNoCache(const base::FilePath& source_dir, |
221 const FilePath& dest_dir) { | 222 const base::FilePath& dest_dir) { |
222 // Try to create the directory if it doesn't already exist. | 223 // Try to create the directory if it doesn't already exist. |
223 if (!CreateDirectory(dest_dir)) { | 224 if (!CreateDirectory(dest_dir)) { |
224 if (GetLastError() != ERROR_ALREADY_EXISTS) | 225 if (GetLastError() != ERROR_ALREADY_EXISTS) |
225 return false; | 226 return false; |
226 } | 227 } |
227 | 228 |
228 std::vector<std::wstring> files_copied; | 229 std::vector<std::wstring> files_copied; |
229 | 230 |
230 FilePath src(source_dir.AppendASCII("*")); | 231 base::FilePath src(source_dir.AppendASCII("*")); |
231 | 232 |
232 WIN32_FIND_DATA fd; | 233 WIN32_FIND_DATA fd; |
233 HANDLE fh = FindFirstFile(src.value().c_str(), &fd); | 234 HANDLE fh = FindFirstFile(src.value().c_str(), &fd); |
234 if (fh == INVALID_HANDLE_VALUE) | 235 if (fh == INVALID_HANDLE_VALUE) |
235 return false; | 236 return false; |
236 | 237 |
237 do { | 238 do { |
238 std::wstring cur_file(fd.cFileName); | 239 std::wstring cur_file(fd.cFileName); |
239 if (cur_file == L"." || cur_file == L"..") | 240 if (cur_file == L"." || cur_file == L"..") |
240 continue; // Skip these special entries. | 241 continue; // Skip these special entries. |
241 | 242 |
242 FilePath cur_source_path = source_dir.Append(cur_file); | 243 base::FilePath cur_source_path = source_dir.Append(cur_file); |
243 FilePath cur_dest_path = dest_dir.Append(cur_file); | 244 base::FilePath cur_dest_path = dest_dir.Append(cur_file); |
244 | 245 |
245 if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { | 246 if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { |
246 // Recursively copy a subdirectory. We stripped "." and ".." already. | 247 // Recursively copy a subdirectory. We stripped "." and ".." already. |
247 if (!CopyRecursiveDirNoCache(cur_source_path, cur_dest_path)) { | 248 if (!CopyRecursiveDirNoCache(cur_source_path, cur_dest_path)) { |
248 FindClose(fh); | 249 FindClose(fh); |
249 return false; | 250 return false; |
250 } | 251 } |
251 } else { | 252 } else { |
252 // Copy the file. | 253 // Copy the file. |
253 if (!::CopyFile(cur_source_path.value().c_str(), | 254 if (!::CopyFile(cur_source_path.value().c_str(), |
254 cur_dest_path.value().c_str(), false)) { | 255 cur_dest_path.value().c_str(), false)) { |
255 FindClose(fh); | 256 FindClose(fh); |
256 return false; | 257 return false; |
257 } | 258 } |
258 | 259 |
259 // We don't check for errors from this function, often, we are copying | 260 // We don't check for errors from this function, often, we are copying |
260 // files that are in the repository, and they will have read-only set. | 261 // files that are in the repository, and they will have read-only set. |
261 // This will prevent us from evicting from the cache, but these don't | 262 // This will prevent us from evicting from the cache, but these don't |
262 // matter anyway. | 263 // matter anyway. |
263 EvictFileFromSystemCache(cur_dest_path); | 264 EvictFileFromSystemCache(cur_dest_path); |
264 } | 265 } |
265 } while (FindNextFile(fh, &fd)); | 266 } while (FindNextFile(fh, &fd)); |
266 | 267 |
267 FindClose(fh); | 268 FindClose(fh); |
268 return true; | 269 return true; |
269 } | 270 } |
270 | 271 |
271 // Checks if the volume supports Alternate Data Streams. This is required for | 272 // Checks if the volume supports Alternate Data Streams. This is required for |
272 // the Zone Identifier implementation. | 273 // the Zone Identifier implementation. |
273 bool VolumeSupportsADS(const FilePath& path) { | 274 bool VolumeSupportsADS(const base::FilePath& path) { |
274 wchar_t drive[MAX_PATH] = {0}; | 275 wchar_t drive[MAX_PATH] = {0}; |
275 wcscpy_s(drive, MAX_PATH, path.value().c_str()); | 276 wcscpy_s(drive, MAX_PATH, path.value().c_str()); |
276 | 277 |
277 if (!PathStripToRootW(drive)) | 278 if (!PathStripToRootW(drive)) |
278 return false; | 279 return false; |
279 | 280 |
280 DWORD fs_flags = 0; | 281 DWORD fs_flags = 0; |
281 if (!GetVolumeInformationW(drive, NULL, 0, 0, NULL, &fs_flags, NULL, 0)) | 282 if (!GetVolumeInformationW(drive, NULL, 0, 0, NULL, &fs_flags, NULL, 0)) |
282 return false; | 283 return false; |
283 | 284 |
284 if (fs_flags & FILE_NAMED_STREAMS) | 285 if (fs_flags & FILE_NAMED_STREAMS) |
285 return true; | 286 return true; |
286 | 287 |
287 return false; | 288 return false; |
288 } | 289 } |
289 | 290 |
290 // Return whether the ZoneIdentifier is correctly set to "Internet" (3) | 291 // Return whether the ZoneIdentifier is correctly set to "Internet" (3) |
291 // Only returns a valid result when called from same process as the | 292 // Only returns a valid result when called from same process as the |
292 // one that (was supposed to have) set the zone identifier. | 293 // one that (was supposed to have) set the zone identifier. |
293 bool HasInternetZoneIdentifier(const FilePath& full_path) { | 294 bool HasInternetZoneIdentifier(const base::FilePath& full_path) { |
294 FilePath zone_path(full_path.value() + L":Zone.Identifier"); | 295 base::FilePath zone_path(full_path.value() + L":Zone.Identifier"); |
295 std::string zone_path_contents; | 296 std::string zone_path_contents; |
296 if (!file_util::ReadFileToString(zone_path, &zone_path_contents)) | 297 if (!file_util::ReadFileToString(zone_path, &zone_path_contents)) |
297 return false; | 298 return false; |
298 | 299 |
299 std::vector<std::string> lines; | 300 std::vector<std::string> lines; |
300 // This call also trims whitespaces, including carriage-returns (\r). | 301 // This call also trims whitespaces, including carriage-returns (\r). |
301 base::SplitString(zone_path_contents, '\n', &lines); | 302 base::SplitString(zone_path_contents, '\n', &lines); |
302 | 303 |
303 switch (lines.size()) { | 304 switch (lines.size()) { |
304 case 3: | 305 case 3: |
305 // optional empty line at end of file: | 306 // optional empty line at end of file: |
306 if (lines[2] != "") | 307 if (lines[2] != "") |
307 return false; | 308 return false; |
308 // fall through: | 309 // fall through: |
309 case 2: | 310 case 2: |
310 return lines[0] == "[ZoneTransfer]" && lines[1] == "ZoneId=3"; | 311 return lines[0] == "[ZoneTransfer]" && lines[1] == "ZoneId=3"; |
311 default: | 312 default: |
312 return false; | 313 return false; |
313 } | 314 } |
314 } | 315 } |
315 | 316 |
316 std::wstring FilePathAsWString(const FilePath& path) { | 317 std::wstring FilePathAsWString(const base::FilePath& path) { |
317 return path.value(); | 318 return path.value(); |
318 } | 319 } |
319 FilePath WStringAsFilePath(const std::wstring& path) { | 320 base::FilePath WStringAsFilePath(const std::wstring& path) { |
320 return FilePath(path); | 321 return base::FilePath(path); |
321 } | 322 } |
322 | 323 |
323 bool MakeFileUnreadable(const FilePath& path) { | 324 bool MakeFileUnreadable(const base::FilePath& path) { |
324 return DenyFilePermission(path, GENERIC_READ); | 325 return DenyFilePermission(path, GENERIC_READ); |
325 } | 326 } |
326 | 327 |
327 bool MakeFileUnwritable(const FilePath& path) { | 328 bool MakeFileUnwritable(const base::FilePath& path) { |
328 return DenyFilePermission(path, GENERIC_WRITE); | 329 return DenyFilePermission(path, GENERIC_WRITE); |
329 } | 330 } |
330 | 331 |
331 PermissionRestorer::PermissionRestorer(const FilePath& path) | 332 PermissionRestorer::PermissionRestorer(const base::FilePath& path) |
332 : path_(path), info_(NULL), length_(0) { | 333 : path_(path), info_(NULL), length_(0) { |
333 info_ = GetPermissionInfo(path_, &length_); | 334 info_ = GetPermissionInfo(path_, &length_); |
334 DCHECK(info_ != NULL); | 335 DCHECK(info_ != NULL); |
335 DCHECK_NE(0u, length_); | 336 DCHECK_NE(0u, length_); |
336 } | 337 } |
337 | 338 |
338 PermissionRestorer::~PermissionRestorer() { | 339 PermissionRestorer::~PermissionRestorer() { |
339 if (!RestorePermissionInfo(path_, info_, length_)) | 340 if (!RestorePermissionInfo(path_, info_, length_)) |
340 NOTREACHED(); | 341 NOTREACHED(); |
341 } | 342 } |
342 | 343 |
343 } // namespace file_util | 344 } // namespace file_util |
OLD | NEW |