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

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

Issue 16813006: Make Directory.list pull-based, making it possible to pause, resume and cancel directory listing. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Make the code more Windows-friendly. Created 7 years, 6 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_LINUX) 6 #if defined(TARGET_OS_LINUX)
7 7
8 #include "bin/directory.h" 8 #include "bin/directory.h"
9 9
10 #include <dirent.h> // NOLINT 10 #include <dirent.h> // NOLINT
11 #include <errno.h> // NOLINT 11 #include <errno.h> // NOLINT
12 #include <string.h> // NOLINT 12 #include <string.h> // NOLINT
13 #include <sys/param.h> // NOLINT 13 #include <sys/param.h> // NOLINT
14 #include <sys/stat.h> // NOLINT 14 #include <sys/stat.h> // NOLINT
15 #include <unistd.h> // NOLINT 15 #include <unistd.h> // NOLINT
16 16
17 #include "bin/file.h" 17 #include "bin/file.h"
18 #include "bin/platform.h" 18 #include "bin/platform.h"
19 19
20 20
21 namespace dart { 21 namespace dart {
22 namespace bin { 22 namespace bin {
23 23
24 class PathBuffer { 24
25 public: 25 PathBuffer::PathBuffer() : length_(0) {
26 PathBuffer() : length(0) { 26 data_ = new char[PATH_MAX + 1];
27 data = new char[PATH_MAX + 1]; 27 }
28
29 char* PathBuffer::AsString() const {
30 return reinterpret_cast<char*>(data_);
31 }
32
33 bool PathBuffer::Add(const char* name) {
34 char* data = AsString();
35 int written = snprintf(data + length_,
36 PATH_MAX - length_,
37 "%s",
38 name);
39 data[PATH_MAX] = '\0';
40 if (written <= PATH_MAX - length_ &&
41 written >= 0 &&
42 static_cast<size_t>(written) == strnlen(name, PATH_MAX + 1)) {
43 length_ += written;
44 return true;
45 } else {
46 errno = ENAMETOOLONG;
47 return false;
28 } 48 }
49 }
29 50
30 ~PathBuffer() { 51 void PathBuffer::Reset(int new_length) {
31 delete[] data; 52 length_ = new_length;
32 } 53 AsString()[length_] = '\0';
33 54 }
34 char* data;
35 int length;
36
37 bool Add(const char* name) {
38 int written = snprintf(data + length,
39 PATH_MAX - length,
40 "%s",
41 name);
42 data[PATH_MAX] = '\0';
43 if (written <= PATH_MAX - length &&
44 written >= 0 &&
45 static_cast<size_t>(written) == strnlen(name, PATH_MAX + 1)) {
46 length += written;
47 return true;
48 } else {
49 errno = ENAMETOOLONG;
50 return false;
51 }
52 }
53
54 void Reset(int new_length) {
55 length = new_length;
56 data[length] = '\0';
57 }
58 };
59 55
60 56
61 // A linked list of symbolic links, with their unique file system identifiers. 57 // A linked list of symbolic links, with their unique file system identifiers.
62 // These are scanned to detect loops while doing a recursive directory listing. 58 // These are scanned to detect loops while doing a recursive directory listing.
63 struct LinkList { 59 struct LinkList {
64 dev_t dev; 60 dev_t dev;
65 ino_t ino; 61 ino_t ino;
66 LinkList* next; 62 LinkList* next;
67 }; 63 };
68 64
69 65
70 // Forward declarations. 66 DirectoryListingEntry::DirectoryListingEntry(void* link)
71 static bool ListRecursively(PathBuffer* path, 67 : lister_(NULL), done_(false), link_(link) {}
72 bool recursive,
73 bool follow_links,
74 LinkList* seen,
75 DirectoryListing* listing);
76 static bool DeleteRecursively(PathBuffer* path);
77 68
78 69
79 static void PostError(DirectoryListing *listing, 70 ListType DirectoryListingEntry::Next(DirectoryListing* listing) {
80 const char* dir_name) { 71 if (done_) {
81 listing->HandleError(dir_name); 72 return kListDone;
82 }
83
84
85 static bool HandleDir(char* dir_name,
86 PathBuffer* path,
87 bool recursive,
88 bool follow_links,
89 LinkList* seen,
90 DirectoryListing *listing) {
91 if (strcmp(dir_name, ".") == 0) return true;
92 if (strcmp(dir_name, "..") == 0) return true;
93 if (!path->Add(dir_name)) {
94 PostError(listing, path->data);
95 return false;
96 }
97 return listing->HandleDirectory(path->data) &&
98 (!recursive ||
99 ListRecursively(path, recursive, follow_links, seen, listing));
100 }
101
102
103 static bool HandleFile(char* file_name,
104 PathBuffer* path,
105 DirectoryListing *listing) {
106 if (!path->Add(file_name)) {
107 PostError(listing, path->data);
108 return false;
109 }
110 return listing->HandleFile(path->data);
111 }
112
113
114 static bool HandleLink(char* link_name,
115 PathBuffer* path,
116 DirectoryListing *listing) {
117 if (!path->Add(link_name)) {
118 PostError(listing, path->data);
119 return false;
120 }
121 return listing->HandleLink(path->data);
122 }
123
124
125 static bool ListRecursively(PathBuffer* path,
126 bool recursive,
127 bool follow_links,
128 LinkList* seen,
129 DirectoryListing *listing) {
130 if (!path->Add(File::PathSeparator())) {
131 PostError(listing, path->data);
132 return false;
133 }
134 DIR* dir_pointer;
135 do {
136 dir_pointer = opendir(path->data);
137 } while (dir_pointer == NULL && errno == EINTR);
138 if (dir_pointer == NULL) {
139 PostError(listing, path->data);
140 return false;
141 } 73 }
142 74
75 if (lister_ == NULL) {
76 if (!listing->path_buffer().Add(File::PathSeparator())) {
77 done_ = true;
78 return kListError;
79 }
80 path_length_ = listing->path_buffer().length();
81 do {
82 lister_ = opendir(listing->path_buffer().AsString());
83 } while (lister_ == NULL && errno == EINTR);
84
85 if (lister_ == NULL) {
86 done_ = true;
87 return kListError;
88 }
89 }
90 // Reset.
91 listing->path_buffer().Reset(path_length_);
92 if (parent_ != NULL && parent_->link_ != link_) {
93 delete reinterpret_cast<LinkList*>(link_);
94 link_ = parent_->link_;
95 } else if (parent_ == NULL && link_ != NULL) {
96 delete reinterpret_cast<LinkList*>(link_);
97 link_ = NULL;
98 }
143 // Iterate the directory and post the directories and files to the 99 // Iterate the directory and post the directories and files to the
144 // ports. 100 // ports.
145 int path_length = path->length;
146 int status = 0; 101 int status = 0;
147 bool success = true;
148 dirent entry; 102 dirent entry;
149 dirent* result; 103 dirent* result;
150 while ((status = TEMP_FAILURE_RETRY(readdir_r(dir_pointer, 104 if ((status = TEMP_FAILURE_RETRY(readdir_r(reinterpret_cast<DIR*>(lister_),
151 &entry, 105 &entry,
152 &result))) == 0 && 106 &result))) == 0 &&
153 result != NULL) { 107 result != NULL) {
108 if (!listing->path_buffer().Add(entry.d_name)) {
109 done_ = true;
110 return kListError;
111 }
154 switch (entry.d_type) { 112 switch (entry.d_type) {
155 case DT_DIR: 113 case DT_DIR:
156 success = HandleDir(entry.d_name, 114 if (strcmp(entry.d_name, ".") == 0) return Next(listing);
157 path, 115 if (strcmp(entry.d_name, "..") == 0) return Next(listing);
158 recursive, 116 return kListDirectory;
159 follow_links,
160 seen,
161 listing) && success;
162 break;
163 case DT_REG: 117 case DT_REG:
164 success = HandleFile(entry.d_name, 118 return kListFile;
165 path,
166 listing) && success;
167 break;
168 case DT_LNK: 119 case DT_LNK:
169 if (!follow_links) { 120 if (!listing->follow_links()) {
170 success = HandleLink(entry.d_name, 121 return kListLink;
171 path,
172 listing) && success;
173 break;
174 } 122 }
175 // Else fall through to next case. 123 // Else fall through to next case.
176 // Fall through. 124 // Fall through.
177 case DT_UNKNOWN: { 125 case DT_UNKNOWN: {
178 // On some file systems the entry type is not determined by 126 // On some file systems the entry type is not determined by
179 // readdir_r. For those and for links we use stat to determine 127 // readdir_r. For those and for links we use stat to determine
180 // the actual entry type. Notice that stat returns the type of 128 // the actual entry type. Notice that stat returns the type of
181 // the file pointed to. 129 // the file pointed to.
182 struct stat entry_info; 130 struct stat entry_info;
183 if (!path->Add(entry.d_name)) { 131 int stat_success;
184 success = false; 132 stat_success = TEMP_FAILURE_RETRY(
185 break; 133 lstat(listing->path_buffer().AsString(), &entry_info));
134 if (stat_success == -1) {
135 return kListError;
186 } 136 }
187 int stat_success; 137 if (listing->follow_links() && S_ISLNK(entry_info.st_mode)) {
188 stat_success = TEMP_FAILURE_RETRY(lstat(path->data, &entry_info));
189 if (stat_success == -1) {
190 success = false;
191 PostError(listing, path->data);
192 break;
193 }
194 if (follow_links && S_ISLNK(entry_info.st_mode)) {
195 // Check to see if we are in a loop created by a symbolic link. 138 // Check to see if we are in a loop created by a symbolic link.
139 LinkList* previous = reinterpret_cast<LinkList*>(link_);
196 LinkList current_link = { entry_info.st_dev, 140 LinkList current_link = { entry_info.st_dev,
197 entry_info.st_ino, 141 entry_info.st_ino,
198 seen }; 142 previous };
199 LinkList* previous = seen;
200 bool looping_link = false;
201 while (previous != NULL) { 143 while (previous != NULL) {
202 if (previous->dev == current_link.dev && 144 if (previous->dev == current_link.dev &&
203 previous->ino == current_link.ino) { 145 previous->ino == current_link.ino) {
204 // Report the looping link as a link, rather than following it. 146 // Report the looping link as a link, rather than following it.
205 path->Reset(path_length); 147 return kListLink;
206 success = HandleLink(entry.d_name,
207 path,
208 listing) && success;
209 looping_link = true;
210 break;
211 } 148 }
212 previous = previous->next; 149 previous = previous->next;
213 } 150 }
214 if (looping_link) break; 151 stat_success = TEMP_FAILURE_RETRY(
215 stat_success = TEMP_FAILURE_RETRY(stat(path->data, &entry_info)); 152 stat(listing->path_buffer().AsString(), &entry_info));
216 if (stat_success == -1) { 153 if (stat_success == -1) {
217 // Report a broken link as a link, even if follow_links is true. 154 // Report a broken link as a link, even if follow_links is true.
218 path->Reset(path_length); 155 return kListLink;
219 success = HandleLink(entry.d_name,
220 path,
221 listing) && success;
222 break;
223 } 156 }
224 if (S_ISDIR(entry_info.st_mode)) { 157 if (S_ISDIR(entry_info.st_mode)) {
225 // Recurse into the subdirectory with current_link added to the 158 // Recurse into the subdirectory with current_link added to the
226 // linked list of seen file system links. 159 // linked list of seen file system links.
227 path->Reset(path_length); 160 link_ = new LinkList(current_link);
228 success = HandleDir(entry.d_name, 161 if (strcmp(entry.d_name, ".") == 0) return Next(listing);
229 path, 162 if (strcmp(entry.d_name, "..") == 0) return Next(listing);
230 recursive, 163 return kListDirectory;
231 follow_links,
232 &current_link,
233 listing) && success;
234 break;
235 } 164 }
236 } 165 }
237 path->Reset(path_length);
238 if (S_ISDIR(entry_info.st_mode)) { 166 if (S_ISDIR(entry_info.st_mode)) {
239 success = HandleDir(entry.d_name, 167 if (strcmp(entry.d_name, ".") == 0) return Next(listing);
240 path, 168 if (strcmp(entry.d_name, "..") == 0) return Next(listing);
241 recursive, 169 return kListDirectory;
242 follow_links,
243 seen,
244 listing) && success;
245 } else if (S_ISREG(entry_info.st_mode)) { 170 } else if (S_ISREG(entry_info.st_mode)) {
246 success = HandleFile(entry.d_name, 171 return kListFile;
247 path,
248 listing) && success;
249 } else if (S_ISLNK(entry_info.st_mode)) { 172 } else if (S_ISLNK(entry_info.st_mode)) {
250 success = HandleLink(entry.d_name, 173 return kListLink;
251 path,
252 listing) && success;
253 } 174 }
254 break;
255 } 175 }
176
256 default: 177 default:
257 break; 178 break;
258 } 179 }
259 path->Reset(path_length);
260 } 180 }
181 done_ = true;
261 182
262 if (status != 0) { 183 if (status != 0) {
263 errno = status; 184 errno = status;
264 success = false; 185 return kListError;
265 PostError(listing, path->data);
266 } 186 }
267 187
268 if (closedir(dir_pointer) == -1) { 188 if (closedir(reinterpret_cast<DIR*>(lister_)) == -1) {
269 success = false; 189 return kListError;
270 PostError(listing, path->data);
271 } 190 }
272 191
273 return success; 192 return kListDone;
274 } 193 }
275 194
276 195
196 static bool ListNext(DirectoryListing* listing) {
197 switch (listing->top()->Next(listing)) {
198 case kListFile:
199 return listing->HandleFile(listing->CurrentPath());
200
201 case kListLink:
202 return listing->HandleLink(listing->CurrentPath());
203
204 case kListDirectory:
205 if (listing->recursive()) {
206 listing->Push(new DirectoryListingEntry(listing->top()->link()));
207 }
208 return listing->HandleDirectory(listing->CurrentPath());
209
210 case kListError:
211 return listing->HandleError(listing->CurrentPath());
212
213 case kListDone:
214 listing->Pop();
215 if (listing->IsEmpty()) {
216 listing->HandleDone();
217 return false;
218 } else {
219 return true;
220 }
221
222 default:
223 ASSERT(0);
Søren Gjesse 2013/06/12 12:52:41 UNREACHABLE();
Anders Johnsen 2013/06/13 08:38:24 Done.
224 }
225 return false;
226 }
227
228
229 static bool DeleteRecursively(PathBuffer* path);
230
231
277 static bool DeleteFile(char* file_name, 232 static bool DeleteFile(char* file_name,
278 PathBuffer* path) { 233 PathBuffer* path) {
279 return path->Add(file_name) && unlink(path->data) == 0; 234 return path->Add(file_name) && unlink(path->AsString()) == 0;
280 } 235 }
281 236
282 237
283 static bool DeleteDir(char* dir_name, 238 static bool DeleteDir(char* dir_name,
284 PathBuffer* path) { 239 PathBuffer* path) {
285 if (strcmp(dir_name, ".") == 0) return true; 240 if (strcmp(dir_name, ".") == 0) return true;
286 if (strcmp(dir_name, "..") == 0) return true; 241 if (strcmp(dir_name, "..") == 0) return true;
287 return path->Add(dir_name) && DeleteRecursively(path); 242 return path->Add(dir_name) && DeleteRecursively(path);
288 } 243 }
289 244
290 245
291 static bool DeleteRecursively(PathBuffer* path) { 246 static bool DeleteRecursively(PathBuffer* path) {
292 // Do not recurse into links for deletion. Instead delete the link. 247 // Do not recurse into links for deletion. Instead delete the link.
293 // If it's a file, delete it. 248 // If it's a file, delete it.
294 struct stat st; 249 struct stat st;
295 if (TEMP_FAILURE_RETRY(lstat(path->data, &st)) == -1) { 250 if (TEMP_FAILURE_RETRY(lstat(path->AsString(), &st)) == -1) {
296 return false; 251 return false;
297 } else if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) { 252 } else if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) {
298 return (unlink(path->data) == 0); 253 return (unlink(path->AsString()) == 0);
299 } 254 }
300 255
301 if (!path->Add(File::PathSeparator())) return false; 256 if (!path->Add(File::PathSeparator())) return false;
302 257
303 // Not a link. Attempt to open as a directory and recurse into the 258 // Not a link. Attempt to open as a directory and recurse into the
304 // directory. 259 // directory.
305 DIR* dir_pointer; 260 DIR* dir_pointer;
306 do { 261 do {
307 dir_pointer = opendir(path->data); 262 dir_pointer = opendir(path->AsString());
308 } while (dir_pointer == NULL && errno == EINTR); 263 } while (dir_pointer == NULL && errno == EINTR);
309 264
310 if (dir_pointer == NULL) { 265 if (dir_pointer == NULL) {
311 return false; 266 return false;
312 } 267 }
313 268
314 // Iterate the directory and delete all files and directories. 269 // Iterate the directory and delete all files and directories.
315 int path_length = path->length; 270 int path_length = path->length();
316 int read = 0; 271 int read = 0;
317 bool success = true; 272 bool success = true;
318 dirent entry; 273 dirent entry;
319 dirent* result; 274 dirent* result;
320 while ((read = TEMP_FAILURE_RETRY(readdir_r(dir_pointer, 275 while ((read = TEMP_FAILURE_RETRY(readdir_r(dir_pointer,
321 &entry, 276 &entry,
322 &result))) == 0 && 277 &result))) == 0 &&
323 result != NULL && 278 result != NULL &&
324 success) { 279 success) {
325 switch (entry.d_type) { 280 switch (entry.d_type) {
326 case DT_DIR: 281 case DT_DIR:
327 success = success && DeleteDir(entry.d_name, path); 282 success = success && DeleteDir(entry.d_name, path);
328 break; 283 break;
329 case DT_REG: 284 case DT_REG:
330 case DT_LNK: 285 case DT_LNK:
331 // Treat all links as files. This will delete the link which 286 // Treat all links as files. This will delete the link which
332 // is what we want no matter if the link target is a file or a 287 // is what we want no matter if the link target is a file or a
333 // directory. 288 // directory.
334 success = success && DeleteFile(entry.d_name, path); 289 success = success && DeleteFile(entry.d_name, path);
335 break; 290 break;
336 case DT_UNKNOWN: { 291 case DT_UNKNOWN: {
337 // On some file systems the entry type is not determined by 292 // On some file systems the entry type is not determined by
338 // readdir_r. For those we use lstat to determine the entry 293 // readdir_r. For those we use lstat to determine the entry
339 // type. 294 // type.
340 struct stat entry_info; 295 struct stat entry_info;
341 if (!path->Add(entry.d_name)) { 296 if (!path->Add(entry.d_name)) {
342 success = false; 297 success = false;
343 break; 298 break;
344 } 299 }
345 int lstat_success = TEMP_FAILURE_RETRY(lstat(path->data, &entry_info)); 300 int lstat_success = TEMP_FAILURE_RETRY(
301 lstat(path->AsString(), &entry_info));
346 if (lstat_success == -1) { 302 if (lstat_success == -1) {
347 success = false; 303 success = false;
348 break; 304 break;
349 } 305 }
350 path->Reset(path_length); 306 path->Reset(path_length);
351 if (S_ISDIR(entry_info.st_mode)) { 307 if (S_ISDIR(entry_info.st_mode)) {
352 success = success && DeleteDir(entry.d_name, path); 308 success = success && DeleteDir(entry.d_name, path);
353 } else if (S_ISREG(entry_info.st_mode) || S_ISLNK(entry_info.st_mode)) { 309 } else if (S_ISREG(entry_info.st_mode) || S_ISLNK(entry_info.st_mode)) {
354 // Treat links as files. This will delete the link which is 310 // Treat links as files. This will delete the link which is
355 // what we want no matter if the link target is a file or a 311 // what we want no matter if the link target is a file or a
356 // directory. 312 // directory.
357 success = success && DeleteFile(entry.d_name, path); 313 success = success && DeleteFile(entry.d_name, path);
358 } 314 }
359 break; 315 break;
360 } 316 }
361 default: 317 default:
362 break; 318 break;
363 } 319 }
364 path->Reset(path_length); 320 path->Reset(path_length);
365 } 321 }
366 322
367 if ((read != 0) || 323 if ((read != 0) ||
368 (closedir(dir_pointer) == -1) || 324 (closedir(dir_pointer) == -1) ||
369 (remove(path->data) == -1)) { 325 (remove(path->AsString()) == -1)) {
370 return false; 326 return false;
371 } 327 }
372 return success; 328 return success;
373 } 329 }
374 330
375 331
376 bool Directory::List(const char* dir_name,
377 bool recursive,
378 bool follow_links,
379 DirectoryListing *listing) {
380 PathBuffer path;
381 if (!path.Add(dir_name)) {
382 PostError(listing, dir_name);
383 return false;
384 }
385 return ListRecursively(&path, recursive, follow_links, NULL, listing);
386 }
387
388
389 Directory::ExistsResult Directory::Exists(const char* dir_name) { 332 Directory::ExistsResult Directory::Exists(const char* dir_name) {
390 struct stat entry_info; 333 struct stat entry_info;
391 int success = TEMP_FAILURE_RETRY(stat(dir_name, &entry_info)); 334 int success = TEMP_FAILURE_RETRY(stat(dir_name, &entry_info));
392 if (success == 0) { 335 if (success == 0) {
393 if (S_ISDIR(entry_info.st_mode)) { 336 if (S_ISDIR(entry_info.st_mode)) {
394 return EXISTS; 337 return EXISTS;
395 } else { 338 } else {
396 return DOES_NOT_EXIST; 339 return DOES_NOT_EXIST;
397 } 340 }
398 } else { 341 } else {
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
449 } 392 }
450 393
451 394
452 char* Directory::CreateTemp(const char* const_template) { 395 char* Directory::CreateTemp(const char* const_template) {
453 // Returns a new, unused directory name, modifying the contents of 396 // Returns a new, unused directory name, modifying the contents of
454 // dir_template. Creates the directory with the permissions specified 397 // dir_template. Creates the directory with the permissions specified
455 // by the process umask. 398 // by the process umask.
456 // The return value must be freed by the caller. 399 // The return value must be freed by the caller.
457 PathBuffer path; 400 PathBuffer path;
458 path.Add(const_template); 401 path.Add(const_template);
459 if (path.length == 0) { 402 if (path.length() == 0) {
460 path.Add("/tmp/temp_dir1_"); 403 path.Add("/tmp/temp_dir1_");
461 } else if ((path.data)[path.length - 1] == '/') { 404 } else if ((path.AsString())[path.length() - 1] == '/') {
462 path.Add("temp_dir_"); 405 path.Add("temp_dir_");
463 } 406 }
464 if (!path.Add("XXXXXX")) { 407 if (!path.Add("XXXXXX")) {
465 // Pattern has overflowed. 408 // Pattern has overflowed.
466 return NULL; 409 return NULL;
467 } 410 }
468 char* result; 411 char* result;
469 do { 412 do {
470 result = mkdtemp(path.data); 413 result = mkdtemp(path.AsString());
471 } while (result == NULL && errno == EINTR); 414 } while (result == NULL && errno == EINTR);
472 if (result == NULL) { 415 if (result == NULL) {
473 return NULL; 416 return NULL;
474 } 417 }
475 int length = strnlen(path.data, PATH_MAX); 418 int length = strnlen(path.AsString(), PATH_MAX);
476 result = static_cast<char*>(malloc(length + 1)); 419 result = static_cast<char*>(malloc(length + 1));
477 strncpy(result, path.data, length); 420 strncpy(result, path.AsString(), length);
478 result[length] = '\0'; 421 result[length] = '\0';
479 return result; 422 return result;
480 } 423 }
481 424
482 425
483 bool Directory::Delete(const char* dir_name, bool recursive) { 426 bool Directory::Delete(const char* dir_name, bool recursive) {
484 if (!recursive) { 427 if (!recursive) {
485 if (File::GetType(dir_name, false) == File::kIsLink && 428 if (File::GetType(dir_name, false) == File::kIsLink &&
486 File::GetType(dir_name, true) == File::kIsDirectory) { 429 File::GetType(dir_name, true) == File::kIsDirectory) {
487 return (TEMP_FAILURE_RETRY(unlink(dir_name)) == 0); 430 return (TEMP_FAILURE_RETRY(unlink(dir_name)) == 0);
488 } 431 }
489 return (TEMP_FAILURE_RETRY(rmdir(dir_name)) == 0); 432 return (TEMP_FAILURE_RETRY(rmdir(dir_name)) == 0);
490 } else { 433 } else {
491 PathBuffer path; 434 PathBuffer path;
492 if (!path.Add(dir_name)) { 435 if (!path.Add(dir_name)) {
493 return false; 436 return false;
494 } 437 }
495 return DeleteRecursively(&path); 438 return DeleteRecursively(&path);
496 } 439 }
497 } 440 }
498 441
499 442
500 bool Directory::Rename(const char* path, const char* new_path) { 443 bool Directory::Rename(const char* path, const char* new_path) {
501 ExistsResult exists = Exists(path); 444 ExistsResult exists = Exists(path);
502 if (exists != EXISTS) return false; 445 if (exists != EXISTS) return false;
503 return (TEMP_FAILURE_RETRY(rename(path, new_path)) == 0); 446 return (TEMP_FAILURE_RETRY(rename(path, new_path)) == 0);
504 } 447 }
505 448
449
450 void Directory::List(DirectoryListing* listing) {
451 if (listing->error()) {
452 listing->HandleError("Invalid path");
453 listing->HandleDone();
454 } else {
455 while (ListNext(listing)) {}
456 }
457 }
458
506 } // namespace bin 459 } // namespace bin
507 } // namespace dart 460 } // namespace dart
508 461
509 #endif // defined(TARGET_OS_LINUX) 462 #endif // defined(TARGET_OS_LINUX)
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698