Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(22)

Side by Side Diff: runtime/bin/directory_win.cc

Issue 13818010: dart:io | Ensure that Directory.list terminates even when symbolic links create loops in the file s… (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Add documentation of new behavior. Created 7 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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 &current_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
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
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)
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698