blob: 8175d9b3710febe11f99a7ed944a1cce4a24d18d [file] [log] [blame]
// 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.
#include "bin/file.h"
#include "bin/builtin.h"
#include "bin/dartutils.h"
#include "bin/io_buffer.h"
#include "bin/utils.h"
#include "include/dart_api.h"
#include "include/dart_tools_api.h"
namespace dart {
namespace bin {
static const int kMSPerSecond = 1000;
// Are we capturing output from either stdout or stderr for the VM Service?
bool capture_stdio = false;
// Are we capturing output from stdout for the VM service?
bool capture_stdout = false;
// Are we capturing output from stderr for the VM service?
bool capture_stderr = false;
// 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* GetFilePointer(Dart_Handle handle) {
intptr_t value = DartUtils::GetIntptrValue(handle);
return reinterpret_cast<File*>(value);
}
bool File::ReadFully(void* buffer, int64_t num_bytes) {
int64_t remaining = num_bytes;
char* current_buffer = reinterpret_cast<char*>(buffer);
while (remaining > 0) {
int64_t bytes_read = Read(current_buffer, remaining);
if (bytes_read <= 0) {
return false;
}
remaining -= bytes_read; // Reduce the number of remaining bytes.
current_buffer += bytes_read; // Move the buffer forward.
}
return true;
}
bool File::WriteFully(const void* buffer, int64_t num_bytes) {
int64_t remaining = num_bytes;
const char* current_buffer = reinterpret_cast<const char*>(buffer);
while (remaining > 0) {
int64_t bytes_written = Write(current_buffer, remaining);
if (bytes_written < 0) {
return false;
}
remaining -= bytes_written; // Reduce the number of remaining bytes.
current_buffer += bytes_written; // Move the buffer forward.
}
if (capture_stdio) {
intptr_t fd = GetFD();
if (fd == STDOUT_FILENO && capture_stdout) {
Dart_ServiceSendDataEvent("Stdout", "WriteEvent",
reinterpret_cast<const uint8_t*>(buffer),
num_bytes);
} else if (fd == STDERR_FILENO && capture_stderr) {
Dart_ServiceSendDataEvent("Stderr", "WriteEvent",
reinterpret_cast<const uint8_t*>(buffer),
num_bytes);
}
}
return true;
}
File::FileOpenMode File::DartModeToFileMode(DartFileOpenMode mode) {
ASSERT(mode == File::kDartRead ||
mode == File::kDartWrite ||
mode == File::kDartAppend ||
mode == File::kDartWriteOnly ||
mode == File::kDartWriteOnlyAppend);
if (mode == File::kDartWrite) {
return File::kWriteTruncate;
}
if (mode == File::kDartAppend) {
return File::kWrite;
}
if (mode == File::kDartWriteOnly) {
return File::kWriteOnlyTruncate;
}
if (mode == File::kDartWriteOnlyAppend) {
return File::kWriteOnly;
}
return File::kRead;
}
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<File::DartFileOpenMode>(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 = NULL;
file = File::Open(filename, file_mode);
if (file != NULL) {
Dart_SetReturnValue(args,
Dart_NewInteger(reinterpret_cast<intptr_t>(file)));
} else {
Dart_Handle err = DartUtils::NewDartOSError();
if (Dart_IsError(err)) Dart_PropagateError(err);
Dart_SetReturnValue(args, err);
}
}
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 = GetFilePointer(Dart_GetNativeArgument(args, 0));
ASSERT(file != NULL);
delete file;
Dart_SetReturnValue(args, Dart_NewInteger(0));
}
void FUNCTION_NAME(File_GetFD)(Dart_NativeArguments args) {
File* file = GetFilePointer(Dart_GetNativeArgument(args, 0));
ASSERT(file != NULL);
Dart_SetReturnValue(args, Dart_NewInteger(file->GetFD()));
}
void FUNCTION_NAME(File_ReadByte)(Dart_NativeArguments args) {
File* file = GetFilePointer(Dart_GetNativeArgument(args, 0));
ASSERT(file != NULL);
uint8_t buffer;
int64_t bytes_read = file->Read(reinterpret_cast<void*>(&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_Handle err = DartUtils::NewDartOSError();
if (Dart_IsError(err)) Dart_PropagateError(err);
Dart_SetReturnValue(args, err);
}
}
void FUNCTION_NAME(File_WriteByte)(Dart_NativeArguments args) {
File* file = GetFilePointer(Dart_GetNativeArgument(args, 0));
ASSERT(file != NULL);
int64_t byte = 0;
if (DartUtils::GetInt64Value(Dart_GetNativeArgument(args, 1), &byte)) {
uint8_t buffer = static_cast<uint8_t>(byte & 0xff);
bool success = file->WriteFully(reinterpret_cast<void*>(&buffer), 1);
if (success) {
Dart_SetReturnValue(args, Dart_NewInteger(1));
} else {
Dart_Handle err = DartUtils::NewDartOSError();
if (Dart_IsError(err)) Dart_PropagateError(err);
Dart_SetReturnValue(args, err);
}
} else {
OSError os_error(-1, "Invalid argument", OSError::kUnknown);
Dart_Handle err = DartUtils::NewDartOSError(&os_error);
if (Dart_IsError(err)) Dart_PropagateError(err);
Dart_SetReturnValue(args, err);
}
}
void FUNCTION_NAME(File_Read)(Dart_NativeArguments args) {
File* file = GetFilePointer(Dart_GetNativeArgument(args, 0));
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<void*>(buffer), length);
if (bytes_read < 0) {
Dart_Handle err = DartUtils::NewDartOSError();
if (Dart_IsError(err)) Dart_PropagateError(err);
Dart_SetReturnValue(args, err);
} 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);
if (Dart_IsError(array_view)) Dart_PropagateError(array_view);
Dart_SetReturnValue(args, array_view);
} else {
Dart_SetReturnValue(args, external_array);
}
}
} else {
OSError os_error(-1, "Invalid argument", OSError::kUnknown);
Dart_Handle err = DartUtils::NewDartOSError(&os_error);
if (Dart_IsError(err)) Dart_PropagateError(err);
Dart_SetReturnValue(args, err);
}
}
void FUNCTION_NAME(File_ReadInto)(Dart_NativeArguments args) {
File* file = GetFilePointer(Dart_GetNativeArgument(args, 0));
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 = new uint8_t[length];
int64_t bytes_read = file->Read(reinterpret_cast<void*>(buffer), length);
if (bytes_read >= 0) {
result = Dart_ListSetAsBytes(buffer_obj, start, buffer, bytes_read);
if (Dart_IsError(result)) {
delete[] buffer;
Dart_PropagateError(result);
}
Dart_SetReturnValue(args, Dart_NewInteger(bytes_read));
} else {
Dart_Handle err = DartUtils::NewDartOSError();
if (Dart_IsError(err)) Dart_PropagateError(err);
Dart_SetReturnValue(args, err);
}
delete[] buffer;
}
void FUNCTION_NAME(File_WriteFrom)(Dart_NativeArguments args) {
File* file = GetFilePointer(Dart_GetNativeArgument(args, 0));
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.
bool success = file->WriteFully(buffer, length);
// Release the direct pointer acquired above.
result = Dart_TypedDataReleaseData(buffer_obj);
if (Dart_IsError(result)) Dart_PropagateError(result);
if (!success) {
Dart_Handle err = DartUtils::NewDartOSError();
if (Dart_IsError(err)) Dart_PropagateError(err);
Dart_SetReturnValue(args, err);
} else {
Dart_SetReturnValue(args, Dart_Null());
}
}
void FUNCTION_NAME(File_Position)(Dart_NativeArguments args) {
File* file = GetFilePointer(Dart_GetNativeArgument(args, 0));
ASSERT(file != NULL);
intptr_t return_value = file->Position();
if (return_value >= 0) {
Dart_SetReturnValue(args, Dart_NewInteger(return_value));
} else {
Dart_Handle err = DartUtils::NewDartOSError();
if (Dart_IsError(err)) Dart_PropagateError(err);
Dart_SetReturnValue(args, err);
}
}
void FUNCTION_NAME(File_SetPosition)(Dart_NativeArguments args) {
File* file = GetFilePointer(Dart_GetNativeArgument(args, 0));
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_Handle err = DartUtils::NewDartOSError();
if (Dart_IsError(err)) Dart_PropagateError(err);
Dart_SetReturnValue(args, err);
}
} else {
OSError os_error(-1, "Invalid argument", OSError::kUnknown);
Dart_Handle err = DartUtils::NewDartOSError(&os_error);
if (Dart_IsError(err)) Dart_PropagateError(err);
Dart_SetReturnValue(args, err);
}
}
void FUNCTION_NAME(File_Truncate)(Dart_NativeArguments args) {
File* file = GetFilePointer(Dart_GetNativeArgument(args, 0));
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_Handle err = DartUtils::NewDartOSError();
if (Dart_IsError(err)) Dart_PropagateError(err);
Dart_SetReturnValue(args, err);
}
} else {
OSError os_error(-1, "Invalid argument", OSError::kUnknown);
Dart_Handle err = DartUtils::NewDartOSError(&os_error);
if (Dart_IsError(err)) Dart_PropagateError(err);
Dart_SetReturnValue(args, err);
}
}
void FUNCTION_NAME(File_Length)(Dart_NativeArguments args) {
File* file = GetFilePointer(Dart_GetNativeArgument(args, 0));
ASSERT(file != NULL);
int64_t return_value = file->Length();
if (return_value >= 0) {
Dart_SetReturnValue(args, Dart_NewInteger(return_value));
} else {
Dart_Handle err = DartUtils::NewDartOSError();
if (Dart_IsError(err)) Dart_PropagateError(err);
Dart_SetReturnValue(args, err);
}
}
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_Handle err = DartUtils::NewDartOSError();
if (Dart_IsError(err)) Dart_PropagateError(err);
Dart_SetReturnValue(args, err);
}
}
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 * kMSPerSecond));
} else {
Dart_Handle err = DartUtils::NewDartOSError();
if (Dart_IsError(err)) Dart_PropagateError(err);
Dart_SetReturnValue(args, err);
}
}
void FUNCTION_NAME(File_Flush)(Dart_NativeArguments args) {
File* file = GetFilePointer(Dart_GetNativeArgument(args, 0));
ASSERT(file != NULL);
if (file->Flush()) {
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(File_Lock)(Dart_NativeArguments args) {
File* file = GetFilePointer(Dart_GetNativeArgument(args, 0));
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<File::LockType>(lock), start, end)) {
Dart_SetReturnValue(args, Dart_True());
} else {
Dart_Handle err = DartUtils::NewDartOSError();
if (Dart_IsError(err)) Dart_PropagateError(err);
Dart_SetReturnValue(args, err);
}
return;
}
}
OSError os_error(-1, "Invalid argument", OSError::kUnknown);
Dart_Handle err = DartUtils::NewDartOSError(&os_error);
if (Dart_IsError(err)) Dart_PropagateError(err);
Dart_SetReturnValue(args, err);
}
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_Handle err = DartUtils::NewDartOSError();
if (Dart_IsError(err)) Dart_PropagateError(err);
Dart_SetReturnValue(args, err);
}
}
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_Handle err = DartUtils::NewDartOSError();
if (Dart_IsError(err)) Dart_PropagateError(err);
Dart_SetReturnValue(args, err);
}
} else {
Dart_Handle err = DartUtils::NewDartArgumentError(
"Non-string argument to Link.create");
if (Dart_IsError(err)) Dart_PropagateError(err);
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));
char* target = File::LinkTarget(name);
if (target == NULL) {
Dart_Handle err = DartUtils::NewDartOSError();
if (Dart_IsError(err)) Dart_PropagateError(err);
Dart_SetReturnValue(args, err);
} else {
Dart_SetReturnValue(args, DartUtils::NewString(target));
free(target);
}
} else {
Dart_Handle err = DartUtils::NewDartArgumentError(
"Non-string argument to Link.target");
if (Dart_IsError(err)) Dart_PropagateError(err);
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_Handle err = DartUtils::NewDartOSError();
if (Dart_IsError(err)) Dart_PropagateError(err);
Dart_SetReturnValue(args, err);
}
}
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_Handle err = DartUtils::NewDartOSError();
if (Dart_IsError(err)) Dart_PropagateError(err);
Dart_SetReturnValue(args, err);
}
}
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_Handle err = DartUtils::NewDartOSError();
if (Dart_IsError(err)) Dart_PropagateError(err);
Dart_SetReturnValue(args, err);
}
}
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_Handle err = DartUtils::NewDartOSError();
if (Dart_IsError(err)) Dart_PropagateError(err);
Dart_SetReturnValue(args, err);
}
}
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_Handle err = DartUtils::NewDartOSError();
if (Dart_IsError(err)) Dart_PropagateError(err);
Dart_SetReturnValue(args, err);
}
}
void FUNCTION_NAME(File_ResolveSymbolicLinks)(Dart_NativeArguments args) {
const char* str =
DartUtils::GetStringValue(Dart_GetNativeArgument(args, 0));
char* path = File::GetCanonicalPath(str);
if (path != NULL) {
Dart_SetReturnValue(args, DartUtils::NewString(path));
free(path);
} else {
Dart_Handle err = DartUtils::NewDartOSError();
if (Dart_IsError(err)) Dart_PropagateError(err);
Dart_SetReturnValue(args, err);
}
}
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<int>(fd));
Dart_SetReturnValue(args, Dart_NewInteger(reinterpret_cast<intptr_t>(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<int>(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<int>(type)));
} else {
Dart_Handle err = DartUtils::NewDartArgumentError(
"Non-string argument to FileSystemEntity.type");
if (Dart_IsError(err)) Dart_PropagateError(err);
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_Handle err = DartUtils::NewDartOSError();
if (Dart_IsError(err)) Dart_PropagateError(err);
Dart_SetReturnValue(args, err);
} 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");
if (Dart_IsError(err)) Dart_PropagateError(err);
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_Handle err = DartUtils::NewDartOSError();
if (Dart_IsError(err)) Dart_PropagateError(err);
Dart_SetReturnValue(args, err);
} else {
Dart_SetReturnValue(args, Dart_NewBoolean(result == File::kIdentical));
}
} else {
Dart_Handle err = DartUtils::NewDartArgumentError(
"Non-string argument to FileSystemEntity.identical");
if (Dart_IsError(err)) Dart_PropagateError(err);
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<File*>(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<File::DartFileOpenMode>(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<intptr_t>(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]);
char* result = File::GetCanonicalPath(filename.CString());
if (result != NULL) {
CObject* path = new CObjectString(CObject::NewString(result));
free(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]);
ASSERT(file != NULL);
delete file;
return_value = 0;
}
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]);
ASSERT(file != NULL);
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() == 2 &&
request[0]->IsIntptr() &&
request[1]->IsInt32OrInt64()) {
File* file = CObjectToFilePointer(request[0]);
ASSERT(file != NULL);
if (!file->IsClosed()) {
int64_t position = CObjectInt32OrInt64ToInt64(request[1]);
if (file->SetPosition(position)) {
return CObject::True();
} else {
return CObject::NewOSError();
}
} else {
return CObject::FileClosedError();
}
}
return CObject::IllegalArgumentError();
}
CObject* File::TruncateRequest(const CObjectArray& request) {
if (request.Length() == 2 &&
request[0]->IsIntptr() &&
request[1]->IsInt32OrInt64()) {
File* file = CObjectToFilePointer(request[0]);
ASSERT(file != NULL);
if (!file->IsClosed()) {
int64_t length = CObjectInt32OrInt64ToInt64(request[1]);
if (file->Truncate(length)) {
return CObject::True();
} else {
return CObject::NewOSError();
}
} else {
return CObject::FileClosedError();
}
}
return CObject::IllegalArgumentError();
}
CObject* File::LengthRequest(const CObjectArray& request) {
if (request.Length() == 1 && request[0]->IsIntptr()) {
File* file = CObjectToFilePointer(request[0]);
ASSERT(file != NULL);
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::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 * kMSPerSecond));
} 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]);
ASSERT(file != NULL);
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]);
ASSERT(file != NULL);
if (!file->IsClosed()) {
uint8_t buffer;
int64_t bytes_read = file->Read(reinterpret_cast<void*>(&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() == 2 &&
request[0]->IsIntptr() &&
request[1]->IsInt32OrInt64()) {
File* file = CObjectToFilePointer(request[0]);
ASSERT(file != NULL);
if (!file->IsClosed()) {
int64_t byte = CObjectInt32OrInt64ToInt64(request[1]);
uint8_t buffer = static_cast<uint8_t>(byte & 0xff);
bool success = file->WriteFully(reinterpret_cast<void*>(&buffer), 1);
if (success) {
return new CObjectInt64(CObject::NewInt64(1));
} else {
return CObject::NewOSError();
}
} else {
return CObject::FileClosedError();
}
}
return CObject::IllegalArgumentError();
}
CObject* File::ReadRequest(const CObjectArray& request) {
if (request.Length() == 2 &&
request[0]->IsIntptr() &&
request[1]->IsInt32OrInt64()) {
File* file = CObjectToFilePointer(request[0]);
ASSERT(file != NULL);
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();
}
}
return CObject::IllegalArgumentError();
}
CObject* File::ReadIntoRequest(const CObjectArray& request) {
if (request.Length() == 2 &&
request[0]->IsIntptr() &&
request[1]->IsInt32OrInt64()) {
File* file = CObjectToFilePointer(request[0]);
ASSERT(file != NULL);
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();
}
}
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() == 4 &&
request[0]->IsIntptr() &&
(request[1]->IsTypedData() || request[1]->IsArray()) &&
request[2]->IsInt32OrInt64() &&
request[3]->IsInt32OrInt64()) {
File* file = CObjectToFilePointer(request[0]);
ASSERT(file != NULL);
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 = new uint8_t[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<uint8_t>(value & 0xFF);
} else {
// Unsupported type.
delete[] buffer_start;
return CObject::IllegalArgumentError();
}
}
start = 0;
}
bool success =
file->WriteFully(reinterpret_cast<void*>(buffer_start), length);
if (!request[1]->IsTypedData()) {
delete[] buffer_start;
}
if (success) {
return new CObjectInt64(CObject::NewInt64(length));
} else {
return CObject::NewOSError();
}
} else {
return CObject::FileClosedError();
}
}
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]);
char* target = File::LinkTarget(link_path.CString());
if (target != NULL) {
CObject* result = new CObjectString(CObject::NewString(target));
free(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() == 4 &&
request[0]->IsIntptr() &&
request[1]->IsInt32OrInt64() &&
request[2]->IsInt32OrInt64() &&
request[3]->IsInt32OrInt64()) {
File* file = CObjectToFilePointer(request[0]);
ASSERT(file != NULL);
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<File::LockType>(lock), start, end)) {
return CObject::True();
} else {
return CObject::NewOSError();
}
} else {
return CObject::FileClosedError();
}
}
return CObject::IllegalArgumentError();
}
} // namespace bin
} // namespace dart