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
3// BSD-style license that can be found in the LICENSE file.
4
5#include <cstdlib>
6#include <memory>
7
8#include "bin/directory.h"
9
10#include "bin/dartutils.h"
11#include "bin/io_buffer.h"
12#include "bin/namespace.h"
13#include "bin/typed_data_utils.h"
14#include "bin/utils.h"
15#include "include/dart_api.h"
16#include "platform/assert.h"
17#include "platform/syslog.h"
18
19namespace dart {
20namespace bin {
21
22char* Directory::system_temp_path_override_ = NULL;
23
24void FUNCTION_NAME(Directory_Current)(Dart_NativeArguments args) {
25 Namespace* namespc = Namespace::GetNamespace(args, 0);
26 const char* current = Directory::Current(namespc);
27 if (current != NULL) {
28 Dart_Handle str = ThrowIfError(DartUtils::NewString(current));
29 Dart_SetReturnValue(args, str);
30 } else {
31 Dart_SetReturnValue(args, DartUtils::NewDartOSError());
32 }
33}
34
35void FUNCTION_NAME(Directory_SetCurrent)(Dart_NativeArguments args) {
36 Namespace* namespc = Namespace::GetNamespace(args, 0);
37 Dart_Handle path = Dart_GetNativeArgument(args, 1);
38 OSError os_error;
39 ASSERT(!Dart_IsError(path));
40 bool result;
41 {
42 TypedDataScope data(path);
43 ASSERT(data.type() == Dart_TypedData_kUint8);
44 const char* name = data.GetCString();
45 result = Directory::SetCurrent(namespc, name);
46 if (!result) {
47 // Errors must be caught before TypedDataScope data is destroyed.
48 os_error.Reload();
49 }
50 }
51 if (result) {
52 Dart_SetBooleanReturnValue(args, true);
53 } else {
54 Dart_SetReturnValue(args, DartUtils::NewDartOSError(&os_error));
55 }
56}
57
58void FUNCTION_NAME(Directory_Exists)(Dart_NativeArguments args) {
59 static const int kExists = 1;
60 static const int kDoesNotExist = 0;
61 Namespace* namespc = Namespace::GetNamespace(args, 0);
62 Dart_Handle path = Dart_GetNativeArgument(args, 1);
63 OSError os_error;
64 Directory::ExistsResult result;
65 {
66 TypedDataScope data(path);
67 ASSERT(data.type() == Dart_TypedData_kUint8);
68 const char* name = data.GetCString();
69 result = Directory::Exists(namespc, name);
70 if ((result != Directory::DOES_NOT_EXIST) &&
71 (result != Directory::EXISTS)) {
72 // Errors must be caught before TypedDataScope data is destroyed.
73 os_error.Reload();
74 }
75 }
76 if (result == Directory::EXISTS) {
77 Dart_SetIntegerReturnValue(args, kExists);
78 } else if (result == Directory::DOES_NOT_EXIST) {
79 Dart_SetIntegerReturnValue(args, kDoesNotExist);
80 } else {
81 Dart_SetReturnValue(args, DartUtils::NewDartOSError(&os_error));
82 }
83}
84
85void FUNCTION_NAME(Directory_Create)(Dart_NativeArguments args) {
86 Namespace* namespc = Namespace::GetNamespace(args, 0);
87 Dart_Handle path = Dart_GetNativeArgument(args, 1);
88 OSError os_error;
89 bool result;
90 {
91 TypedDataScope data(path);
92 ASSERT(data.type() == Dart_TypedData_kUint8);
93 const char* name = data.GetCString();
94 result = Directory::Create(namespc, name);
95 if (!result) {
96 // Errors must be caught before TypedDataScope data is destroyed.
97 os_error.Reload();
98 }
99 }
100 if (result) {
101 Dart_SetBooleanReturnValue(args, true);
102 } else {
103 Dart_SetReturnValue(args, DartUtils::NewDartOSError(&os_error));
104 }
105}
106
107void FUNCTION_NAME(Directory_SystemTemp)(Dart_NativeArguments args) {
108 Namespace* namespc = Namespace::GetNamespace(args, 0);
109 const char* result = Directory::SystemTemp(namespc);
110 Dart_Handle str = ThrowIfError(DartUtils::NewString(result));
111 Dart_SetReturnValue(args, str);
112}
113
114void FUNCTION_NAME(Directory_CreateTemp)(Dart_NativeArguments args) {
115 Namespace* namespc = Namespace::GetNamespace(args, 0);
116 Dart_Handle path = Dart_GetNativeArgument(args, 1);
117 OSError os_error;
118 const char* result = NULL;
119 {
120 TypedDataScope data(path);
121 ASSERT(data.type() == Dart_TypedData_kUint8);
122 const char* name = data.GetCString();
123 result = Directory::CreateTemp(namespc, name);
124 if (result == NULL) {
125 // Errors must be caught before TypedDataScope data is destroyed.
126 os_error.Reload();
127 }
128 }
129 if (result != NULL) {
130 Dart_Handle str = ThrowIfError(DartUtils::NewString(result));
131 Dart_SetReturnValue(args, str);
132 } else {
133 Dart_SetReturnValue(args, DartUtils::NewDartOSError(&os_error));
134 }
135}
136
137void FUNCTION_NAME(Directory_Delete)(Dart_NativeArguments args) {
138 Namespace* namespc = Namespace::GetNamespace(args, 0);
139 Dart_Handle path = Dart_GetNativeArgument(args, 1);
140 OSError os_error;
141 bool result;
142 {
143 TypedDataScope data(path);
144 ASSERT(data.type() == Dart_TypedData_kUint8);
145 const char* name = data.GetCString();
146 result = Directory::Delete(namespc, name,
147 DartUtils::GetNativeBooleanArgument(args, 2));
148 if (!result) {
149 // Errors must be caught before TypedDataScope data is destroyed.
150 os_error.Reload();
151 }
152 }
153 if (result) {
154 Dart_SetBooleanReturnValue(args, true);
155 } else {
156 Dart_SetReturnValue(args, DartUtils::NewDartOSError(&os_error));
157 }
158}
159
160void FUNCTION_NAME(Directory_Rename)(Dart_NativeArguments args) {
161 Namespace* namespc = Namespace::GetNamespace(args, 0);
162 Dart_Handle path = Dart_GetNativeArgument(args, 1);
163 OSError os_error;
164 bool result;
165 {
166 TypedDataScope data(path);
167 ASSERT(data.type() == Dart_TypedData_kUint8);
168 const char* name = data.GetCString();
169 result = Directory::Rename(namespc, name,
170 DartUtils::GetNativeStringArgument(args, 2));
171 if (!result) {
172 // Errors must be caught before TypedDataScope data is destroyed.
173 os_error.Reload();
174 }
175 }
176 if (result) {
177 Dart_SetBooleanReturnValue(args, true);
178 } else {
179 Dart_SetReturnValue(args, DartUtils::NewDartOSError(&os_error));
180 }
181}
182
183void FUNCTION_NAME(Directory_FillWithDirectoryListing)(
184 Dart_NativeArguments args) {
185 Namespace* namespc = Namespace::GetNamespace(args, 0);
186 // The list that we should fill.
187 Dart_Handle results = Dart_GetNativeArgument(args, 1);
188 Dart_Handle path = Dart_GetNativeArgument(args, 2);
189 Dart_Handle dart_error;
190 const char* name;
191 {
192 TypedDataScope data(path);
193 ASSERT(data.type() == Dart_TypedData_kUint8);
194 // We need to release our typed data before creating SyncDirectoryListing
195 // since it allocates objects which require us to not be holding typed data
196 // that has been acquired.
197 name = data.GetScopedCString();
198 }
199 {
200 // Pass the list that should hold the directory listing to the
201 // SyncDirectoryListing object, which adds elements to it.
202 SyncDirectoryListing sync_listing(
203 results, namespc, name, DartUtils::GetNativeBooleanArgument(args, 3),
204 DartUtils::GetNativeBooleanArgument(args, 4));
205 Directory::List(&sync_listing);
206 dart_error = sync_listing.dart_error();
207 }
208 if (Dart_IsError(dart_error)) {
209 Dart_PropagateError(dart_error);
210 } else if (!Dart_IsNull(dart_error)) {
211 Dart_ThrowException(dart_error);
212 }
213}
214
215static const int kAsyncDirectoryListerFieldIndex = 0;
216
217void FUNCTION_NAME(Directory_GetAsyncDirectoryListerPointer)(
218 Dart_NativeArguments args) {
219 AsyncDirectoryListing* listing;
220 Dart_Handle dart_this = ThrowIfError(Dart_GetNativeArgument(args, 0));
221 ASSERT(Dart_IsInstance(dart_this));
222 ThrowIfError(
223 Dart_GetNativeInstanceField(dart_this, kAsyncDirectoryListerFieldIndex,
224 reinterpret_cast<intptr_t*>(&listing)));
225 if (listing != NULL) {
226 intptr_t listing_pointer = reinterpret_cast<intptr_t>(listing);
227 // Increment the listing's reference count. This native should only be
228 // be called when we are about to send the AsyncDirectoryListing* to the
229 // IO service.
230 listing->Retain();
231 Dart_SetReturnValue(args, Dart_NewInteger(listing_pointer));
232 }
233}
234
235static void ReleaseListing(void* isolate_callback_data, void* peer) {
236 AsyncDirectoryListing* listing =
237 reinterpret_cast<AsyncDirectoryListing*>(peer);
238 listing->Release();
239}
240
241void FUNCTION_NAME(Directory_SetAsyncDirectoryListerPointer)(
242 Dart_NativeArguments args) {
243 Dart_Handle dart_this = ThrowIfError(Dart_GetNativeArgument(args, 0));
244 intptr_t listing_pointer =
245 DartUtils::GetIntptrValue(Dart_GetNativeArgument(args, 1));
246 AsyncDirectoryListing* listing =
247 reinterpret_cast<AsyncDirectoryListing*>(listing_pointer);
248 Dart_NewFinalizableHandle(dart_this, reinterpret_cast<void*>(listing),
249 sizeof(*listing), ReleaseListing);
250 Dart_Handle result = Dart_SetNativeInstanceField(
251 dart_this, kAsyncDirectoryListerFieldIndex, listing_pointer);
252 ThrowIfError(result);
253}
254
255void Directory::SetSystemTemp(const char* path) {
256 if (system_temp_path_override_ != NULL) {
257 free(system_temp_path_override_);
258 system_temp_path_override_ = NULL;
259 }
260 if (path != NULL) {
261 system_temp_path_override_ = Utils::StrDup(path);
262 }
263}
264
265static Namespace* CObjectToNamespacePointer(CObject* cobject) {
266 CObjectIntptr value(cobject);
267 return reinterpret_cast<Namespace*>(value.Value());
268}
269
270CObject* Directory::CreateRequest(const CObjectArray& request) {
271 if ((request.Length() < 1) || !request[0]->IsIntptr()) {
272 return CObject::IllegalArgumentError();
273 }
274 Namespace* namespc = CObjectToNamespacePointer(request[0]);
275 RefCntReleaseScope<Namespace> rs(namespc);
276 if ((request.Length() != 2) || !request[1]->IsUint8Array()) {
277 return CObject::IllegalArgumentError();
278 }
279 CObjectUint8Array path(request[1]);
280 return Directory::Create(namespc,
281 reinterpret_cast<const char*>(path.Buffer()))
282 ? CObject::True()
283 : CObject::NewOSError();
284}
285
286CObject* Directory::DeleteRequest(const CObjectArray& request) {
287 if ((request.Length() < 1) || !request[0]->IsIntptr()) {
288 return CObject::IllegalArgumentError();
289 }
290 Namespace* namespc = CObjectToNamespacePointer(request[0]);
291 RefCntReleaseScope<Namespace> rs(namespc);
292 if ((request.Length() != 3) || !request[1]->IsUint8Array() ||
293 !request[2]->IsBool()) {
294 return CObject::IllegalArgumentError();
295 }
296 CObjectUint8Array path(request[1]);
297 CObjectBool recursive(request[2]);
298 return Directory::Delete(namespc,
299 reinterpret_cast<const char*>(path.Buffer()),
300 recursive.Value())
301 ? CObject::True()
302 : CObject::NewOSError();
303}
304
305CObject* Directory::ExistsRequest(const CObjectArray& request) {
306 static const int kExists = 1;
307 static const int kDoesNotExist = 0;
308 if ((request.Length() < 1) || !request[0]->IsIntptr()) {
309 return CObject::IllegalArgumentError();
310 }
311 Namespace* namespc = CObjectToNamespacePointer(request[0]);
312 RefCntReleaseScope<Namespace> rs(namespc);
313 if ((request.Length() != 2) || !request[1]->IsUint8Array()) {
314 return CObject::IllegalArgumentError();
315 }
316 CObjectUint8Array path(request[1]);
317 Directory::ExistsResult result =
318 Directory::Exists(namespc, reinterpret_cast<const char*>(path.Buffer()));
319 if (result == Directory::EXISTS) {
320 return new CObjectInt32(CObject::NewInt32(kExists));
321 } else if (result == Directory::DOES_NOT_EXIST) {
322 return new CObjectInt32(CObject::NewInt32(kDoesNotExist));
323 } else {
324 return CObject::NewOSError();
325 }
326}
327
328CObject* Directory::CreateTempRequest(const CObjectArray& request) {
329 if ((request.Length() < 1) || !request[0]->IsIntptr()) {
330 return CObject::IllegalArgumentError();
331 }
332 Namespace* namespc = CObjectToNamespacePointer(request[0]);
333 RefCntReleaseScope<Namespace> rs(namespc);
334 if ((request.Length() != 2) || !request[1]->IsUint8Array()) {
335 return CObject::IllegalArgumentError();
336 }
337 CObjectUint8Array path(request[1]);
338 const char* result = Directory::CreateTemp(
339 namespc, reinterpret_cast<const char*>(path.Buffer()));
340 if (result == NULL) {
341 return CObject::NewOSError();
342 }
343 return new CObjectString(CObject::NewString(result));
344}
345
346static CObject* CreateIllegalArgumentError() {
347 // Respond with an illegal argument list error message.
348 CObjectArray* error = new CObjectArray(CObject::NewArray(3));
349 error->SetAt(0, new CObjectInt32(
350 CObject::NewInt32(AsyncDirectoryListing::kListError)));
351 error->SetAt(1, CObject::Null());
352 error->SetAt(2, CObject::IllegalArgumentError());
353 return error;
354}
355
356CObject* Directory::ListStartRequest(const CObjectArray& request) {
357 if ((request.Length() < 1) || !request[0]->IsIntptr()) {
358 return CreateIllegalArgumentError();
359 }
360 Namespace* namespc = CObjectToNamespacePointer(request[0]);
361 RefCntReleaseScope<Namespace> rs(namespc);
362 if ((request.Length() != 4) || !request[1]->IsUint8Array() ||
363 !request[2]->IsBool() || !request[3]->IsBool()) {
364 return CreateIllegalArgumentError();
365 }
366 CObjectUint8Array path(request[1]);
367 CObjectBool recursive(request[2]);
368 CObjectBool follow_links(request[3]);
369 AsyncDirectoryListing* dir_listing = new AsyncDirectoryListing(
370 namespc, reinterpret_cast<const char*>(path.Buffer()), recursive.Value(),
371 follow_links.Value());
372 if (dir_listing->error()) {
373 // Report error now, so we capture the correct OSError.
374 CObject* err = CObject::NewOSError();
375 dir_listing->Release();
376 CObjectArray* error = new CObjectArray(CObject::NewArray(3));
377 error->SetAt(0, new CObjectInt32(
378 CObject::NewInt32(AsyncDirectoryListing::kListError)));
379 error->SetAt(1, request[1]);
380 error->SetAt(2, err);
381 return error;
382 }
383 // TODO(ajohnsen): Consider returning the first few results.
384 return new CObjectIntptr(
385 CObject::NewIntptr(reinterpret_cast<intptr_t>(dir_listing)));
386}
387
388CObject* Directory::ListNextRequest(const CObjectArray& request) {
389 if ((request.Length() != 1) || !request[0]->IsIntptr()) {
390 return CreateIllegalArgumentError();
391 }
392 CObjectIntptr ptr(request[0]);
393 AsyncDirectoryListing* dir_listing =
394 reinterpret_cast<AsyncDirectoryListing*>(ptr.Value());
395 RefCntReleaseScope<AsyncDirectoryListing> rs(dir_listing);
396 if (dir_listing->IsEmpty()) {
397 return new CObjectArray(CObject::NewArray(0));
398 }
399 const int kArraySize = 128;
400 CObjectArray* response = new CObjectArray(CObject::NewArray(kArraySize));
401 dir_listing->SetArray(response, kArraySize);
402 Directory::List(dir_listing);
403 // In case the listing ended before it hit the buffer length, we need to
404 // override the array length.
405 response->AsApiCObject()->value.as_array.length = dir_listing->index();
406 return response;
407}
408
409CObject* Directory::ListStopRequest(const CObjectArray& request) {
410 if ((request.Length() != 1) || !request[0]->IsIntptr()) {
411 return CreateIllegalArgumentError();
412 }
413 CObjectIntptr ptr(request[0]);
414 AsyncDirectoryListing* dir_listing =
415 reinterpret_cast<AsyncDirectoryListing*>(ptr.Value());
416 RefCntReleaseScope<AsyncDirectoryListing> rs(dir_listing);
417
418 // We have retained a reference to the listing here. Therefore the listing's
419 // destructor can't be running. Since no further requests are dispatched by
420 // the Dart code after an async stop call, this PopAll() can't be racing
421 // with any other call on the listing. We don't do an extra Release(), and
422 // we don't delete the weak persistent handle. The file is closed here, but
423 // the memory for the listing will be cleaned up when the finalizer runs.
424 dir_listing->PopAll();
425 return new CObjectBool(CObject::Bool(true));
426}
427
428CObject* Directory::RenameRequest(const CObjectArray& request) {
429 if ((request.Length() < 1) || !request[0]->IsIntptr()) {
430 return CObject::IllegalArgumentError();
431 }
432 Namespace* namespc = CObjectToNamespacePointer(request[0]);
433 RefCntReleaseScope<Namespace> rs(namespc);
434 if ((request.Length() != 3) || !request[1]->IsUint8Array() ||
435 !request[2]->IsString()) {
436 return CObject::IllegalArgumentError();
437 }
438 CObjectUint8Array path(request[1]);
439 CObjectString new_path(request[2]);
440 return Directory::Rename(namespc,
441 reinterpret_cast<const char*>(path.Buffer()),
442 new_path.CString())
443 ? CObject::True()
444 : CObject::NewOSError();
445}
446
447bool AsyncDirectoryListing::AddFileSystemEntityToResponse(Response type,
448 const char* arg) {
449 array_->SetAt(index_++, new CObjectInt32(CObject::NewInt32(type)));
450 if (arg != NULL) {
451 size_t len = strlen(arg);
452 Dart_CObject* io_buffer = CObject::NewIOBuffer(len);
453 uint8_t* data = io_buffer->value.as_external_typed_data.data;
454 memmove(reinterpret_cast<char*>(data), arg, len);
455
456 CObjectExternalUint8Array* external_array =
457 new CObjectExternalUint8Array(io_buffer);
458 array_->SetAt(index_++, external_array);
459 } else {
460 array_->SetAt(index_++, CObject::Null());
461 }
462 return index_ < length_;
463}
464
465bool AsyncDirectoryListing::HandleDirectory(const char* dir_name) {
466 return AddFileSystemEntityToResponse(kListDirectory, dir_name);
467}
468
469bool AsyncDirectoryListing::HandleFile(const char* file_name) {
470 return AddFileSystemEntityToResponse(kListFile, file_name);
471}
472
473bool AsyncDirectoryListing::HandleLink(const char* link_name) {
474 return AddFileSystemEntityToResponse(kListLink, link_name);
475}
476
477void AsyncDirectoryListing::HandleDone() {
478 AddFileSystemEntityToResponse(kListDone, NULL);
479}
480
481bool AsyncDirectoryListing::HandleError() {
482 CObject* err = CObject::NewOSError();
483 array_->SetAt(index_++, new CObjectInt32(CObject::NewInt32(kListError)));
484 CObjectArray* response = new CObjectArray(CObject::NewArray(3));
485 response->SetAt(0, new CObjectInt32(CObject::NewInt32(kListError)));
486 // Delay calling CurrentPath() until after CObject::NewOSError() in case
487 // CurrentPath() pollutes the OS error code.
488 response->SetAt(1, new CObjectString(CObject::NewString(
489 error() ? "Invalid path" : CurrentPath())));
490 response->SetAt(2, err);
491 array_->SetAt(index_++, response);
492 return index_ < length_;
493}
494
495bool SyncDirectoryListing::HandleDirectory(const char* dir_name) {
496 // Allocates a Uint8List for dir_name, and invokes the Directory.fromRawPath
497 // constructor. This avoids/delays interpreting the UTF-8 bytes in dir_name.
498 // Later, client code may either choose to access FileSystemEntity.path.
499 // FileSystemEntity.path will trigger UTF-8 decoding and return a path with
500 // non-UTF-8 characters replaced with U+FFFD.
501
502 size_t dir_name_length = strlen(dir_name);
503 uint8_t* buffer = NULL;
504 Dart_Handle dir_name_dart = IOBuffer::Allocate(dir_name_length, &buffer);
505 if (Dart_IsNull(dir_name_dart)) {
506 dart_error_ = DartUtils::NewDartOSError();
507 return false;
508 }
509 memmove(buffer, dir_name, dir_name_length);
510 Dart_Handle constructor_name = from_raw_path_string_;
511 Dart_Handle dir =
512 Dart_New(directory_type_, constructor_name, 1, &dir_name_dart);
513 Dart_Handle result = Dart_Invoke(results_, add_string_, 1, &dir);
514 if (Dart_IsError(result)) {
515 dart_error_ = result;
516 return false;
517 }
518 return true;
519}
520
521bool SyncDirectoryListing::HandleLink(const char* link_name) {
522 // Allocates a Uint8List for dir_name, and invokes the Directory.fromRawPath
523 // constructor. This avoids/delays interpreting the UTF-8 bytes in dir_name.
524 // Later, client code may either choose to access FileSystemEntity.path.
525 // FileSystemEntity.path will trigger UTF-8 decoding and return a path with
526 // non-UTF-8 characters replaced with U+FFFD.
527
528 size_t link_name_length = strlen(link_name);
529 uint8_t* buffer = NULL;
530 Dart_Handle link_name_dart = IOBuffer::Allocate(link_name_length, &buffer);
531 if (Dart_IsNull(link_name_dart)) {
532 dart_error_ = DartUtils::NewDartOSError();
533 return false;
534 }
535 memmove(buffer, link_name, link_name_length);
536 Dart_Handle constructor_name = from_raw_path_string_;
537 Dart_Handle link = Dart_New(link_type_, constructor_name, 1, &link_name_dart);
538 Dart_Handle result = Dart_Invoke(results_, add_string_, 1, &link);
539 if (Dart_IsError(result)) {
540 dart_error_ = result;
541 return false;
542 }
543 return true;
544}
545
546bool SyncDirectoryListing::HandleFile(const char* file_name) {
547 // Allocates a Uint8List for dir_name, and invokes the Directory.fromRawPath
548 // constructor. This avoids/delays interpreting the UTF-8 bytes in dir_name.
549 // Later, client code may either choose to access FileSystemEntity.path.
550 // FileSystemEntity.path will trigger UTF-8 decoding and return a path with
551 // non-UTF-8 characters replaced with U+FFFD.
552
553 size_t file_name_length = strlen(file_name);
554 uint8_t* buffer = NULL;
555 Dart_Handle file_name_dart = IOBuffer::Allocate(file_name_length, &buffer);
556 if (Dart_IsNull(file_name_dart)) {
557 dart_error_ = DartUtils::NewDartOSError();
558 return false;
559 }
560 memmove(buffer, file_name, file_name_length);
561 Dart_Handle constructor_name = from_raw_path_string_;
562 Dart_Handle file = Dart_New(file_type_, constructor_name, 1, &file_name_dart);
563 Dart_Handle result = Dart_Invoke(results_, add_string_, 1, &file);
564 if (Dart_IsError(result)) {
565 dart_error_ = result;
566 return false;
567 }
568 return true;
569}
570
571bool SyncDirectoryListing::HandleError() {
572 Dart_Handle dart_os_error = DartUtils::NewDartOSError();
573 Dart_Handle args[3];
574 args[0] = DartUtils::NewString("Directory listing failed");
575 args[1] = DartUtils::NewString(error() ? "Invalid path" : CurrentPath());
576 args[2] = dart_os_error;
577
578 dart_error_ = Dart_New(
579 DartUtils::GetDartType(DartUtils::kIOLibURL, "FileSystemException"),
580 Dart_Null(), 3, args);
581 return false;
582}
583
584static bool ListNext(DirectoryListing* listing) {
585 switch (listing->top()->Next(listing)) {
586 case kListFile:
587 return listing->HandleFile(listing->CurrentPath());
588
589 case kListLink:
590 return listing->HandleLink(listing->CurrentPath());
591
592 case kListDirectory:
593 if (listing->recursive()) {
594 listing->Push(new DirectoryListingEntry(listing->top()));
595 }
596 return listing->HandleDirectory(listing->CurrentPath());
597
598 case kListError:
599 return listing->HandleError();
600
601 case kListDone:
602 listing->Pop();
603 if (listing->IsEmpty()) {
604 listing->HandleDone();
605 return false;
606 } else {
607 return true;
608 }
609
610 default:
611 UNREACHABLE();
612 }
613 return false;
614}
615
616void Directory::List(DirectoryListing* listing) {
617 if (listing->error()) {
618 listing->HandleError();
619 listing->HandleDone();
620 } else {
621 while (ListNext(listing)) {
622 }
623 }
624}
625
626const char* Directory::Current(Namespace* namespc) {
627 return Namespace::GetCurrent(namespc);
628}
629
630bool Directory::SetCurrent(Namespace* namespc, const char* name) {
631 return Namespace::SetCurrent(namespc, name);
632}
633
634} // namespace bin
635} // namespace dart
636