// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. #include "bin/directory.h" #include "bin/dartutils.h" #include "bin/thread.h" #include "include/dart_api.h" #include "platform/assert.h" namespace dart { namespace bin { void FUNCTION_NAME(Directory_Current)(Dart_NativeArguments args) { char* current = Directory::Current(); if (current != NULL) { Dart_SetReturnValue(args, DartUtils::NewString(current)); free(current); } else { Dart_Handle err = DartUtils::NewDartOSError(); if (Dart_IsError(err)) Dart_PropagateError(err); Dart_SetReturnValue(args, err); } } void FUNCTION_NAME(Directory_SetCurrent)(Dart_NativeArguments args) { int argc = Dart_GetNativeArgumentCount(args); Dart_Handle path; if (argc == 1) { path = Dart_GetNativeArgument(args, 0); } if (argc != 1 || !Dart_IsString(path)) { Dart_SetReturnValue(args, DartUtils::NewDartArgumentError(NULL)); } else { if (Directory::SetCurrent(DartUtils::GetStringValue(path))) { Dart_SetReturnValue(args, Dart_True()); } else { Dart_Handle err = DartUtils::NewDartOSError(); if (Dart_IsError(err)) Dart_PropagateError(err); Dart_SetReturnValue(args, err); } } } void FUNCTION_NAME(Directory_Exists)(Dart_NativeArguments args) { static const int kExists = 1; static const int kDoesNotExist = 0; Dart_Handle path = Dart_GetNativeArgument(args, 0); Directory::ExistsResult result = Directory::Exists(DartUtils::GetStringValue(path)); if (result == Directory::EXISTS) { Dart_SetReturnValue(args, Dart_NewInteger(kExists)); } else if (result == Directory::DOES_NOT_EXIST) { Dart_SetReturnValue(args, Dart_NewInteger(kDoesNotExist)); } else { Dart_Handle err = DartUtils::NewDartOSError(); if (Dart_IsError(err)) Dart_PropagateError(err); Dart_SetReturnValue(args, err); } } void FUNCTION_NAME(Directory_Create)(Dart_NativeArguments args) { Dart_Handle path = Dart_GetNativeArgument(args, 0); if (Directory::Create(DartUtils::GetStringValue(path))) { Dart_SetReturnValue(args, Dart_True()); } else { Dart_Handle err = DartUtils::NewDartOSError(); if (Dart_IsError(err)) Dart_PropagateError(err); Dart_SetReturnValue(args, err); } } void FUNCTION_NAME(Directory_SystemTemp)( Dart_NativeArguments args) { char* result = Directory::SystemTemp(); Dart_SetReturnValue(args, DartUtils::NewString(result)); free(result); } void FUNCTION_NAME(Directory_CreateTemp)(Dart_NativeArguments args) { Dart_Handle path = Dart_GetNativeArgument(args, 0); if (!Dart_IsString(path)) { Dart_SetReturnValue(args, DartUtils::NewDartArgumentError( "Prefix argument of CreateSystemTempSync is not a String")); return; } char* result = Directory::CreateTemp(DartUtils::GetStringValue(path)); if (result != NULL) { Dart_SetReturnValue(args, DartUtils::NewString(result)); free(result); } else { Dart_Handle err = DartUtils::NewDartOSError(); if (Dart_IsError(err)) Dart_PropagateError(err); Dart_SetReturnValue(args, err); } } void FUNCTION_NAME(Directory_Delete)(Dart_NativeArguments args) { Dart_Handle path = Dart_GetNativeArgument(args, 0); Dart_Handle recursive = Dart_GetNativeArgument(args, 1); if (Directory::Delete(DartUtils::GetStringValue(path), DartUtils::GetBooleanValue(recursive))) { Dart_SetReturnValue(args, Dart_True()); } else { Dart_Handle err = DartUtils::NewDartOSError(); if (Dart_IsError(err)) Dart_PropagateError(err); Dart_SetReturnValue(args, err); } } void FUNCTION_NAME(Directory_Rename)(Dart_NativeArguments args) { Dart_Handle path = Dart_GetNativeArgument(args, 0); Dart_Handle newPath = Dart_GetNativeArgument(args, 1); if (Directory::Rename(DartUtils::GetStringValue(path), DartUtils::GetStringValue(newPath))) { Dart_SetReturnValue(args, Dart_True()); } else { Dart_Handle err = DartUtils::NewDartOSError(); if (Dart_IsError(err)) Dart_PropagateError(err); Dart_SetReturnValue(args, err); } } void FUNCTION_NAME(Directory_List)(Dart_NativeArguments args) { Dart_Handle path = Dart_GetNativeArgument(args, 0); Dart_Handle recursive = Dart_GetNativeArgument(args, 1); // Create the list to hold the directory listing here, and pass it to the // SyncDirectoryListing object, which adds elements to it. Dart_Handle follow_links = Dart_GetNativeArgument(args, 2); // Create the list to hold the directory listing here, and pass it to the // SyncDirectoryListing object, which adds elements to it. Dart_Handle results = Dart_New(DartUtils::GetDartType(DartUtils::kCoreLibURL, "List"), Dart_Null(), 0, NULL); SyncDirectoryListing sync_listing(results, DartUtils::GetStringValue(path), DartUtils::GetBooleanValue(recursive), DartUtils::GetBooleanValue(follow_links)); Directory::List(&sync_listing); Dart_SetReturnValue(args, results); } CObject* Directory::CreateRequest(const CObjectArray& request) { if (request.Length() == 1 && request[0]->IsString()) { CObjectString path(request[0]); if (Directory::Create(path.CString())) { return CObject::True(); } else { return CObject::NewOSError(); } } return CObject::IllegalArgumentError(); } CObject* Directory::DeleteRequest(const CObjectArray& request) { if (request.Length() == 2 && request[0]->IsString() && request[1]->IsBool()) { CObjectString path(request[0]); CObjectBool recursive(request[1]); if (Directory::Delete(path.CString(), recursive.Value())) { return CObject::True(); } else { return CObject::NewOSError(); } } return CObject::IllegalArgumentError(); } CObject* Directory::ExistsRequest(const CObjectArray& request) { static const int kExists = 1; static const int kDoesNotExist = 0; if (request.Length() == 1 && request[0]->IsString()) { CObjectString path(request[0]); Directory::ExistsResult result = Directory::Exists(path.CString()); if (result == Directory::EXISTS) { return new CObjectInt32(CObject::NewInt32(kExists)); } else if (result == Directory::DOES_NOT_EXIST) { return new CObjectInt32(CObject::NewInt32(kDoesNotExist)); } else { return CObject::NewOSError(); } } return CObject::IllegalArgumentError(); } CObject* Directory::CreateTempRequest(const CObjectArray& request) { if (request.Length() == 1 && request[0]->IsString()) { CObjectString path(request[0]); char* result = Directory::CreateTemp(path.CString()); if (result != NULL) { CObject* temp_dir = new CObjectString(CObject::NewString(result)); free(result); return temp_dir; } else { return CObject::NewOSError(); } } return CObject::IllegalArgumentError(); } static CObject* CreateIllegalArgumentError() { // Respond with an illegal argument list error message. CObjectArray* error = new CObjectArray(CObject::NewArray(3)); error->SetAt(0, new CObjectInt32( CObject::NewInt32(AsyncDirectoryListing::kListError))); error->SetAt(1, CObject::Null()); error->SetAt(2, CObject::IllegalArgumentError()); return error; } CObject* Directory::ListStartRequest(const CObjectArray& request) { if (request.Length() == 3 && request[0]->IsString() && request[1]->IsBool() && request[2]->IsBool()) { CObjectString path(request[0]); CObjectBool recursive(request[1]); CObjectBool follow_links(request[2]); AsyncDirectoryListing* dir_listing = new AsyncDirectoryListing(path.CString(), recursive.Value(), follow_links.Value()); if (dir_listing->error()) { // Report error now, so we capture the correct OSError. CObject* err = CObject::NewOSError(); delete dir_listing; CObjectArray* error = new CObjectArray(CObject::NewArray(3)); error->SetAt(0, new CObjectInt32( CObject::NewInt32(AsyncDirectoryListing::kListError))); error->SetAt(1, request[0]); error->SetAt(2, err); return error; } // TODO(ajohnsen): Consider returning the first few results. return new CObjectIntptr(CObject::NewIntptr( reinterpret_cast(dir_listing))); } return CreateIllegalArgumentError(); } CObject* Directory::ListNextRequest(const CObjectArray& request) { if (request.Length() == 1 && request[0]->IsIntptr()) { CObjectIntptr ptr(request[0]); AsyncDirectoryListing* dir_listing = reinterpret_cast(ptr.Value()); if (dir_listing->IsEmpty()) { return new CObjectArray(CObject::NewArray(0)); } const int kArraySize = 128; CObjectArray* response = new CObjectArray(CObject::NewArray(kArraySize)); dir_listing->SetArray(response, kArraySize); Directory::List(dir_listing); // In case the listing ended before it hit the buffer length, we need to // override the array length. response->AsApiCObject()->value.as_array.length = dir_listing->index(); return response; } return CreateIllegalArgumentError(); } CObject* Directory::ListStopRequest(const CObjectArray& request) { if (request.Length() == 1 && request[0]->IsIntptr()) { CObjectIntptr ptr(request[0]); AsyncDirectoryListing* dir_listing = reinterpret_cast(ptr.Value()); delete dir_listing; return new CObjectBool(CObject::Bool(true)); } return CreateIllegalArgumentError(); } CObject* Directory::RenameRequest(const CObjectArray& request) { if (request.Length() == 2 && request[0]->IsString() && request[1]->IsString()) { CObjectString path(request[0]); CObjectString new_path(request[1]); bool completed = Directory::Rename(path.CString(), new_path.CString()); if (completed) return CObject::True(); return CObject::NewOSError(); } return CObject::IllegalArgumentError(); } bool AsyncDirectoryListing::AddFileSystemEntityToResponse(Response type, char* arg) { array_->SetAt(index_++, new CObjectInt32(CObject::NewInt32(type))); if (arg != NULL) { array_->SetAt(index_++, new CObjectString(CObject::NewString(arg))); } else { array_->SetAt(index_++, CObject::Null()); } return index_ < length_; } bool AsyncDirectoryListing::HandleDirectory(char* dir_name) { return AddFileSystemEntityToResponse(kListDirectory, dir_name); } bool AsyncDirectoryListing::HandleFile(char* file_name) { return AddFileSystemEntityToResponse(kListFile, file_name); } bool AsyncDirectoryListing::HandleLink(char* link_name) { return AddFileSystemEntityToResponse(kListLink, link_name); } void AsyncDirectoryListing::HandleDone() { AddFileSystemEntityToResponse(kListDone, NULL); } bool AsyncDirectoryListing::HandleError(const char* dir_name) { CObject* err = CObject::NewOSError(); array_->SetAt(index_++, new CObjectInt32(CObject::NewInt32(kListError))); CObjectArray* response = new CObjectArray(CObject::NewArray(3)); response->SetAt(0, new CObjectInt32(CObject::NewInt32(kListError))); response->SetAt(1, new CObjectString(CObject::NewString(dir_name))); response->SetAt(2, err); array_->SetAt(index_++, response); return index_ < length_; } bool SyncDirectoryListing::HandleDirectory(char* dir_name) { Dart_Handle dir_name_dart = DartUtils::NewString(dir_name); Dart_Handle dir = Dart_New(directory_type_, Dart_Null(), 1, &dir_name_dart); Dart_Invoke(results_, add_string_, 1, &dir); return true; } bool SyncDirectoryListing::HandleLink(char* link_name) { Dart_Handle link_name_dart = DartUtils::NewString(link_name); Dart_Handle link = Dart_New(link_type_, Dart_Null(), 1, &link_name_dart); Dart_Invoke(results_, add_string_, 1, &link); return true; } bool SyncDirectoryListing::HandleFile(char* file_name) { Dart_Handle file_name_dart = DartUtils::NewString(file_name); Dart_Handle file = Dart_New(file_type_, Dart_Null(), 1, &file_name_dart); Dart_Invoke(results_, add_string_, 1, &file); return true; } bool SyncDirectoryListing::HandleError(const char* dir_name) { Dart_Handle dart_os_error = DartUtils::NewDartOSError(); Dart_Handle args[3]; args[0] = DartUtils::NewString("Directory listing failed"); args[1] = DartUtils::NewString(dir_name); args[2] = dart_os_error; Dart_ThrowException(Dart_New( DartUtils::GetDartType(DartUtils::kIOLibURL, "FileSystemException"), Dart_Null(), 3, args)); return true; } static bool ListNext(DirectoryListing* listing) { switch (listing->top()->Next(listing)) { case kListFile: return listing->HandleFile(listing->CurrentPath()); case kListLink: return listing->HandleLink(listing->CurrentPath()); case kListDirectory: if (listing->recursive()) { listing->Push(new DirectoryListingEntry(listing->top())); } return listing->HandleDirectory(listing->CurrentPath()); case kListError: return listing->HandleError(listing->CurrentPath()); case kListDone: listing->Pop(); if (listing->IsEmpty()) { listing->HandleDone(); return false; } else { return true; } default: UNREACHABLE(); } return false; } void Directory::List(DirectoryListing* listing) { if (listing->error()) { listing->HandleError("Invalid path"); listing->HandleDone(); } else { while (ListNext(listing)) {} } } } // namespace bin } // namespace dart