// Copyright (c) 2013, 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. #if !defined(DART_IO_DISABLED) #include "bin/file.h" #include "bin/builtin.h" #include "bin/dartutils.h" #include "bin/embedded_dart_io.h" #include "bin/io_buffer.h" #include "bin/utils.h" #include "include/dart_api.h" #include "include/dart_tools_api.h" #include "platform/globals.h" namespace dart { namespace bin { static const int kFileNativeFieldIndex = 0; // The file pointer has been passed into Dart as an intptr_t and it is safe // to pull it out of Dart as a 64-bit integer, cast it to an intptr_t and // from there to a File pointer. static File* GetFile(Dart_NativeArguments args) { File* file; Dart_Handle dart_this = ThrowIfError(Dart_GetNativeArgument(args, 0)); ASSERT(Dart_IsInstance(dart_this)); ThrowIfError(Dart_GetNativeInstanceField(dart_this, kFileNativeFieldIndex, reinterpret_cast(&file))); return file; } static void SetFile(Dart_Handle dart_this, intptr_t file_pointer) { Dart_Handle result = Dart_SetNativeInstanceField( dart_this, kFileNativeFieldIndex, file_pointer); if (Dart_IsError(result)) { Log::PrintErr("SetNativeInstanceField in SetFile() failed\n"); Dart_PropagateError(result); } } void FUNCTION_NAME(File_GetPointer)(Dart_NativeArguments args) { File* file = GetFile(args); // If the file is already closed, GetFile() will return NULL. if (file != NULL) { // Increment file's reference count. File_GetPointer() should only be called // when we are about to send the File* to the IO Service. file->Retain(); } intptr_t file_pointer = reinterpret_cast(file); Dart_SetReturnValue(args, Dart_NewInteger(file_pointer)); } static void ReleaseFile(void* isolate_callback_data, Dart_WeakPersistentHandle handle, void* peer) { File* file = reinterpret_cast(peer); file->Release(); } void FUNCTION_NAME(File_SetPointer)(Dart_NativeArguments args) { Dart_Handle dart_this = ThrowIfError(Dart_GetNativeArgument(args, 0)); intptr_t file_pointer = DartUtils::GetIntptrValue(Dart_GetNativeArgument(args, 1)); File* file = reinterpret_cast(file_pointer); Dart_WeakPersistentHandle handle = Dart_NewWeakPersistentHandle( dart_this, reinterpret_cast(file), sizeof(*file), ReleaseFile); file->SetWeakHandle(handle); SetFile(dart_this, file_pointer); } void FUNCTION_NAME(File_SetTranslation)(Dart_NativeArguments args) { File* file = GetFile(args); ASSERT(file != NULL); int64_t translation; Dart_Handle status = Dart_GetNativeIntegerArgument(args, 1, &translation); if (Dart_IsError(status)) { Dart_PropagateError(status); } if ((translation != File::kText) && (translation != File::kBinary)) { Dart_ThrowException(DartUtils::NewDartArgumentError( "The argument must be a FileTranslation mode")); } file->SetTranslation(static_cast(translation)); } void FUNCTION_NAME(File_Open)(Dart_NativeArguments args) { const char* filename = DartUtils::GetStringValue(Dart_GetNativeArgument(args, 0)); int64_t mode = DartUtils::GetIntegerValue(Dart_GetNativeArgument(args, 1)); File::DartFileOpenMode dart_file_mode = static_cast(mode); File::FileOpenMode file_mode = File::DartModeToFileMode(dart_file_mode); // Check that the file exists before opening it only for // reading. This is to prevent the opening of directories as // files. Directories can be opened for reading using the posix // 'open' call. File* file = File::Open(filename, file_mode); if (file != NULL) { Dart_SetReturnValue(args, Dart_NewInteger(reinterpret_cast(file))); } else { Dart_SetReturnValue(args, DartUtils::NewDartOSError()); } } void FUNCTION_NAME(File_Exists)(Dart_NativeArguments args) { const char* filename = DartUtils::GetStringValue(Dart_GetNativeArgument(args, 0)); bool exists = File::Exists(filename); Dart_SetReturnValue(args, Dart_NewBoolean(exists)); } void FUNCTION_NAME(File_Close)(Dart_NativeArguments args) { File* file = GetFile(args); ASSERT(file != NULL); file->Close(); file->DeleteWeakHandle(Dart_CurrentIsolate()); file->Release(); // NULL-out the now potentially dangling pointer. Dart_Handle dart_this = Dart_GetNativeArgument(args, 0); SetFile(dart_this, 0); Dart_SetReturnValue(args, Dart_NewInteger(0)); } void FUNCTION_NAME(File_ReadByte)(Dart_NativeArguments args) { File* file = GetFile(args); ASSERT(file != NULL); uint8_t buffer; int64_t bytes_read = file->Read(reinterpret_cast(&buffer), 1); if (bytes_read == 1) { Dart_SetReturnValue(args, Dart_NewInteger(buffer)); } else if (bytes_read == 0) { Dart_SetReturnValue(args, Dart_NewInteger(-1)); } else { Dart_SetReturnValue(args, DartUtils::NewDartOSError()); } } void FUNCTION_NAME(File_WriteByte)(Dart_NativeArguments args) { File* file = GetFile(args); ASSERT(file != NULL); int64_t byte = 0; if (DartUtils::GetInt64Value(Dart_GetNativeArgument(args, 1), &byte)) { uint8_t buffer = static_cast(byte & 0xff); bool success = file->WriteFully(reinterpret_cast(&buffer), 1); if (success) { Dart_SetReturnValue(args, Dart_NewInteger(1)); } else { Dart_SetReturnValue(args, DartUtils::NewDartOSError()); } } else { OSError os_error(-1, "Invalid argument", OSError::kUnknown); Dart_SetReturnValue(args, DartUtils::NewDartOSError(&os_error)); } } void FUNCTION_NAME(File_Read)(Dart_NativeArguments args) { File* file = GetFile(args); ASSERT(file != NULL); Dart_Handle length_object = Dart_GetNativeArgument(args, 1); int64_t length = 0; if (DartUtils::GetInt64Value(length_object, &length)) { uint8_t* buffer = NULL; Dart_Handle external_array = IOBuffer::Allocate(length, &buffer); int64_t bytes_read = file->Read(reinterpret_cast(buffer), length); if (bytes_read < 0) { Dart_SetReturnValue(args, DartUtils::NewDartOSError()); } else { if (bytes_read < length) { const int kNumArgs = 3; Dart_Handle dart_args[kNumArgs]; dart_args[0] = external_array; dart_args[1] = Dart_NewInteger(0); dart_args[2] = Dart_NewInteger(bytes_read); // TODO(sgjesse): Cache the _makeUint8ListView function somewhere. Dart_Handle io_lib = Dart_LookupLibrary(DartUtils::NewString("dart:io")); if (Dart_IsError(io_lib)) { Dart_PropagateError(io_lib); } Dart_Handle array_view = Dart_Invoke(io_lib, DartUtils::NewString("_makeUint8ListView"), kNumArgs, dart_args); Dart_SetReturnValue(args, array_view); } else { Dart_SetReturnValue(args, external_array); } } } else { OSError os_error(-1, "Invalid argument", OSError::kUnknown); Dart_SetReturnValue(args, DartUtils::NewDartOSError(&os_error)); } } void FUNCTION_NAME(File_ReadInto)(Dart_NativeArguments args) { File* file = GetFile(args); ASSERT(file != NULL); Dart_Handle buffer_obj = Dart_GetNativeArgument(args, 1); ASSERT(Dart_IsList(buffer_obj)); // start and end arguments are checked in Dart code to be // integers and have the property that end <= // list.length. Therefore, it is safe to extract their value as // intptr_t. intptr_t start = DartUtils::GetIntptrValue(Dart_GetNativeArgument(args, 2)); intptr_t end = DartUtils::GetIntptrValue(Dart_GetNativeArgument(args, 3)); intptr_t length = end - start; intptr_t array_len = 0; Dart_Handle result = Dart_ListLength(buffer_obj, &array_len); if (Dart_IsError(result)) { Dart_PropagateError(result); } ASSERT(end <= array_len); uint8_t* buffer = Dart_ScopeAllocate(length); int64_t bytes_read = file->Read(reinterpret_cast(buffer), length); if (bytes_read >= 0) { result = Dart_ListSetAsBytes(buffer_obj, start, buffer, bytes_read); if (Dart_IsError(result)) { Dart_SetReturnValue(args, result); } else { Dart_SetReturnValue(args, Dart_NewInteger(bytes_read)); } } else { Dart_SetReturnValue(args, DartUtils::NewDartOSError()); } } void FUNCTION_NAME(File_WriteFrom)(Dart_NativeArguments args) { File* file = GetFile(args); ASSERT(file != NULL); Dart_Handle buffer_obj = Dart_GetNativeArgument(args, 1); // Offset and length arguments are checked in Dart code to be // integers and have the property that (offset + length) <= // list.length. Therefore, it is safe to extract their value as // intptr_t. intptr_t start = DartUtils::GetIntptrValue(Dart_GetNativeArgument(args, 2)); intptr_t end = DartUtils::GetIntptrValue(Dart_GetNativeArgument(args, 3)); // The buffer object passed in has to be an Int8List or Uint8List object. // Acquire a direct pointer to the data area of the buffer object. Dart_TypedData_Type type; intptr_t length = end - start; intptr_t buffer_len = 0; void* buffer = NULL; Dart_Handle result = Dart_TypedDataAcquireData(buffer_obj, &type, &buffer, &buffer_len); if (Dart_IsError(result)) { Dart_PropagateError(result); } ASSERT(type == Dart_TypedData_kUint8 || type == Dart_TypedData_kInt8); ASSERT(end <= buffer_len); ASSERT(buffer != NULL); // Write all the data out into the file. char* byte_buffer = reinterpret_cast(buffer); bool success = file->WriteFully(byte_buffer + start, length); // Release the direct pointer acquired above. result = Dart_TypedDataReleaseData(buffer_obj); if (Dart_IsError(result)) { Dart_PropagateError(result); } if (!success) { Dart_SetReturnValue(args, DartUtils::NewDartOSError()); } else { Dart_SetReturnValue(args, Dart_Null()); } } void FUNCTION_NAME(File_Position)(Dart_NativeArguments args) { File* file = GetFile(args); ASSERT(file != NULL); intptr_t return_value = file->Position(); if (return_value >= 0) { Dart_SetReturnValue(args, Dart_NewInteger(return_value)); } else { Dart_SetReturnValue(args, DartUtils::NewDartOSError()); } } void FUNCTION_NAME(File_SetPosition)(Dart_NativeArguments args) { File* file = GetFile(args); ASSERT(file != NULL); int64_t position = 0; if (DartUtils::GetInt64Value(Dart_GetNativeArgument(args, 1), &position)) { if (file->SetPosition(position)) { Dart_SetReturnValue(args, Dart_True()); } else { Dart_SetReturnValue(args, DartUtils::NewDartOSError()); } } else { OSError os_error(-1, "Invalid argument", OSError::kUnknown); Dart_SetReturnValue(args, DartUtils::NewDartOSError(&os_error)); } } void FUNCTION_NAME(File_Truncate)(Dart_NativeArguments args) { File* file = GetFile(args); ASSERT(file != NULL); int64_t length = 0; if (DartUtils::GetInt64Value(Dart_GetNativeArgument(args, 1), &length)) { if (file->Truncate(length)) { Dart_SetReturnValue(args, Dart_True()); } else { Dart_SetReturnValue(args, DartUtils::NewDartOSError()); } } else { OSError os_error(-1, "Invalid argument", OSError::kUnknown); Dart_SetReturnValue(args, DartUtils::NewDartOSError(&os_error)); } } void FUNCTION_NAME(File_Length)(Dart_NativeArguments args) { File* file = GetFile(args); ASSERT(file != NULL); int64_t return_value = file->Length(); if (return_value >= 0) { Dart_SetReturnValue(args, Dart_NewInteger(return_value)); } else { Dart_SetReturnValue(args, DartUtils::NewDartOSError()); } } void FUNCTION_NAME(File_LengthFromPath)(Dart_NativeArguments args) { const char* path = DartUtils::GetStringValue(Dart_GetNativeArgument(args, 0)); int64_t return_value = File::LengthFromPath(path); if (return_value >= 0) { Dart_SetReturnValue(args, Dart_NewInteger(return_value)); } else { Dart_SetReturnValue(args, DartUtils::NewDartOSError()); } } void FUNCTION_NAME(File_LastModified)(Dart_NativeArguments args) { const char* name = DartUtils::GetStringValue(Dart_GetNativeArgument(args, 0)); int64_t return_value = File::LastModified(name); if (return_value >= 0) { Dart_SetReturnValue(args, Dart_NewInteger(return_value * kMillisecondsPerSecond)); } else { Dart_SetReturnValue(args, DartUtils::NewDartOSError()); } } void FUNCTION_NAME(File_SetLastModified)(Dart_NativeArguments args) { const char* name = DartUtils::GetStringValue(Dart_GetNativeArgument(args, 0)); int64_t millis; if (!DartUtils::GetInt64Value(Dart_GetNativeArgument(args, 1), &millis)) { Dart_ThrowException(DartUtils::NewDartArgumentError( "The second argument must be a 64-bit int.")); } if (!File::SetLastModified(name, millis)) { Dart_SetReturnValue(args, DartUtils::NewDartOSError()); } } void FUNCTION_NAME(File_LastAccessed)(Dart_NativeArguments args) { const char* name = DartUtils::GetStringValue(Dart_GetNativeArgument(args, 0)); int64_t return_value = File::LastAccessed(name); if (return_value >= 0) { Dart_SetReturnValue(args, Dart_NewInteger(return_value * kMillisecondsPerSecond)); } else { Dart_SetReturnValue(args, DartUtils::NewDartOSError()); } } void FUNCTION_NAME(File_SetLastAccessed)(Dart_NativeArguments args) { const char* name = DartUtils::GetStringValue(Dart_GetNativeArgument(args, 0)); int64_t millis; if (!DartUtils::GetInt64Value(Dart_GetNativeArgument(args, 1), &millis)) { Dart_ThrowException(DartUtils::NewDartArgumentError( "The second argument must be a 64-bit int.")); } if (!File::SetLastAccessed(name, millis)) { Dart_SetReturnValue(args, DartUtils::NewDartOSError()); } } void FUNCTION_NAME(File_Flush)(Dart_NativeArguments args) { File* file = GetFile(args); ASSERT(file != NULL); if (file->Flush()) { Dart_SetReturnValue(args, Dart_True()); } else { Dart_SetReturnValue(args, DartUtils::NewDartOSError()); } } void FUNCTION_NAME(File_Lock)(Dart_NativeArguments args) { File* file = GetFile(args); ASSERT(file != NULL); int64_t lock; int64_t start; int64_t end; if (DartUtils::GetInt64Value(Dart_GetNativeArgument(args, 1), &lock) && DartUtils::GetInt64Value(Dart_GetNativeArgument(args, 2), &start) && DartUtils::GetInt64Value(Dart_GetNativeArgument(args, 3), &end)) { if ((lock >= File::kLockMin) && (lock <= File::kLockMax) && (start >= 0) && (end == -1 || end > start)) { if (file->Lock(static_cast(lock), start, end)) { Dart_SetReturnValue(args, Dart_True()); } else { Dart_SetReturnValue(args, DartUtils::NewDartOSError()); } return; } } OSError os_error(-1, "Invalid argument", OSError::kUnknown); Dart_SetReturnValue(args, DartUtils::NewDartOSError(&os_error)); } void FUNCTION_NAME(File_Create)(Dart_NativeArguments args) { const char* str = DartUtils::GetStringValue(Dart_GetNativeArgument(args, 0)); bool result = File::Create(str); if (result) { Dart_SetReturnValue(args, Dart_NewBoolean(result)); } else { Dart_SetReturnValue(args, DartUtils::NewDartOSError()); } } void FUNCTION_NAME(File_CreateLink)(Dart_NativeArguments args) { if (Dart_IsString(Dart_GetNativeArgument(args, 0)) && Dart_IsString(Dart_GetNativeArgument(args, 1))) { const char* name = DartUtils::GetStringValue(Dart_GetNativeArgument(args, 0)); const char* target = DartUtils::GetStringValue(Dart_GetNativeArgument(args, 1)); if (!File::CreateLink(name, target)) { Dart_SetReturnValue(args, DartUtils::NewDartOSError()); } } else { Dart_Handle err = DartUtils::NewDartArgumentError("Non-string argument to Link.create"); Dart_SetReturnValue(args, err); } } void FUNCTION_NAME(File_LinkTarget)(Dart_NativeArguments args) { if (Dart_IsString(Dart_GetNativeArgument(args, 0))) { const char* name = DartUtils::GetStringValue(Dart_GetNativeArgument(args, 0)); const char* target = File::LinkTarget(name); if (target == NULL) { Dart_SetReturnValue(args, DartUtils::NewDartOSError()); } else { Dart_SetReturnValue(args, DartUtils::NewString(target)); } } else { Dart_Handle err = DartUtils::NewDartArgumentError("Non-string argument to Link.target"); Dart_SetReturnValue(args, err); } } void FUNCTION_NAME(File_Delete)(Dart_NativeArguments args) { const char* str = DartUtils::GetStringValue(Dart_GetNativeArgument(args, 0)); bool result = File::Delete(str); if (result) { Dart_SetReturnValue(args, Dart_NewBoolean(result)); } else { Dart_SetReturnValue(args, DartUtils::NewDartOSError()); } } void FUNCTION_NAME(File_DeleteLink)(Dart_NativeArguments args) { const char* str = DartUtils::GetStringValue(Dart_GetNativeArgument(args, 0)); bool result = File::DeleteLink(str); if (result) { Dart_SetReturnValue(args, Dart_NewBoolean(result)); } else { Dart_SetReturnValue(args, DartUtils::NewDartOSError()); } } void FUNCTION_NAME(File_Rename)(Dart_NativeArguments args) { const char* old_path = DartUtils::GetStringValue(Dart_GetNativeArgument(args, 0)); const char* new_path = DartUtils::GetStringValue(Dart_GetNativeArgument(args, 1)); bool result = File::Rename(old_path, new_path); if (result) { Dart_SetReturnValue(args, Dart_NewBoolean(result)); } else { Dart_SetReturnValue(args, DartUtils::NewDartOSError()); } } void FUNCTION_NAME(File_RenameLink)(Dart_NativeArguments args) { const char* old_path = DartUtils::GetStringValue(Dart_GetNativeArgument(args, 0)); const char* new_path = DartUtils::GetStringValue(Dart_GetNativeArgument(args, 1)); bool result = File::RenameLink(old_path, new_path); if (result) { Dart_SetReturnValue(args, Dart_NewBoolean(result)); } else { Dart_SetReturnValue(args, DartUtils::NewDartOSError()); } } void FUNCTION_NAME(File_Copy)(Dart_NativeArguments args) { const char* old_path = DartUtils::GetStringValue(Dart_GetNativeArgument(args, 0)); const char* new_path = DartUtils::GetStringValue(Dart_GetNativeArgument(args, 1)); bool result = File::Copy(old_path, new_path); if (result) { Dart_SetReturnValue(args, Dart_NewBoolean(result)); } else { Dart_SetReturnValue(args, DartUtils::NewDartOSError()); } } void FUNCTION_NAME(File_ResolveSymbolicLinks)(Dart_NativeArguments args) { const char* str = DartUtils::GetStringValue(Dart_GetNativeArgument(args, 0)); const char* path = File::GetCanonicalPath(str); if (path != NULL) { Dart_SetReturnValue(args, DartUtils::NewString(path)); } else { Dart_SetReturnValue(args, DartUtils::NewDartOSError()); } } void FUNCTION_NAME(File_OpenStdio)(Dart_NativeArguments args) { int64_t fd = DartUtils::GetIntegerValue(Dart_GetNativeArgument(args, 0)); ASSERT((fd == STDIN_FILENO) || (fd == STDOUT_FILENO) || (fd == STDERR_FILENO)); File* file = File::OpenStdio(static_cast(fd)); Dart_SetReturnValue(args, Dart_NewInteger(reinterpret_cast(file))); } void FUNCTION_NAME(File_GetStdioHandleType)(Dart_NativeArguments args) { int64_t fd = DartUtils::GetIntegerValue(Dart_GetNativeArgument(args, 0)); ASSERT((fd == STDIN_FILENO) || (fd == STDOUT_FILENO) || (fd == STDERR_FILENO)); File::StdioHandleType type = File::GetStdioHandleType(static_cast(fd)); Dart_SetReturnValue(args, Dart_NewInteger(type)); } void FUNCTION_NAME(File_GetType)(Dart_NativeArguments args) { if (Dart_IsString(Dart_GetNativeArgument(args, 0)) && Dart_IsBoolean(Dart_GetNativeArgument(args, 1))) { const char* str = DartUtils::GetStringValue(Dart_GetNativeArgument(args, 0)); bool follow_links = DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 1)); File::Type type = File::GetType(str, follow_links); Dart_SetReturnValue(args, Dart_NewInteger(static_cast(type))); } else { Dart_Handle err = DartUtils::NewDartArgumentError( "Non-string argument to FileSystemEntity.type"); Dart_SetReturnValue(args, err); } } void FUNCTION_NAME(File_Stat)(Dart_NativeArguments args) { if (Dart_IsString(Dart_GetNativeArgument(args, 0))) { const char* path = DartUtils::GetStringValue(Dart_GetNativeArgument(args, 0)); int64_t stat_data[File::kStatSize]; File::Stat(path, stat_data); if (stat_data[File::kType] == File::kDoesNotExist) { Dart_SetReturnValue(args, DartUtils::NewDartOSError()); } else { Dart_Handle returned_data = Dart_NewTypedData(Dart_TypedData_kInt64, File::kStatSize); if (Dart_IsError(returned_data)) { Dart_PropagateError(returned_data); } Dart_TypedData_Type data_type_unused; void* data_location; intptr_t data_length_unused; Dart_Handle status = Dart_TypedDataAcquireData(returned_data, &data_type_unused, &data_location, &data_length_unused); if (Dart_IsError(status)) { Dart_PropagateError(status); } memmove(data_location, stat_data, File::kStatSize * sizeof(int64_t)); status = Dart_TypedDataReleaseData(returned_data); if (Dart_IsError(status)) { Dart_PropagateError(status); } Dart_SetReturnValue(args, returned_data); } } else { Dart_Handle err = DartUtils::NewDartArgumentError( "Non-string argument to FileSystemEntity.stat"); Dart_SetReturnValue(args, err); } } void FUNCTION_NAME(File_AreIdentical)(Dart_NativeArguments args) { if (Dart_IsString(Dart_GetNativeArgument(args, 0)) && Dart_IsString(Dart_GetNativeArgument(args, 1))) { const char* path_1 = DartUtils::GetStringValue(Dart_GetNativeArgument(args, 0)); const char* path_2 = DartUtils::GetStringValue(Dart_GetNativeArgument(args, 1)); File::Identical result = File::AreIdentical(path_1, path_2); if (result == File::kError) { Dart_SetReturnValue(args, DartUtils::NewDartOSError()); } else { Dart_SetReturnValue(args, Dart_NewBoolean(result == File::kIdentical)); } } else { Dart_Handle err = DartUtils::NewDartArgumentError( "Non-string argument to FileSystemEntity.identical"); Dart_SetReturnValue(args, err); } } static int64_t CObjectInt32OrInt64ToInt64(CObject* cobject) { ASSERT(cobject->IsInt32OrInt64()); int64_t result; if (cobject->IsInt32()) { CObjectInt32 value(cobject); result = value.Value(); } else { CObjectInt64 value(cobject); result = value.Value(); } return result; } File* CObjectToFilePointer(CObject* cobject) { CObjectIntptr value(cobject); return reinterpret_cast(value.Value()); } CObject* File::ExistsRequest(const CObjectArray& request) { if ((request.Length() == 1) && request[0]->IsString()) { CObjectString filename(request[0]); bool result = File::Exists(filename.CString()); return CObject::Bool(result); } return CObject::IllegalArgumentError(); } CObject* File::CreateRequest(const CObjectArray& request) { if ((request.Length() == 1) && request[0]->IsString()) { CObjectString filename(request[0]); bool result = File::Create(filename.CString()); if (result) { return CObject::True(); } else { return CObject::NewOSError(); } } return CObject::IllegalArgumentError(); } CObject* File::OpenRequest(const CObjectArray& request) { File* file = NULL; if ((request.Length() == 2) && request[0]->IsString() && request[1]->IsInt32()) { CObjectString filename(request[0]); CObjectInt32 mode(request[1]); File::DartFileOpenMode dart_file_mode = static_cast(mode.Value()); File::FileOpenMode file_mode = File::DartModeToFileMode(dart_file_mode); file = File::Open(filename.CString(), file_mode); if (file != NULL) { return new CObjectIntptr( CObject::NewIntptr(reinterpret_cast(file))); } else { return CObject::NewOSError(); } } return CObject::IllegalArgumentError(); } CObject* File::DeleteRequest(const CObjectArray& request) { if ((request.Length() == 1) && request[0]->IsString()) { CObjectString filename(request[0]); bool result = File::Delete(filename.CString()); if (result) { return CObject::True(); } else { return CObject::NewOSError(); } } return CObject::False(); } CObject* File::RenameRequest(const CObjectArray& request) { if ((request.Length() == 2) && request[0]->IsString() && request[1]->IsString()) { CObjectString old_path(request[0]); CObjectString new_path(request[1]); bool completed = File::Rename(old_path.CString(), new_path.CString()); if (completed) { return CObject::True(); } return CObject::NewOSError(); } return CObject::IllegalArgumentError(); } CObject* File::CopyRequest(const CObjectArray& request) { if ((request.Length() == 2) && request[0]->IsString() && request[1]->IsString()) { CObjectString old_path(request[0]); CObjectString new_path(request[1]); bool completed = File::Copy(old_path.CString(), new_path.CString()); if (completed) { return CObject::True(); } return CObject::NewOSError(); } return CObject::IllegalArgumentError(); } CObject* File::ResolveSymbolicLinksRequest(const CObjectArray& request) { if ((request.Length() == 1) && request[0]->IsString()) { CObjectString filename(request[0]); const char* result = File::GetCanonicalPath(filename.CString()); if (result != NULL) { CObject* path = new CObjectString(CObject::NewString(result)); return path; } else { return CObject::NewOSError(); } } return CObject::IllegalArgumentError(); } CObject* File::CloseRequest(const CObjectArray& request) { intptr_t return_value = -1; if ((request.Length() == 1) && request[0]->IsIntptr()) { File* file = CObjectToFilePointer(request[0]); RefCntReleaseScope rs(file); return_value = 0; // We have retained a reference to the file here. Therefore the file's // destructor can't be running. Since no further requests are dispatched by // the Dart code after an async close call, this Close() can't be racing // with any other call on the file. We don't do an extra Release(), and we // don't delete the weak persistent handle. The file is closed here, but the // memory will be cleaned up when the finalizer runs. ASSERT(!file->IsClosed()); file->Close(); } return new CObjectIntptr(CObject::NewIntptr(return_value)); } CObject* File::PositionRequest(const CObjectArray& request) { if ((request.Length() == 1) && request[0]->IsIntptr()) { File* file = CObjectToFilePointer(request[0]); RefCntReleaseScope rs(file); if (!file->IsClosed()) { intptr_t return_value = file->Position(); if (return_value >= 0) { return new CObjectIntptr(CObject::NewIntptr(return_value)); } else { return CObject::NewOSError(); } } else { return CObject::FileClosedError(); } } return CObject::IllegalArgumentError(); } CObject* File::SetPositionRequest(const CObjectArray& request) { if ((request.Length() >= 1) && request[0]->IsIntptr()) { File* file = CObjectToFilePointer(request[0]); RefCntReleaseScope rs(file); if ((request.Length() == 2) && request[1]->IsInt32OrInt64()) { if (!file->IsClosed()) { int64_t position = CObjectInt32OrInt64ToInt64(request[1]); if (file->SetPosition(position)) { return CObject::True(); } else { return CObject::NewOSError(); } } else { return CObject::FileClosedError(); } } else { return CObject::IllegalArgumentError(); } } return CObject::IllegalArgumentError(); } CObject* File::TruncateRequest(const CObjectArray& request) { if ((request.Length() >= 1) && request[0]->IsIntptr()) { File* file = CObjectToFilePointer(request[0]); RefCntReleaseScope rs(file); if ((request.Length() == 2) && request[1]->IsInt32OrInt64()) { if (!file->IsClosed()) { int64_t length = CObjectInt32OrInt64ToInt64(request[1]); if (file->Truncate(length)) { return CObject::True(); } else { return CObject::NewOSError(); } } else { return CObject::FileClosedError(); } } else { return CObject::IllegalArgumentError(); } } return CObject::IllegalArgumentError(); } CObject* File::LengthRequest(const CObjectArray& request) { if ((request.Length() == 1) && request[0]->IsIntptr()) { File* file = CObjectToFilePointer(request[0]); RefCntReleaseScope rs(file); if (!file->IsClosed()) { int64_t return_value = file->Length(); if (return_value >= 0) { return new CObjectInt64(CObject::NewInt64(return_value)); } else { return CObject::NewOSError(); } } else { return CObject::FileClosedError(); } } return CObject::IllegalArgumentError(); } CObject* File::LengthFromPathRequest(const CObjectArray& request) { if ((request.Length() == 1) && request[0]->IsString()) { CObjectString filepath(request[0]); int64_t return_value = File::LengthFromPath(filepath.CString()); if (return_value >= 0) { return new CObjectInt64(CObject::NewInt64(return_value)); } else { return CObject::NewOSError(); } } return CObject::IllegalArgumentError(); } CObject* File::LastAccessedRequest(const CObjectArray& request) { if ((request.Length() == 1) && request[0]->IsString()) { CObjectString filepath(request[0]); int64_t return_value = File::LastAccessed(filepath.CString()); if (return_value >= 0) { return new CObjectIntptr( CObject::NewInt64(return_value * kMillisecondsPerSecond)); } else { return CObject::NewOSError(); } } return CObject::IllegalArgumentError(); } CObject* File::SetLastAccessedRequest(const CObjectArray& request) { if ((request.Length() == 2) && request[0]->IsString() && request[1]->IsInt32OrInt64()) { CObjectString filepath(request[0]); const int64_t millis = CObjectInt32OrInt64ToInt64(request[1]); if (File::SetLastAccessed(filepath.CString(), millis)) { return CObject::Null(); } else { return CObject::NewOSError(); } } return CObject::IllegalArgumentError(); } CObject* File::LastModifiedRequest(const CObjectArray& request) { if ((request.Length() == 1) && request[0]->IsString()) { CObjectString filepath(request[0]); int64_t return_value = File::LastModified(filepath.CString()); if (return_value >= 0) { return new CObjectIntptr( CObject::NewInt64(return_value * kMillisecondsPerSecond)); } else { return CObject::NewOSError(); } } return CObject::IllegalArgumentError(); } CObject* File::SetLastModifiedRequest(const CObjectArray& request) { if ((request.Length() == 2) && request[0]->IsString() && request[1]->IsInt32OrInt64()) { CObjectString filepath(request[0]); const int64_t millis = CObjectInt32OrInt64ToInt64(request[1]); if (File::SetLastModified(filepath.CString(), millis)) { return CObject::Null(); } else { return CObject::NewOSError(); } } return CObject::IllegalArgumentError(); } CObject* File::FlushRequest(const CObjectArray& request) { if ((request.Length() == 1) && request[0]->IsIntptr()) { File* file = CObjectToFilePointer(request[0]); RefCntReleaseScope rs(file); if (!file->IsClosed()) { if (file->Flush()) { return CObject::True(); } else { return CObject::NewOSError(); } } else { return CObject::FileClosedError(); } } return CObject::IllegalArgumentError(); } CObject* File::ReadByteRequest(const CObjectArray& request) { if ((request.Length() == 1) && request[0]->IsIntptr()) { File* file = CObjectToFilePointer(request[0]); RefCntReleaseScope rs(file); if (!file->IsClosed()) { uint8_t buffer; int64_t bytes_read = file->Read(reinterpret_cast(&buffer), 1); if (bytes_read > 0) { return new CObjectIntptr(CObject::NewIntptr(buffer)); } else if (bytes_read == 0) { return new CObjectIntptr(CObject::NewIntptr(-1)); } else { return CObject::NewOSError(); } } else { return CObject::FileClosedError(); } } return CObject::IllegalArgumentError(); } CObject* File::WriteByteRequest(const CObjectArray& request) { if ((request.Length() >= 1) && request[0]->IsIntptr()) { File* file = CObjectToFilePointer(request[0]); RefCntReleaseScope rs(file); if ((request.Length() == 2) && request[1]->IsInt32OrInt64()) { if (!file->IsClosed()) { int64_t byte = CObjectInt32OrInt64ToInt64(request[1]); uint8_t buffer = static_cast(byte & 0xff); bool success = file->WriteFully(reinterpret_cast(&buffer), 1); if (success) { return new CObjectInt64(CObject::NewInt64(1)); } else { return CObject::NewOSError(); } } else { return CObject::FileClosedError(); } } else { return CObject::IllegalArgumentError(); } } return CObject::IllegalArgumentError(); } CObject* File::ReadRequest(const CObjectArray& request) { if ((request.Length() >= 1) && request[0]->IsIntptr()) { File* file = CObjectToFilePointer(request[0]); RefCntReleaseScope rs(file); if ((request.Length() == 2) && request[1]->IsInt32OrInt64()) { if (!file->IsClosed()) { int64_t length = CObjectInt32OrInt64ToInt64(request[1]); Dart_CObject* io_buffer = CObject::NewIOBuffer(length); ASSERT(io_buffer != NULL); uint8_t* data = io_buffer->value.as_external_typed_data.data; int64_t bytes_read = file->Read(data, length); if (bytes_read >= 0) { CObjectExternalUint8Array* external_array = new CObjectExternalUint8Array(io_buffer); external_array->SetLength(bytes_read); CObjectArray* result = new CObjectArray(CObject::NewArray(2)); result->SetAt(0, new CObjectIntptr(CObject::NewInt32(0))); result->SetAt(1, external_array); return result; } else { CObject::FreeIOBufferData(io_buffer); return CObject::NewOSError(); } } else { return CObject::FileClosedError(); } } else { return CObject::IllegalArgumentError(); } } return CObject::IllegalArgumentError(); } CObject* File::ReadIntoRequest(const CObjectArray& request) { if ((request.Length() >= 1) && request[0]->IsIntptr()) { File* file = CObjectToFilePointer(request[0]); RefCntReleaseScope rs(file); if ((request.Length() == 2) && request[1]->IsInt32OrInt64()) { if (!file->IsClosed()) { int64_t length = CObjectInt32OrInt64ToInt64(request[1]); Dart_CObject* io_buffer = CObject::NewIOBuffer(length); ASSERT(io_buffer != NULL); uint8_t* data = io_buffer->value.as_external_typed_data.data; int64_t bytes_read = file->Read(data, length); if (bytes_read >= 0) { CObjectExternalUint8Array* external_array = new CObjectExternalUint8Array(io_buffer); external_array->SetLength(bytes_read); CObjectArray* result = new CObjectArray(CObject::NewArray(3)); result->SetAt(0, new CObjectIntptr(CObject::NewInt32(0))); result->SetAt(1, new CObjectInt64(CObject::NewInt64(bytes_read))); result->SetAt(2, external_array); return result; } else { CObject::FreeIOBufferData(io_buffer); return CObject::NewOSError(); } } else { return CObject::FileClosedError(); } } else { return CObject::IllegalArgumentError(); } } return CObject::IllegalArgumentError(); } static int SizeInBytes(Dart_TypedData_Type type) { switch (type) { case Dart_TypedData_kInt8: case Dart_TypedData_kUint8: case Dart_TypedData_kUint8Clamped: return 1; case Dart_TypedData_kInt16: case Dart_TypedData_kUint16: return 2; case Dart_TypedData_kInt32: case Dart_TypedData_kUint32: case Dart_TypedData_kFloat32: return 4; case Dart_TypedData_kInt64: case Dart_TypedData_kUint64: case Dart_TypedData_kFloat64: return 8; default: break; } UNREACHABLE(); return -1; } CObject* File::WriteFromRequest(const CObjectArray& request) { if ((request.Length() >= 1) && request[0]->IsIntptr()) { File* file = CObjectToFilePointer(request[0]); RefCntReleaseScope rs(file); if ((request.Length() == 4) && (request[1]->IsTypedData() || request[1]->IsArray()) && request[2]->IsInt32OrInt64() && request[3]->IsInt32OrInt64()) { if (!file->IsClosed()) { int64_t start = CObjectInt32OrInt64ToInt64(request[2]); int64_t end = CObjectInt32OrInt64ToInt64(request[3]); int64_t length = end - start; uint8_t* buffer_start; if (request[1]->IsTypedData()) { CObjectTypedData typed_data(request[1]); start = start * SizeInBytes(typed_data.Type()); length = length * SizeInBytes(typed_data.Type()); buffer_start = typed_data.Buffer() + start; } else { CObjectArray array(request[1]); buffer_start = Dart_ScopeAllocate(length); for (int i = 0; i < length; i++) { if (array[i + start]->IsInt32OrInt64()) { int64_t value = CObjectInt32OrInt64ToInt64(array[i + start]); buffer_start[i] = static_cast(value & 0xFF); } else { // Unsupported type. return CObject::IllegalArgumentError(); } } start = 0; } bool success = file->WriteFully(reinterpret_cast(buffer_start), length); if (success) { return new CObjectInt64(CObject::NewInt64(length)); } else { return CObject::NewOSError(); } } else { return CObject::FileClosedError(); } } else { return CObject::IllegalArgumentError(); } } return CObject::IllegalArgumentError(); } CObject* File::CreateLinkRequest(const CObjectArray& request) { if ((request.Length() != 2) || !request[0]->IsString() || !request[1]->IsString()) { return CObject::IllegalArgumentError(); } CObjectString link_name(request[0]); CObjectString target_name(request[1]); if (File::CreateLink(link_name.CString(), target_name.CString())) { return CObject::True(); } else { return CObject::NewOSError(); } } CObject* File::DeleteLinkRequest(const CObjectArray& request) { if ((request.Length() == 1) && request[0]->IsString()) { CObjectString link_path(request[0]); bool result = File::DeleteLink(link_path.CString()); if (result) { return CObject::True(); } else { return CObject::NewOSError(); } } return CObject::IllegalArgumentError(); } CObject* File::RenameLinkRequest(const CObjectArray& request) { if ((request.Length() == 2) && request[0]->IsString() && request[1]->IsString()) { CObjectString old_path(request[0]); CObjectString new_path(request[1]); bool completed = File::RenameLink(old_path.CString(), new_path.CString()); if (completed) { return CObject::True(); } return CObject::NewOSError(); } return CObject::IllegalArgumentError(); } CObject* File::LinkTargetRequest(const CObjectArray& request) { if ((request.Length() == 1) && request[0]->IsString()) { CObjectString link_path(request[0]); const char* target = File::LinkTarget(link_path.CString()); if (target != NULL) { CObject* result = new CObjectString(CObject::NewString(target)); return result; } else { return CObject::NewOSError(); } } return CObject::IllegalArgumentError(); } CObject* File::TypeRequest(const CObjectArray& request) { if ((request.Length() == 2) && request[0]->IsString() && request[1]->IsBool()) { CObjectString path(request[0]); CObjectBool follow_links(request[1]); File::Type type = File::GetType(path.CString(), follow_links.Value()); return new CObjectInt32(CObject::NewInt32(type)); } return CObject::IllegalArgumentError(); } CObject* File::IdenticalRequest(const CObjectArray& request) { if ((request.Length() == 2) && request[0]->IsString() && request[1]->IsString()) { CObjectString path1(request[0]); CObjectString path2(request[1]); File::Identical result = File::AreIdentical(path1.CString(), path2.CString()); if (result == File::kError) { return CObject::NewOSError(); } else if (result == File::kIdentical) { return CObject::True(); } else { return CObject::False(); } } return CObject::IllegalArgumentError(); } CObject* File::StatRequest(const CObjectArray& request) { if ((request.Length() == 1) && request[0]->IsString()) { int64_t data[File::kStatSize]; CObjectString path(request[0]); File::Stat(path.CString(), data); if (data[File::kType] == File::kDoesNotExist) { return CObject::NewOSError(); } CObjectArray* result = new CObjectArray(CObject::NewArray(File::kStatSize)); for (int i = 0; i < File::kStatSize; ++i) { result->SetAt(i, new CObjectInt64(CObject::NewInt64(data[i]))); } CObjectArray* wrapper = new CObjectArray(CObject::NewArray(2)); wrapper->SetAt(0, new CObjectInt32(CObject::NewInt32(CObject::kSuccess))); wrapper->SetAt(1, result); return wrapper; } return CObject::IllegalArgumentError(); } CObject* File::LockRequest(const CObjectArray& request) { if ((request.Length() >= 1) && request[0]->IsIntptr()) { File* file = CObjectToFilePointer(request[0]); RefCntReleaseScope rs(file); if ((request.Length() == 4) && request[1]->IsInt32OrInt64() && request[2]->IsInt32OrInt64() && request[3]->IsInt32OrInt64()) { if (!file->IsClosed()) { int64_t lock = CObjectInt32OrInt64ToInt64(request[1]); int64_t start = CObjectInt32OrInt64ToInt64(request[2]); int64_t end = CObjectInt32OrInt64ToInt64(request[3]); if (file->Lock(static_cast(lock), start, end)) { return CObject::True(); } else { return CObject::NewOSError(); } } else { return CObject::FileClosedError(); } } else { return CObject::IllegalArgumentError(); } } return CObject::IllegalArgumentError(); } } // namespace bin } // namespace dart #endif // !defined(DART_IO_DISABLED)