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 |