| 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 |