OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 #include "platform/globals.h" | 5 #include "platform/globals.h" |
6 #if defined(TARGET_OS_WINDOWS) | 6 #if defined(TARGET_OS_WINDOWS) |
7 | 7 |
8 #include "bin/directory.h" | 8 #include "bin/directory.h" |
| 9 #include "bin/file.h" |
9 | 10 |
10 #include <errno.h> // NOLINT | 11 #include <errno.h> // NOLINT |
11 #include <sys/stat.h> // NOLINT | 12 #include <sys/stat.h> // NOLINT |
12 | 13 |
13 #include "bin/log.h" | 14 #include "bin/log.h" |
14 | 15 |
15 class PathBuffer { | 16 class PathBuffer { |
16 public: | 17 public: |
17 PathBuffer() : length(0) { | 18 PathBuffer() : length(0) { |
18 data = new wchar_t[MAX_PATH + 1]; | 19 data = new wchar_t[MAX_PATH + 1]; |
(...skipping 22 matching lines...) Expand all Loading... |
41 return false; | 42 return false; |
42 } | 43 } |
43 } | 44 } |
44 | 45 |
45 void Reset(int new_length) { | 46 void Reset(int new_length) { |
46 length = new_length; | 47 length = new_length; |
47 data[length] = L'\0'; | 48 data[length] = L'\0'; |
48 } | 49 } |
49 }; | 50 }; |
50 | 51 |
| 52 // If link_name points to a link, IsBrokenLink will return true if link_name |
| 53 // points to an invalid target. |
| 54 static bool IsBrokenLink(const wchar_t* link_name) { |
| 55 HANDLE handle = CreateFileW( |
| 56 link_name, |
| 57 0, |
| 58 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, |
| 59 NULL, |
| 60 OPEN_EXISTING, |
| 61 FILE_FLAG_BACKUP_SEMANTICS, |
| 62 NULL); |
| 63 if (handle == INVALID_HANDLE_VALUE) { |
| 64 return true; |
| 65 } else { |
| 66 CloseHandle(handle); |
| 67 return false; |
| 68 } |
| 69 } |
| 70 |
51 | 71 |
52 // Forward declarations. | 72 // Forward declarations. |
53 static bool ListRecursively(PathBuffer* path, | 73 static bool ListRecursively(PathBuffer* path, |
54 bool recursive, | 74 bool recursive, |
55 bool follow_links, | 75 bool follow_links, |
56 DirectoryListing* listing); | 76 DirectoryListing* listing); |
57 static bool DeleteRecursively(PathBuffer* path); | 77 static bool DeleteRecursively(PathBuffer* path); |
58 | 78 |
59 | 79 |
60 static void PostError(DirectoryListing* listing, | 80 static void PostError(DirectoryListing* listing, |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
115 static bool HandleEntry(LPWIN32_FIND_DATAW find_file_data, | 135 static bool HandleEntry(LPWIN32_FIND_DATAW find_file_data, |
116 PathBuffer* path, | 136 PathBuffer* path, |
117 bool recursive, | 137 bool recursive, |
118 bool follow_links, | 138 bool follow_links, |
119 DirectoryListing* listing) { | 139 DirectoryListing* listing) { |
120 DWORD attributes = find_file_data->dwFileAttributes; | 140 DWORD attributes = find_file_data->dwFileAttributes; |
121 if ((attributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0) { | 141 if ((attributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0) { |
122 if (!follow_links) { | 142 if (!follow_links) { |
123 return HandleLink(find_file_data->cFileName, path, listing); | 143 return HandleLink(find_file_data->cFileName, path, listing); |
124 } | 144 } |
125 // Attempt to list the directory, to see if it's a valid link or not. | |
126 int path_length = path->length; | 145 int path_length = path->length; |
127 if (!path->Add(find_file_data->cFileName)) return false; | 146 if (!path->Add(find_file_data->cFileName)) return false; |
128 if (!path->Add(L"\\*")) return false; | 147 bool broken = IsBrokenLink(path->data); |
129 WIN32_FIND_DATAW tmp_file_data; | |
130 HANDLE find_handle = FindFirstFileW(path->data, &tmp_file_data); | |
131 path->Reset(path_length); | 148 path->Reset(path_length); |
132 if (find_handle == INVALID_HANDLE_VALUE) { | 149 if (broken) { |
133 // Invalid handle, report as (broken) link. | 150 // Report as (broken) link. |
134 return HandleLink(find_file_data->cFileName, path, listing); | 151 return HandleLink(find_file_data->cFileName, path, listing); |
135 } else { | |
136 FindClose(find_handle); | |
137 } | 152 } |
138 } | 153 } |
139 if ((attributes & FILE_ATTRIBUTE_DIRECTORY) != 0) { | 154 if ((attributes & FILE_ATTRIBUTE_DIRECTORY) != 0) { |
140 return HandleDir(find_file_data->cFileName, | 155 return HandleDir(find_file_data->cFileName, |
141 path, | 156 path, |
142 recursive, | 157 recursive, |
143 follow_links, | 158 follow_links, |
144 listing); | 159 listing); |
145 } else { | 160 } else { |
146 return HandleFile(find_file_data->cFileName, path, listing); | 161 return HandleFile(find_file_data->cFileName, path, listing); |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
246 } | 261 } |
247 } | 262 } |
248 | 263 |
249 | 264 |
250 static bool DeleteRecursively(PathBuffer* path) { | 265 static bool DeleteRecursively(PathBuffer* path) { |
251 // If the directory is a junction, it's pointing to some other place in the | 266 // If the directory is a junction, it's pointing to some other place in the |
252 // filesystem that we do not want to recurse into. | 267 // filesystem that we do not want to recurse into. |
253 DWORD attributes = GetFileAttributesW(path->data); | 268 DWORD attributes = GetFileAttributesW(path->data); |
254 if ((attributes != INVALID_FILE_ATTRIBUTES) && | 269 if ((attributes != INVALID_FILE_ATTRIBUTES) && |
255 (attributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0) { | 270 (attributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0) { |
256 // Just delete the junction itself. | 271 if (IsBrokenLink(path->data)) { |
257 return RemoveDirectoryW(path->data) != 0; | 272 return false; |
| 273 } else { |
| 274 // Just delete the junction itself. |
| 275 return RemoveDirectoryW(path->data) != 0; |
| 276 } |
258 } | 277 } |
259 | 278 |
260 if (!path->Add(L"\\*")) return false; | 279 if (!path->Add(L"\\*")) return false; |
261 | 280 |
262 WIN32_FIND_DATAW find_file_data; | 281 WIN32_FIND_DATAW find_file_data; |
263 HANDLE find_handle = FindFirstFileW(path->data, &find_file_data); | 282 HANDLE find_handle = FindFirstFileW(path->data, &find_file_data); |
264 | 283 |
265 // Adjust the path by removing the '*' used for the search. | 284 // Adjust the path by removing the '*' used for the search. |
266 int path_length = path->length - 1; | 285 int path_length = path->length - 1; |
267 path->Reset(path_length); | 286 path->Reset(path_length); |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
311 last_error == ERROR_PATH_NOT_FOUND) { | 330 last_error == ERROR_PATH_NOT_FOUND) { |
312 return Directory::DOES_NOT_EXIST; | 331 return Directory::DOES_NOT_EXIST; |
313 } else { | 332 } else { |
314 // We might not be able to get the file attributes for other | 333 // We might not be able to get the file attributes for other |
315 // reasons such as lack of permissions. In that case we do | 334 // reasons such as lack of permissions. In that case we do |
316 // not know if the directory exists. | 335 // not know if the directory exists. |
317 return Directory::UNKNOWN; | 336 return Directory::UNKNOWN; |
318 } | 337 } |
319 } | 338 } |
320 bool exists = (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0; | 339 bool exists = (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0; |
| 340 exists = exists && !IsBrokenLink(dir_name); |
321 return exists ? Directory::EXISTS : Directory::DOES_NOT_EXIST; | 341 return exists ? Directory::EXISTS : Directory::DOES_NOT_EXIST; |
322 } | 342 } |
323 | 343 |
324 | 344 |
325 Directory::ExistsResult Directory::Exists(const char* dir_name) { | 345 Directory::ExistsResult Directory::Exists(const char* dir_name) { |
326 const wchar_t* system_name = StringUtils::Utf8ToWide(dir_name); | 346 const wchar_t* system_name = StringUtils::Utf8ToWide(dir_name); |
327 Directory::ExistsResult result = ExistsHelper(system_name); | 347 Directory::ExistsResult result = ExistsHelper(system_name); |
328 free(const_cast<wchar_t*>(system_name)); | 348 free(const_cast<wchar_t*>(system_name)); |
329 return result; | 349 return result; |
330 } | 350 } |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
400 } | 420 } |
401 char* result = StringUtils::WideToUtf8(path.data); | 421 char* result = StringUtils::WideToUtf8(path.data); |
402 return result; | 422 return result; |
403 } | 423 } |
404 | 424 |
405 | 425 |
406 bool Directory::Delete(const char* dir_name, bool recursive) { | 426 bool Directory::Delete(const char* dir_name, bool recursive) { |
407 bool result = false; | 427 bool result = false; |
408 const wchar_t* system_dir_name = StringUtils::Utf8ToWide(dir_name); | 428 const wchar_t* system_dir_name = StringUtils::Utf8ToWide(dir_name); |
409 if (!recursive) { | 429 if (!recursive) { |
410 result = (RemoveDirectoryW(system_dir_name) != 0); | 430 if (File::GetType(dir_name, true) == File::kIsDirectory) { |
| 431 result = (RemoveDirectoryW(system_dir_name) != 0); |
| 432 } else { |
| 433 SetLastError(ERROR_DIRECTORY); |
| 434 } |
411 } else { | 435 } else { |
412 PathBuffer path; | 436 PathBuffer path; |
413 if (!path.Add(system_dir_name)) { | 437 if (path.Add(system_dir_name)) { |
414 return false; | 438 result = DeleteRecursively(&path); |
415 } | 439 } |
416 result = DeleteRecursively(&path); | |
417 } | 440 } |
418 free(const_cast<wchar_t*>(system_dir_name)); | 441 free(const_cast<wchar_t*>(system_dir_name)); |
419 return result; | 442 return result; |
420 } | 443 } |
421 | 444 |
422 | 445 |
423 bool Directory::Rename(const char* path, const char* new_path) { | 446 bool Directory::Rename(const char* path, const char* new_path) { |
424 const wchar_t* system_path = StringUtils::Utf8ToWide(path); | 447 const wchar_t* system_path = StringUtils::Utf8ToWide(path); |
425 const wchar_t* system_new_path = StringUtils::Utf8ToWide(new_path); | 448 const wchar_t* system_new_path = StringUtils::Utf8ToWide(new_path); |
426 ExistsResult exists = ExistsHelper(system_path); | 449 ExistsResult exists = ExistsHelper(system_path); |
427 if (exists != EXISTS) return false; | 450 if (exists != EXISTS) return false; |
428 ExistsResult new_exists = ExistsHelper(system_new_path); | 451 ExistsResult new_exists = ExistsHelper(system_new_path); |
429 // MoveFile does not allow replacing exising directories. Therefore, | 452 // MoveFile does not allow replacing exising directories. Therefore, |
430 // if the new_path is currently a directory we need to delete it | 453 // if the new_path is currently a directory we need to delete it |
431 // first. | 454 // first. |
432 if (new_exists == EXISTS) { | 455 if (new_exists == EXISTS) { |
433 bool success = Delete(new_path, true); | 456 bool success = Delete(new_path, true); |
434 if (!success) return false; | 457 if (!success) return false; |
435 } | 458 } |
436 DWORD flags = MOVEFILE_WRITE_THROUGH; | 459 DWORD flags = MOVEFILE_WRITE_THROUGH; |
437 int move_status = | 460 int move_status = |
438 MoveFileExW(system_path, system_new_path, flags); | 461 MoveFileExW(system_path, system_new_path, flags); |
439 free(const_cast<wchar_t*>(system_path)); | 462 free(const_cast<wchar_t*>(system_path)); |
440 free(const_cast<wchar_t*>(system_new_path)); | 463 free(const_cast<wchar_t*>(system_new_path)); |
441 return (move_status != 0); | 464 return (move_status != 0); |
442 } | 465 } |
443 | 466 |
444 #endif // defined(TARGET_OS_WINDOWS) | 467 #endif // defined(TARGET_OS_WINDOWS) |
OLD | NEW |