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

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

Issue 12212194: IO v2: Use a single PathBuffer in Directory.list on Windows, and stop rewriting paths during listin… (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Fix bug, remove other platforms. Created 7 years, 10 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
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 "bin/directory.h" 5 #include "bin/directory.h"
6 6
7 #include <errno.h> 7 #include <errno.h>
8 #include <sys/stat.h> 8 #include <sys/stat.h>
9 9
10 #include "bin/log.h" 10 #include "bin/log.h"
11 11
12 class PathBuffer { 12 class PathBuffer {
13 public: 13 public:
14 PathBuffer() : length(0) { } 14 PathBuffer() : length(0) {
15 data = new wchar_t[MAX_PATH + 1];
16 }
15 17
16 wchar_t data[MAX_PATH + 1]; 18 ~PathBuffer() {
19 delete[] data;
20 }
21
22 wchar_t* data;
17 int length; 23 int length;
18 24
19 bool Add(const wchar_t* name) { 25 bool Add(const wchar_t* name) {
20 size_t written = _snwprintf(data + length, 26 size_t written = _snwprintf(data + length,
21 MAX_PATH - length, 27 MAX_PATH - length,
22 L"%s", 28 L"%s",
23 name); 29 name);
24 data[MAX_PATH] = L'\0'; 30 data[MAX_PATH] = L'\0';
25 if (written == wcsnlen(name, MAX_PATH + 1)) { 31 if (written == wcsnlen(name, MAX_PATH + 1)) {
26 length += written; 32 length += written;
27 return true; 33 return true;
28 } else { 34 } else {
29 SetLastError(ERROR_BUFFER_OVERFLOW); 35 SetLastError(ERROR_BUFFER_OVERFLOW);
30 return false; 36 return false;
31 } 37 }
32 } 38 }
33 39
34 void Reset(int new_length) { 40 void Reset(int new_length) {
35 length = new_length; 41 length = new_length;
36 data[length] = L'\0'; 42 data[length] = L'\0';
37 } 43 }
38 }; 44 };
39 45
40 46
41 // Forward declarations. 47 // Forward declarations.
42 static bool ListRecursively(const wchar_t* dir_name, 48 static bool ListRecursively(PathBuffer* path,
43 bool recursive, 49 bool recursive,
44 DirectoryListing* listing); 50 DirectoryListing* listing);
45 static bool DeleteRecursively(const wchar_t* dir_name); 51 static bool DeleteRecursively(PathBuffer* path);
46 52
47 53
48 static void PostError(DirectoryListing* listing, 54 static void PostError(DirectoryListing* listing,
49 const wchar_t* dir_name) { 55 const wchar_t* dir_name) {
50 const char* utf8_path = StringUtils::WideToUtf8(dir_name); 56 const char* utf8_path = StringUtils::WideToUtf8(dir_name);
51 listing->HandleError(utf8_path); 57 listing->HandleError(utf8_path);
52 free(const_cast<char*>(utf8_path)); 58 free(const_cast<char*>(utf8_path));
53 } 59 }
54 60
55 61
56 static bool HandleDir(wchar_t* dir_name, 62 static bool HandleDir(wchar_t* dir_name,
57 PathBuffer* path, 63 PathBuffer* path,
58 bool recursive, 64 bool recursive,
59 DirectoryListing* listing) { 65 DirectoryListing* listing) {
60 if (wcscmp(dir_name, L".") == 0) return true; 66 if (wcscmp(dir_name, L".") == 0) return true;
61 if (wcscmp(dir_name, L"..") == 0) return true; 67 if (wcscmp(dir_name, L"..") == 0) return true;
62 if (!path->Add(dir_name)) { 68 if (!path->Add(dir_name)) {
63 PostError(listing, path->data); 69 PostError(listing, path->data);
64 return false; 70 return false;
65 } 71 }
66 char* utf8_path = StringUtils::WideToUtf8(path->data); 72 char* utf8_path = StringUtils::WideToUtf8(path->data);
67 bool ok = listing->HandleDirectory(utf8_path); 73 bool ok = listing->HandleDirectory(utf8_path);
68 free(utf8_path); 74 free(utf8_path);
69 return ok && (!recursive || ListRecursively(path->data, recursive, listing)); 75 return ok && (!recursive || ListRecursively(path, recursive, listing));
70 } 76 }
71 77
72 78
73 static bool HandleFile(wchar_t* file_name, 79 static bool HandleFile(wchar_t* file_name,
74 PathBuffer* path, 80 PathBuffer* path,
75 DirectoryListing* listing) { 81 DirectoryListing* listing) {
76 if (!path->Add(file_name)) { 82 if (!path->Add(file_name)) {
77 PostError(listing, path->data); 83 PostError(listing, path->data);
78 return false; 84 return false;
79 } 85 }
(...skipping 13 matching lines...) Expand all
93 return HandleDir(find_file_data->cFileName, 99 return HandleDir(find_file_data->cFileName,
94 path, 100 path,
95 recursive, 101 recursive,
96 listing); 102 listing);
97 } else { 103 } else {
98 return HandleFile(find_file_data->cFileName, path, listing); 104 return HandleFile(find_file_data->cFileName, path, listing);
99 } 105 }
100 } 106 }
101 107
102 108
103 static PathBuffer* ComputeFullSearchPath(const wchar_t* dir_name) { 109 static bool ListRecursively(PathBuffer* path,
104 // GetFullPathName only works in a multi-threaded environment if
105 // SetCurrentDirectory is not used. We currently have no plan for
106 // exposing SetCurrentDirectory.
107 PathBuffer* path = new PathBuffer();
108
109 size_t written = GetFullPathNameW(dir_name, MAX_PATH + 1, path->data, NULL);
110 // GetFullPathName only accepts input strings of size less than
111 // MAX_PATH and returns 0 to indicate failure for paths longer than
112 // that. Therefore the path buffer is always big enough.
113 if (written == 0 || written > MAX_PATH) {
114 delete path;
115 return NULL;
116 }
117 path->length = written;
118 if (path->Add(L"\\*")) {
119 return path;
120 } else {
121 delete path;
122 return NULL;
123 }
124 }
125
126
127 static bool ListRecursively(const wchar_t* dir_name,
128 bool recursive, 110 bool recursive,
129 DirectoryListing* listing) { 111 DirectoryListing* listing) {
130 // Compute full path for the directory currently being listed. The 112 if (!path->Add(L"\\*")) {
131 // path buffer will be used to construct the current path in the 113 PostError(listing, path->data);
132 // recursive traversal. path_length does not always equal
133 // strlen(path) but indicates the current prefix of path that is the
134 // path of the current directory in the traversal.
135 PathBuffer* path = ComputeFullSearchPath(dir_name);
136 if (path == NULL) {
137 PostError(listing, dir_name);
138 delete path;
139 return false; 114 return false;
140 } 115 }
141 116
142 WIN32_FIND_DATAW find_file_data; 117 WIN32_FIND_DATAW find_file_data;
143 HANDLE find_handle = FindFirstFileW(path->data, &find_file_data); 118 HANDLE find_handle = FindFirstFileW(path->data, &find_file_data);
144 119
145 // Adjust the path by removing the '*' used for the search. 120 // Adjust the path by removing the '*' used for the search.
146 path->Reset(path->length - 1); 121 path->Reset(path->length - 1);
147 122
148 if (find_handle == INVALID_HANDLE_VALUE) { 123 if (find_handle == INVALID_HANDLE_VALUE) {
149 PostError(listing, path->data); 124 PostError(listing, path->data);
150 delete path;
151 return false; 125 return false;
152 } 126 }
153 127
154 int path_length = path->length; 128 int path_length = path->length;
155 bool success = HandleEntry(&find_file_data, 129 bool success = HandleEntry(&find_file_data,
156 path, 130 path,
157 recursive, 131 recursive,
158 listing); 132 listing);
159 133
160 while ((FindNextFileW(find_handle, &find_file_data) != 0)) { 134 while ((FindNextFileW(find_handle, &find_file_data) != 0)) {
161 path->Reset(path_length); // HandleEntry adds the entry name to path. 135 path->Reset(path_length); // HandleEntry adds the entry name to path.
162 success = HandleEntry(&find_file_data, 136 success = HandleEntry(&find_file_data,
163 path, 137 path,
164 recursive, 138 recursive,
165 listing) && success; 139 listing) && success;
166 } 140 }
167 141
168 if (GetLastError() != ERROR_NO_MORE_FILES) { 142 if (GetLastError() != ERROR_NO_MORE_FILES) {
169 success = false; 143 success = false;
170 PostError(listing, dir_name); 144 PostError(listing, path->data);
171 } 145 }
172 146
173 if (FindClose(find_handle) == 0) { 147 if (FindClose(find_handle) == 0) {
174 success = false; 148 success = false;
175 PostError(listing, dir_name); 149 PostError(listing, path->data);
176 } 150 }
177 delete path;
178 151
179 return success; 152 return success;
180 } 153 }
181 154
182 155
183 static bool DeleteFile(wchar_t* file_name, PathBuffer* path) { 156 static bool DeleteFile(wchar_t* file_name, PathBuffer* path) {
184 if (!path->Add(file_name)) return false; 157 if (!path->Add(file_name)) return false;
185 158
186 if (DeleteFileW(path->data) != 0) { 159 if (DeleteFileW(path->data) != 0) {
187 return true; 160 return true;
(...skipping 19 matching lines...) Expand all
207 } 180 }
208 } 181 }
209 182
210 return false; 183 return false;
211 } 184 }
212 185
213 186
214 static bool DeleteDir(wchar_t* dir_name, PathBuffer* path) { 187 static bool DeleteDir(wchar_t* dir_name, PathBuffer* path) {
215 if (wcscmp(dir_name, L".") == 0) return true; 188 if (wcscmp(dir_name, L".") == 0) return true;
216 if (wcscmp(dir_name, L"..") == 0) return true; 189 if (wcscmp(dir_name, L"..") == 0) return true;
217 return path->Add(dir_name) && DeleteRecursively(path->data); 190 return path->Add(dir_name) && DeleteRecursively(path);
218 } 191 }
219 192
220 193
221 static bool DeleteEntry(LPWIN32_FIND_DATAW find_file_data, PathBuffer* path) { 194 static bool DeleteEntry(LPWIN32_FIND_DATAW find_file_data, PathBuffer* path) {
222 DWORD attributes = find_file_data->dwFileAttributes; 195 DWORD attributes = find_file_data->dwFileAttributes;
223 196
224 if ((attributes & FILE_ATTRIBUTE_DIRECTORY) != 0) { 197 if ((attributes & FILE_ATTRIBUTE_DIRECTORY) != 0) {
225 return DeleteDir(find_file_data->cFileName, path); 198 return DeleteDir(find_file_data->cFileName, path);
226 } else { 199 } else {
227 return DeleteFile(find_file_data->cFileName, path); 200 return DeleteFile(find_file_data->cFileName, path);
228 } 201 }
229 } 202 }
230 203
231 204
232 static bool DeleteRecursively(const wchar_t* dir_name) { 205 static bool DeleteRecursively(PathBuffer* path) {
233 // If the directory is a junction, it's pointing to some other place in the 206 // If the directory is a junction, it's pointing to some other place in the
234 // filesystem that we do not want to recurse into. 207 // filesystem that we do not want to recurse into.
235 DWORD attributes = GetFileAttributesW(dir_name); 208 DWORD attributes = GetFileAttributesW(path->data);
236 if ((attributes != INVALID_FILE_ATTRIBUTES) && 209 if ((attributes != INVALID_FILE_ATTRIBUTES) &&
237 (attributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0) { 210 (attributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0) {
238 // Just delete the junction itself. 211 // Just delete the junction itself.
239 return RemoveDirectoryW(dir_name) != 0; 212 return RemoveDirectoryW(path->data) != 0;
240 } 213 }
241 214
242 // Compute full path for the directory currently being deleted. The 215 if (!path->Add(L"\\*")) return false;
243 // path buffer will be used to construct the current path in the
244 // recursive traversal. path_length does not always equal
245 // strlen(path) but indicates the current prefix of path that is the
246 // path of the current directory in the traversal.
247 PathBuffer* path = ComputeFullSearchPath(dir_name);
248 if (path == NULL) return false;
249 216
250 WIN32_FIND_DATAW find_file_data; 217 WIN32_FIND_DATAW find_file_data;
251 HANDLE find_handle = FindFirstFileW(path->data, &find_file_data); 218 HANDLE find_handle = FindFirstFileW(path->data, &find_file_data);
252 219
253 // Adjust the path by removing the '*' used for the search. 220 // Adjust the path by removing the '*' used for the search.
254 int path_length = path->length - 1; 221 int path_length = path->length - 1;
255 path->Reset(path_length); 222 path->Reset(path_length);
256 223
257 if (find_handle == INVALID_HANDLE_VALUE) { 224 if (find_handle == INVALID_HANDLE_VALUE) {
258 delete path;
259 return false; 225 return false;
260 } 226 }
261 227
262 bool success = DeleteEntry(&find_file_data, path); 228 bool success = DeleteEntry(&find_file_data, path);
263 229
264 while ((FindNextFileW(find_handle, &find_file_data) != 0) && success) { 230 while ((FindNextFileW(find_handle, &find_file_data) != 0) && success) {
265 path->Reset(path_length); // DeleteEntry adds to the path. 231 path->Reset(path_length); // DeleteEntry adds to the path.
266 success = success && DeleteEntry(&find_file_data, path); 232 success = success && DeleteEntry(&find_file_data, path);
267 } 233 }
268 234
269 delete path; 235 path->Reset(path_length - 1); // Drop the "\" from the end of the path.
270
271 if ((GetLastError() != ERROR_NO_MORE_FILES) || 236 if ((GetLastError() != ERROR_NO_MORE_FILES) ||
272 (FindClose(find_handle) == 0) || 237 (FindClose(find_handle) == 0) ||
273 (RemoveDirectoryW(dir_name) == 0)) { 238 (RemoveDirectoryW(path->data) == 0)) {
274 return false; 239 return false;
275 } 240 }
276 241
277 return success; 242 return success;
278 } 243 }
279 244
280 245
281 bool Directory::List(const char* dir_name, 246 bool Directory::List(const char* dir_name,
282 bool recursive, 247 bool recursive,
283 DirectoryListing* listing) { 248 DirectoryListing* listing) {
284 const wchar_t* system_name = StringUtils::Utf8ToWide(dir_name); 249 const wchar_t* system_name = StringUtils::Utf8ToWide(dir_name);
285 bool completed = ListRecursively(system_name, recursive, listing); 250 PathBuffer path;
251 if (!path.Add(system_name)) {
252 PostError(listing, system_name);
253 return false;
254 }
286 free(const_cast<wchar_t*>(system_name)); 255 free(const_cast<wchar_t*>(system_name));
287 return completed; 256 return ListRecursively(&path, recursive, listing);
288 } 257 }
289 258
290 259
291 static Directory::ExistsResult ExistsHelper(const wchar_t* dir_name) { 260 static Directory::ExistsResult ExistsHelper(const wchar_t* dir_name) {
292 DWORD attributes = GetFileAttributesW(dir_name); 261 DWORD attributes = GetFileAttributesW(dir_name);
293 if (attributes == INVALID_FILE_ATTRIBUTES) { 262 if (attributes == INVALID_FILE_ATTRIBUTES) {
294 DWORD last_error = GetLastError(); 263 DWORD last_error = GetLastError();
295 if (last_error == ERROR_FILE_NOT_FOUND || 264 if (last_error == ERROR_FILE_NOT_FOUND ||
296 last_error == ERROR_PATH_NOT_FOUND) { 265 last_error == ERROR_PATH_NOT_FOUND) {
297 return Directory::DOES_NOT_EXIST; 266 return Directory::DOES_NOT_EXIST;
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
338 free(const_cast<wchar_t*>(system_name)); 307 free(const_cast<wchar_t*>(system_name));
339 return (create_status != 0); 308 return (create_status != 0);
340 } 309 }
341 310
342 311
343 char* Directory::CreateTemp(const char* const_template) { 312 char* Directory::CreateTemp(const char* const_template) {
344 // Returns a new, unused directory name, modifying the contents of 313 // Returns a new, unused directory name, modifying the contents of
345 // dir_template. Creates this directory, with a default security 314 // dir_template. Creates this directory, with a default security
346 // descriptor inherited from its parent directory. 315 // descriptor inherited from its parent directory.
347 // The return value must be freed by the caller. 316 // The return value must be freed by the caller.
348 PathBuffer* path = new PathBuffer(); 317 PathBuffer path;
349 if (0 == strncmp(const_template, "", 1)) { 318 if (0 == strncmp(const_template, "", 1)) {
350 path->length = GetTempPathW(MAX_PATH, path->data); 319 path.length = GetTempPathW(MAX_PATH, path.data);
351 if (path->length == 0) { 320 if (path.length == 0) {
352 delete path;
353 return NULL; 321 return NULL;
354 } 322 }
355 } else { 323 } else {
356 const wchar_t* system_template = StringUtils::Utf8ToWide(const_template); 324 const wchar_t* system_template = StringUtils::Utf8ToWide(const_template);
357 path->Add(system_template); 325 path.Add(system_template);
358 free(const_cast<wchar_t*>(system_template)); 326 free(const_cast<wchar_t*>(system_template));
359 } 327 }
360 // Length of tempdir-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx is 44. 328 // Length of tempdir-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx is 44.
361 if (path->length > MAX_PATH - 44) { 329 if (path.length > MAX_PATH - 44) {
362 delete path;
363 return NULL; 330 return NULL;
364 } 331 }
365 if ((path->data)[path->length - 1] == L'\\') { 332 if ((path.data)[path.length - 1] == L'\\') {
366 // No base name for the directory - use "tempdir". 333 // No base name for the directory - use "tempdir".
367 path->Add(L"tempdir"); 334 path.Add(L"tempdir");
368 } 335 }
369 336
370 UUID uuid; 337 UUID uuid;
371 RPC_STATUS status = UuidCreateSequential(&uuid); 338 RPC_STATUS status = UuidCreateSequential(&uuid);
372 if (status != RPC_S_OK && status != RPC_S_UUID_LOCAL_ONLY) { 339 if (status != RPC_S_OK && status != RPC_S_UUID_LOCAL_ONLY) {
373 delete path;
374 return NULL; 340 return NULL;
375 } 341 }
376 RPC_WSTR uuid_string; 342 RPC_WSTR uuid_string;
377 status = UuidToStringW(&uuid, &uuid_string); 343 status = UuidToStringW(&uuid, &uuid_string);
378 if (status != RPC_S_OK) { 344 if (status != RPC_S_OK) {
379 delete path;
380 return NULL; 345 return NULL;
381 } 346 }
382 347
383 path->Add(L"-"); 348 path.Add(L"-");
384 // RPC_WSTR is an unsigned short*, so we cast to wchar_t*. 349 // RPC_WSTR is an unsigned short*, so we cast to wchar_t*.
385 path->Add(reinterpret_cast<wchar_t*>(uuid_string)); 350 path.Add(reinterpret_cast<wchar_t*>(uuid_string));
386 RpcStringFreeW(&uuid_string); 351 RpcStringFreeW(&uuid_string);
387 if (!CreateDirectoryW(path->data, NULL)) { 352 if (!CreateDirectoryW(path.data, NULL)) {
388 delete path;
389 return NULL; 353 return NULL;
390 } 354 }
391 char* result = StringUtils::WideToUtf8(path->data); 355 char* result = StringUtils::WideToUtf8(path.data);
392 delete path;
393 return result; 356 return result;
394 } 357 }
395 358
396 359
397 bool Directory::Delete(const char* dir_name, bool recursive) { 360 bool Directory::Delete(const char* dir_name, bool recursive) {
398 bool result = false; 361 bool result = false;
399 const wchar_t* system_dir_name = StringUtils::Utf8ToWide(dir_name); 362 const wchar_t* system_dir_name = StringUtils::Utf8ToWide(dir_name);
400 if (!recursive) { 363 if (!recursive) {
401 result = (RemoveDirectoryW(system_dir_name) != 0); 364 result = (RemoveDirectoryW(system_dir_name) != 0);
402 } else { 365 } else {
403 result = DeleteRecursively(system_dir_name); 366 PathBuffer path;
367 if (!path.Add(system_dir_name)) {
368 return false;
369 }
370 result = DeleteRecursively(&path);
404 } 371 }
405 free(const_cast<wchar_t*>(system_dir_name)); 372 free(const_cast<wchar_t*>(system_dir_name));
406 return result; 373 return result;
407 } 374 }
408 375
409 376
410 bool Directory::Rename(const char* path, const char* new_path) { 377 bool Directory::Rename(const char* path, const char* new_path) {
411 const wchar_t* system_path = StringUtils::Utf8ToWide(path); 378 const wchar_t* system_path = StringUtils::Utf8ToWide(path);
412 const wchar_t* system_new_path = StringUtils::Utf8ToWide(new_path); 379 const wchar_t* system_new_path = StringUtils::Utf8ToWide(new_path);
413 ExistsResult exists = ExistsHelper(system_path); 380 ExistsResult exists = ExistsHelper(system_path);
414 if (exists != EXISTS) return false; 381 if (exists != EXISTS) return false;
415 ExistsResult new_exists = ExistsHelper(system_new_path); 382 ExistsResult new_exists = ExistsHelper(system_new_path);
416 // MoveFile does not allow replacing exising directories. Therefore, 383 // MoveFile does not allow replacing exising directories. Therefore,
417 // if the new_path is currently a directory we need to delete it 384 // if the new_path is currently a directory we need to delete it
418 // first. 385 // first.
419 if (new_exists == EXISTS) { 386 if (new_exists == EXISTS) {
420 bool success = DeleteRecursively(system_new_path); 387 bool success = Delete(new_path, true);
421 if (!success) return false; 388 if (!success) return false;
422 } 389 }
423 DWORD flags = MOVEFILE_WRITE_THROUGH; 390 DWORD flags = MOVEFILE_WRITE_THROUGH;
424 int move_status = 391 int move_status =
425 MoveFileExW(system_path, system_new_path, flags); 392 MoveFileExW(system_path, system_new_path, flags);
426 free(const_cast<wchar_t*>(system_path)); 393 free(const_cast<wchar_t*>(system_path));
427 free(const_cast<wchar_t*>(system_new_path)); 394 free(const_cast<wchar_t*>(system_new_path));
428 return (move_status != 0); 395 return (move_status != 0);
429 } 396 }
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698