| 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 #include "bin/file.h" |
| 10 | 10 |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 61 FILE_FLAG_BACKUP_SEMANTICS, | 61 FILE_FLAG_BACKUP_SEMANTICS, |
| 62 NULL); | 62 NULL); |
| 63 if (handle == INVALID_HANDLE_VALUE) { | 63 if (handle == INVALID_HANDLE_VALUE) { |
| 64 return true; | 64 return true; |
| 65 } else { | 65 } else { |
| 66 CloseHandle(handle); | 66 CloseHandle(handle); |
| 67 return false; | 67 return false; |
| 68 } | 68 } |
| 69 } | 69 } |
| 70 | 70 |
| 71 // A linked list structure holding a link target's unique file system ID. |
| 72 // Used to detect loops in the file system when listing recursively. |
| 73 struct LinkList { |
| 74 DWORD volume; |
| 75 DWORD id_low; |
| 76 DWORD id_high; |
| 77 LinkList* next; |
| 78 }; |
| 71 | 79 |
| 72 // Forward declarations. | 80 // Forward declarations. |
| 73 static bool ListRecursively(PathBuffer* path, | 81 static bool ListRecursively(PathBuffer* path, |
| 74 bool recursive, | 82 bool recursive, |
| 75 bool follow_links, | 83 bool follow_links, |
| 84 LinkList* seen, |
| 76 DirectoryListing* listing); | 85 DirectoryListing* listing); |
| 77 static bool DeleteRecursively(PathBuffer* path); | 86 static bool DeleteRecursively(PathBuffer* path); |
| 78 | 87 |
| 79 | 88 |
| 80 static void PostError(DirectoryListing* listing, | 89 static void PostError(DirectoryListing* listing, |
| 81 const wchar_t* dir_name) { | 90 const wchar_t* dir_name) { |
| 82 const char* utf8_path = StringUtils::WideToUtf8(dir_name); | 91 const char* utf8_path = StringUtils::WideToUtf8(dir_name); |
| 83 listing->HandleError(utf8_path); | 92 listing->HandleError(utf8_path); |
| 84 free(const_cast<char*>(utf8_path)); | 93 free(const_cast<char*>(utf8_path)); |
| 85 } | 94 } |
| 86 | 95 |
| 87 | 96 |
| 88 static bool HandleDir(wchar_t* dir_name, | 97 static bool HandleDir(wchar_t* dir_name, |
| 89 PathBuffer* path, | 98 PathBuffer* path, |
| 90 bool recursive, | 99 bool recursive, |
| 91 bool follow_links, | 100 bool follow_links, |
| 101 LinkList* seen, |
| 92 DirectoryListing* listing) { | 102 DirectoryListing* listing) { |
| 93 if (wcscmp(dir_name, L".") == 0) return true; | 103 if (wcscmp(dir_name, L".") == 0) return true; |
| 94 if (wcscmp(dir_name, L"..") == 0) return true; | 104 if (wcscmp(dir_name, L"..") == 0) return true; |
| 95 if (!path->Add(dir_name)) { | 105 if (!path->Add(dir_name)) { |
| 96 PostError(listing, path->data); | 106 PostError(listing, path->data); |
| 97 return false; | 107 return false; |
| 98 } | 108 } |
| 99 char* utf8_path = StringUtils::WideToUtf8(path->data); | 109 char* utf8_path = StringUtils::WideToUtf8(path->data); |
| 100 bool ok = listing->HandleDirectory(utf8_path); | 110 bool ok = listing->HandleDirectory(utf8_path); |
| 101 free(utf8_path); | 111 free(utf8_path); |
| 102 return ok && | 112 return ok && |
| 103 (!recursive || ListRecursively(path, recursive, follow_links, listing)); | 113 (!recursive || |
| 114 ListRecursively(path, recursive, follow_links, seen, listing)); |
| 104 } | 115 } |
| 105 | 116 |
| 106 | 117 |
| 107 static bool HandleFile(wchar_t* file_name, | 118 static bool HandleFile(wchar_t* file_name, |
| 108 PathBuffer* path, | 119 PathBuffer* path, |
| 109 DirectoryListing* listing) { | 120 DirectoryListing* listing) { |
| 110 if (!path->Add(file_name)) { | 121 if (!path->Add(file_name)) { |
| 111 PostError(listing, path->data); | 122 PostError(listing, path->data); |
| 112 return false; | 123 return false; |
| 113 } | 124 } |
| (...skipping 15 matching lines...) Expand all Loading... |
| 129 bool ok = listing->HandleLink(utf8_path); | 140 bool ok = listing->HandleLink(utf8_path); |
| 130 free(utf8_path); | 141 free(utf8_path); |
| 131 return ok; | 142 return ok; |
| 132 } | 143 } |
| 133 | 144 |
| 134 | 145 |
| 135 static bool HandleEntry(LPWIN32_FIND_DATAW find_file_data, | 146 static bool HandleEntry(LPWIN32_FIND_DATAW find_file_data, |
| 136 PathBuffer* path, | 147 PathBuffer* path, |
| 137 bool recursive, | 148 bool recursive, |
| 138 bool follow_links, | 149 bool follow_links, |
| 150 LinkList* seen, |
| 139 DirectoryListing* listing) { | 151 DirectoryListing* listing) { |
| 140 DWORD attributes = find_file_data->dwFileAttributes; | 152 DWORD attributes = find_file_data->dwFileAttributes; |
| 141 if ((attributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0) { | 153 if ((attributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0) { |
| 142 if (!follow_links) { | 154 if (!follow_links) { |
| 143 return HandleLink(find_file_data->cFileName, path, listing); | 155 return HandleLink(find_file_data->cFileName, path, listing); |
| 144 } | 156 } |
| 145 int path_length = path->length; | 157 int path_length = path->length; |
| 146 if (!path->Add(find_file_data->cFileName)) return false; | 158 if (!path->Add(find_file_data->cFileName)) return false; |
| 147 bool broken = IsBrokenLink(path->data); | 159 HANDLE handle = CreateFileW( |
| 160 path->data, |
| 161 0, |
| 162 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, |
| 163 NULL, |
| 164 OPEN_EXISTING, |
| 165 FILE_FLAG_BACKUP_SEMANTICS, |
| 166 NULL); |
| 148 path->Reset(path_length); | 167 path->Reset(path_length); |
| 149 if (broken) { | 168 if (handle == INVALID_HANDLE_VALUE) { |
| 150 // Report as (broken) link. | 169 // Report as (broken) link. |
| 151 return HandleLink(find_file_data->cFileName, path, listing); | 170 return HandleLink(find_file_data->cFileName, path, listing); |
| 152 } | 171 } |
| 172 if ((attributes & FILE_ATTRIBUTE_DIRECTORY) != 0) { |
| 173 // Check the seen link targets to see if we are in a file system loop. |
| 174 LinkList current_link; |
| 175 BY_HANDLE_FILE_INFORMATION info; |
| 176 // Get info |
| 177 if (!GetFileInformationByHandle(handle, &info)) { |
| 178 DWORD error = GetLastError(); |
| 179 CloseHandle(handle); |
| 180 SetLastError(error); |
| 181 PostError(listing, path->data); |
| 182 return false; |
| 183 } |
| 184 CloseHandle(handle); |
| 185 current_link.volume = info.dwVolumeSerialNumber; |
| 186 current_link.id_low = info.nFileIndexLow; |
| 187 current_link.id_high = info.nFileIndexHigh; |
| 188 current_link.next = seen; |
| 189 LinkList* previous = seen; |
| 190 while (previous != NULL) { |
| 191 if (previous->volume == current_link.volume && |
| 192 previous->id_low == current_link.id_low && |
| 193 previous->id_high == current_link.id_high) { |
| 194 // Report the looping link as a link, rather than following it. |
| 195 return HandleLink(find_file_data->cFileName, path, listing); |
| 196 } |
| 197 previous = previous->next; |
| 198 } |
| 199 // Recurse into the directory, adding current link to the seen links list. |
| 200 return HandleDir(find_file_data->cFileName, |
| 201 path, |
| 202 recursive, |
| 203 follow_links, |
| 204 ¤t_link, |
| 205 listing); |
| 206 } |
| 153 } | 207 } |
| 154 if ((attributes & FILE_ATTRIBUTE_DIRECTORY) != 0) { | 208 if ((attributes & FILE_ATTRIBUTE_DIRECTORY) != 0) { |
| 155 return HandleDir(find_file_data->cFileName, | 209 return HandleDir(find_file_data->cFileName, |
| 156 path, | 210 path, |
| 157 recursive, | 211 recursive, |
| 158 follow_links, | 212 follow_links, |
| 213 seen, |
| 159 listing); | 214 listing); |
| 160 } else { | 215 } else { |
| 161 return HandleFile(find_file_data->cFileName, path, listing); | 216 return HandleFile(find_file_data->cFileName, path, listing); |
| 162 } | 217 } |
| 163 } | 218 } |
| 164 | 219 |
| 165 | 220 |
| 166 static bool ListRecursively(PathBuffer* path, | 221 static bool ListRecursively(PathBuffer* path, |
| 167 bool recursive, | 222 bool recursive, |
| 168 bool follow_links, | 223 bool follow_links, |
| 224 LinkList* seen, |
| 169 DirectoryListing* listing) { | 225 DirectoryListing* listing) { |
| 170 if (!path->Add(L"\\*")) { | 226 if (!path->Add(L"\\*")) { |
| 171 PostError(listing, path->data); | 227 PostError(listing, path->data); |
| 172 return false; | 228 return false; |
| 173 } | 229 } |
| 174 | 230 |
| 175 WIN32_FIND_DATAW find_file_data; | 231 WIN32_FIND_DATAW find_file_data; |
| 176 HANDLE find_handle = FindFirstFileW(path->data, &find_file_data); | 232 HANDLE find_handle = FindFirstFileW(path->data, &find_file_data); |
| 177 | 233 |
| 178 // Adjust the path by removing the '*' used for the search. | 234 // Adjust the path by removing the '*' used for the search. |
| 179 path->Reset(path->length - 1); | 235 path->Reset(path->length - 1); |
| 180 | 236 |
| 181 if (find_handle == INVALID_HANDLE_VALUE) { | 237 if (find_handle == INVALID_HANDLE_VALUE) { |
| 182 PostError(listing, path->data); | 238 PostError(listing, path->data); |
| 183 return false; | 239 return false; |
| 184 } | 240 } |
| 185 | 241 |
| 186 int path_length = path->length; | 242 int path_length = path->length; |
| 187 bool success = HandleEntry(&find_file_data, | 243 bool success = HandleEntry(&find_file_data, |
| 188 path, | 244 path, |
| 189 recursive, | 245 recursive, |
| 190 follow_links, | 246 follow_links, |
| 247 seen, |
| 191 listing); | 248 listing); |
| 192 | 249 |
| 193 while ((FindNextFileW(find_handle, &find_file_data) != 0)) { | 250 while ((FindNextFileW(find_handle, &find_file_data) != 0)) { |
| 194 path->Reset(path_length); // HandleEntry adds the entry name to path. | 251 path->Reset(path_length); // HandleEntry adds the entry name to path. |
| 195 success = HandleEntry(&find_file_data, | 252 success = HandleEntry(&find_file_data, |
| 196 path, | 253 path, |
| 197 recursive, | 254 recursive, |
| 198 follow_links, | 255 follow_links, |
| 256 seen, |
| 199 listing) && success; | 257 listing) && success; |
| 200 } | 258 } |
| 201 | 259 |
| 202 if (GetLastError() != ERROR_NO_MORE_FILES) { | 260 if (GetLastError() != ERROR_NO_MORE_FILES) { |
| 203 success = false; | 261 success = false; |
| 204 PostError(listing, path->data); | 262 PostError(listing, path->data); |
| 205 } | 263 } |
| 206 | 264 |
| 207 if (FindClose(find_handle) == 0) { | 265 if (FindClose(find_handle) == 0) { |
| 208 success = false; | 266 success = false; |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 313 bool recursive, | 371 bool recursive, |
| 314 bool follow_links, | 372 bool follow_links, |
| 315 DirectoryListing* listing) { | 373 DirectoryListing* listing) { |
| 316 const wchar_t* system_name = StringUtils::Utf8ToWide(dir_name); | 374 const wchar_t* system_name = StringUtils::Utf8ToWide(dir_name); |
| 317 PathBuffer path; | 375 PathBuffer path; |
| 318 if (!path.Add(system_name)) { | 376 if (!path.Add(system_name)) { |
| 319 PostError(listing, system_name); | 377 PostError(listing, system_name); |
| 320 return false; | 378 return false; |
| 321 } | 379 } |
| 322 free(const_cast<wchar_t*>(system_name)); | 380 free(const_cast<wchar_t*>(system_name)); |
| 323 return ListRecursively(&path, recursive, follow_links, listing); | 381 return ListRecursively(&path, recursive, follow_links, NULL, listing); |
| 324 } | 382 } |
| 325 | 383 |
| 326 | 384 |
| 327 static Directory::ExistsResult ExistsHelper(const wchar_t* dir_name) { | 385 static Directory::ExistsResult ExistsHelper(const wchar_t* dir_name) { |
| 328 DWORD attributes = GetFileAttributesW(dir_name); | 386 DWORD attributes = GetFileAttributesW(dir_name); |
| 329 if (attributes == INVALID_FILE_ATTRIBUTES) { | 387 if (attributes == INVALID_FILE_ATTRIBUTES) { |
| 330 DWORD last_error = GetLastError(); | 388 DWORD last_error = GetLastError(); |
| 331 if (last_error == ERROR_FILE_NOT_FOUND || | 389 if (last_error == ERROR_FILE_NOT_FOUND || |
| 332 last_error == ERROR_PATH_NOT_FOUND) { | 390 last_error == ERROR_PATH_NOT_FOUND) { |
| 333 return Directory::DOES_NOT_EXIST; | 391 return Directory::DOES_NOT_EXIST; |
| (...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 460 } | 518 } |
| 461 DWORD flags = MOVEFILE_WRITE_THROUGH; | 519 DWORD flags = MOVEFILE_WRITE_THROUGH; |
| 462 int move_status = | 520 int move_status = |
| 463 MoveFileExW(system_path, system_new_path, flags); | 521 MoveFileExW(system_path, system_new_path, flags); |
| 464 free(const_cast<wchar_t*>(system_path)); | 522 free(const_cast<wchar_t*>(system_path)); |
| 465 free(const_cast<wchar_t*>(system_new_path)); | 523 free(const_cast<wchar_t*>(system_new_path)); |
| 466 return (move_status != 0); | 524 return (move_status != 0); |
| 467 } | 525 } |
| 468 | 526 |
| 469 #endif // defined(TARGET_OS_WINDOWS) | 527 #endif // defined(TARGET_OS_WINDOWS) |
| OLD | NEW |