mirror of
https://github.com/dart-lang/sdk
synced 2024-10-14 11:31:57 +00:00
Fixes leak of native File objects.
Also employs the same reference counting technique as secure sockets to avoid the IO Service touching dangling pointers. R=iposva@google.com Review URL: https://codereview.chromium.org/1892623002 .
This commit is contained in:
parent
8f9defbb50
commit
218545ba10
|
@ -222,7 +222,8 @@ void DartUtils::WriteFile(const void* buffer,
|
|||
|
||||
|
||||
void DartUtils::CloseFile(void* stream) {
|
||||
delete reinterpret_cast<File*>(stream);
|
||||
File* file = reinterpret_cast<File*>(stream);
|
||||
file->Release();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -18,14 +18,66 @@
|
|||
namespace dart {
|
||||
namespace bin {
|
||||
|
||||
static const int kFileNativeFieldIndex = 0;
|
||||
static const int kMSPerSecond = 1000;
|
||||
|
||||
// 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);
|
||||
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<intptr_t*>(&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<intptr_t>(file);
|
||||
Dart_SetReturnValue(args, Dart_NewInteger(file_pointer));
|
||||
}
|
||||
|
||||
|
||||
static void ReleaseFile(void* isolate_callback_data,
|
||||
Dart_WeakPersistentHandle handle,
|
||||
void* peer) {
|
||||
File* file = reinterpret_cast<File*>(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*>(file_pointer);
|
||||
Dart_WeakPersistentHandle handle = Dart_NewWeakPersistentHandle(
|
||||
dart_this, reinterpret_cast<void*>(file), sizeof(*file), ReleaseFile);
|
||||
file->SetWeakHandle(handle);
|
||||
SetFile(dart_this, file_pointer);
|
||||
}
|
||||
|
||||
|
||||
|
@ -40,8 +92,7 @@ void FUNCTION_NAME(File_Open)(Dart_NativeArguments args) {
|
|||
// 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::ScopedOpen(filename, file_mode);
|
||||
File* file = File::ScopedOpen(filename, file_mode);
|
||||
if (file != NULL) {
|
||||
Dart_SetReturnValue(args,
|
||||
Dart_NewInteger(reinterpret_cast<intptr_t>(file)));
|
||||
|
@ -60,22 +111,20 @@ void FUNCTION_NAME(File_Exists)(Dart_NativeArguments args) {
|
|||
|
||||
|
||||
void FUNCTION_NAME(File_Close)(Dart_NativeArguments args) {
|
||||
File* file = GetFilePointer(Dart_GetNativeArgument(args, 0));
|
||||
File* file = GetFile(args);
|
||||
ASSERT(file != NULL);
|
||||
delete file;
|
||||
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_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));
|
||||
File* file = GetFile(args);
|
||||
ASSERT(file != NULL);
|
||||
uint8_t buffer;
|
||||
int64_t bytes_read = file->Read(reinterpret_cast<void*>(&buffer), 1);
|
||||
|
@ -90,7 +139,7 @@ void FUNCTION_NAME(File_ReadByte)(Dart_NativeArguments args) {
|
|||
|
||||
|
||||
void FUNCTION_NAME(File_WriteByte)(Dart_NativeArguments args) {
|
||||
File* file = GetFilePointer(Dart_GetNativeArgument(args, 0));
|
||||
File* file = GetFile(args);
|
||||
ASSERT(file != NULL);
|
||||
int64_t byte = 0;
|
||||
if (DartUtils::GetInt64Value(Dart_GetNativeArgument(args, 1), &byte)) {
|
||||
|
@ -109,7 +158,7 @@ void FUNCTION_NAME(File_WriteByte)(Dart_NativeArguments args) {
|
|||
|
||||
|
||||
void FUNCTION_NAME(File_Read)(Dart_NativeArguments args) {
|
||||
File* file = GetFilePointer(Dart_GetNativeArgument(args, 0));
|
||||
File* file = GetFile(args);
|
||||
ASSERT(file != NULL);
|
||||
Dart_Handle length_object = Dart_GetNativeArgument(args, 1);
|
||||
int64_t length = 0;
|
||||
|
@ -150,7 +199,7 @@ void FUNCTION_NAME(File_Read)(Dart_NativeArguments args) {
|
|||
|
||||
|
||||
void FUNCTION_NAME(File_ReadInto)(Dart_NativeArguments args) {
|
||||
File* file = GetFilePointer(Dart_GetNativeArgument(args, 0));
|
||||
File* file = GetFile(args);
|
||||
ASSERT(file != NULL);
|
||||
Dart_Handle buffer_obj = Dart_GetNativeArgument(args, 1);
|
||||
ASSERT(Dart_IsList(buffer_obj));
|
||||
|
@ -185,7 +234,7 @@ void FUNCTION_NAME(File_ReadInto)(Dart_NativeArguments args) {
|
|||
|
||||
|
||||
void FUNCTION_NAME(File_WriteFrom)(Dart_NativeArguments args) {
|
||||
File* file = GetFilePointer(Dart_GetNativeArgument(args, 0));
|
||||
File* file = GetFile(args);
|
||||
ASSERT(file != NULL);
|
||||
|
||||
Dart_Handle buffer_obj = Dart_GetNativeArgument(args, 1);
|
||||
|
@ -233,7 +282,7 @@ void FUNCTION_NAME(File_WriteFrom)(Dart_NativeArguments args) {
|
|||
|
||||
|
||||
void FUNCTION_NAME(File_Position)(Dart_NativeArguments args) {
|
||||
File* file = GetFilePointer(Dart_GetNativeArgument(args, 0));
|
||||
File* file = GetFile(args);
|
||||
ASSERT(file != NULL);
|
||||
intptr_t return_value = file->Position();
|
||||
if (return_value >= 0) {
|
||||
|
@ -245,7 +294,7 @@ void FUNCTION_NAME(File_Position)(Dart_NativeArguments args) {
|
|||
|
||||
|
||||
void FUNCTION_NAME(File_SetPosition)(Dart_NativeArguments args) {
|
||||
File* file = GetFilePointer(Dart_GetNativeArgument(args, 0));
|
||||
File* file = GetFile(args);
|
||||
ASSERT(file != NULL);
|
||||
int64_t position = 0;
|
||||
if (DartUtils::GetInt64Value(Dart_GetNativeArgument(args, 1), &position)) {
|
||||
|
@ -262,7 +311,7 @@ void FUNCTION_NAME(File_SetPosition)(Dart_NativeArguments args) {
|
|||
|
||||
|
||||
void FUNCTION_NAME(File_Truncate)(Dart_NativeArguments args) {
|
||||
File* file = GetFilePointer(Dart_GetNativeArgument(args, 0));
|
||||
File* file = GetFile(args);
|
||||
ASSERT(file != NULL);
|
||||
int64_t length = 0;
|
||||
if (DartUtils::GetInt64Value(Dart_GetNativeArgument(args, 1), &length)) {
|
||||
|
@ -279,7 +328,7 @@ void FUNCTION_NAME(File_Truncate)(Dart_NativeArguments args) {
|
|||
|
||||
|
||||
void FUNCTION_NAME(File_Length)(Dart_NativeArguments args) {
|
||||
File* file = GetFilePointer(Dart_GetNativeArgument(args, 0));
|
||||
File* file = GetFile(args);
|
||||
ASSERT(file != NULL);
|
||||
int64_t return_value = file->Length();
|
||||
if (return_value >= 0) {
|
||||
|
@ -315,7 +364,7 @@ void FUNCTION_NAME(File_LastModified)(Dart_NativeArguments args) {
|
|||
|
||||
|
||||
void FUNCTION_NAME(File_Flush)(Dart_NativeArguments args) {
|
||||
File* file = GetFilePointer(Dart_GetNativeArgument(args, 0));
|
||||
File* file = GetFile(args);
|
||||
ASSERT(file != NULL);
|
||||
if (file->Flush()) {
|
||||
Dart_SetReturnValue(args, Dart_True());
|
||||
|
@ -326,7 +375,7 @@ void FUNCTION_NAME(File_Flush)(Dart_NativeArguments args) {
|
|||
|
||||
|
||||
void FUNCTION_NAME(File_Lock)(Dart_NativeArguments args) {
|
||||
File* file = GetFilePointer(Dart_GetNativeArgument(args, 0));
|
||||
File* file = GetFile(args);
|
||||
ASSERT(file != NULL);
|
||||
int64_t lock;
|
||||
int64_t start;
|
||||
|
@ -704,9 +753,16 @@ 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;
|
||||
RefCntReleaseScope<File> 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));
|
||||
}
|
||||
|
@ -715,7 +771,7 @@ CObject* File::CloseRequest(const CObjectArray& request) {
|
|||
CObject* File::PositionRequest(const CObjectArray& request) {
|
||||
if ((request.Length() == 1) && request[0]->IsIntptr()) {
|
||||
File* file = CObjectToFilePointer(request[0]);
|
||||
ASSERT(file != NULL);
|
||||
RefCntReleaseScope<File> rs(file);
|
||||
if (!file->IsClosed()) {
|
||||
intptr_t return_value = file->Position();
|
||||
if (return_value >= 0) {
|
||||
|
@ -736,7 +792,7 @@ CObject* File::SetPositionRequest(const CObjectArray& request) {
|
|||
request[0]->IsIntptr() &&
|
||||
request[1]->IsInt32OrInt64()) {
|
||||
File* file = CObjectToFilePointer(request[0]);
|
||||
ASSERT(file != NULL);
|
||||
RefCntReleaseScope<File> rs(file);
|
||||
if (!file->IsClosed()) {
|
||||
int64_t position = CObjectInt32OrInt64ToInt64(request[1]);
|
||||
if (file->SetPosition(position)) {
|
||||
|
@ -757,7 +813,7 @@ CObject* File::TruncateRequest(const CObjectArray& request) {
|
|||
request[0]->IsIntptr() &&
|
||||
request[1]->IsInt32OrInt64()) {
|
||||
File* file = CObjectToFilePointer(request[0]);
|
||||
ASSERT(file != NULL);
|
||||
RefCntReleaseScope<File> rs(file);
|
||||
if (!file->IsClosed()) {
|
||||
int64_t length = CObjectInt32OrInt64ToInt64(request[1]);
|
||||
if (file->Truncate(length)) {
|
||||
|
@ -776,7 +832,7 @@ CObject* File::TruncateRequest(const CObjectArray& request) {
|
|||
CObject* File::LengthRequest(const CObjectArray& request) {
|
||||
if ((request.Length() == 1) && request[0]->IsIntptr()) {
|
||||
File* file = CObjectToFilePointer(request[0]);
|
||||
ASSERT(file != NULL);
|
||||
RefCntReleaseScope<File> rs(file);
|
||||
if (!file->IsClosed()) {
|
||||
int64_t return_value = file->Length();
|
||||
if (return_value >= 0) {
|
||||
|
@ -823,7 +879,7 @@ CObject* File::LastModifiedRequest(const CObjectArray& request) {
|
|||
CObject* File::FlushRequest(const CObjectArray& request) {
|
||||
if ((request.Length() == 1) && request[0]->IsIntptr()) {
|
||||
File* file = CObjectToFilePointer(request[0]);
|
||||
ASSERT(file != NULL);
|
||||
RefCntReleaseScope<File> rs(file);
|
||||
if (!file->IsClosed()) {
|
||||
if (file->Flush()) {
|
||||
return CObject::True();
|
||||
|
@ -841,7 +897,7 @@ CObject* File::FlushRequest(const CObjectArray& request) {
|
|||
CObject* File::ReadByteRequest(const CObjectArray& request) {
|
||||
if ((request.Length() == 1) && request[0]->IsIntptr()) {
|
||||
File* file = CObjectToFilePointer(request[0]);
|
||||
ASSERT(file != NULL);
|
||||
RefCntReleaseScope<File> rs(file);
|
||||
if (!file->IsClosed()) {
|
||||
uint8_t buffer;
|
||||
int64_t bytes_read = file->Read(reinterpret_cast<void*>(&buffer), 1);
|
||||
|
@ -865,7 +921,7 @@ CObject* File::WriteByteRequest(const CObjectArray& request) {
|
|||
request[0]->IsIntptr() &&
|
||||
request[1]->IsInt32OrInt64()) {
|
||||
File* file = CObjectToFilePointer(request[0]);
|
||||
ASSERT(file != NULL);
|
||||
RefCntReleaseScope<File> rs(file);
|
||||
if (!file->IsClosed()) {
|
||||
int64_t byte = CObjectInt32OrInt64ToInt64(request[1]);
|
||||
uint8_t buffer = static_cast<uint8_t>(byte & 0xff);
|
||||
|
@ -888,7 +944,7 @@ CObject* File::ReadRequest(const CObjectArray& request) {
|
|||
request[0]->IsIntptr() &&
|
||||
request[1]->IsInt32OrInt64()) {
|
||||
File* file = CObjectToFilePointer(request[0]);
|
||||
ASSERT(file != NULL);
|
||||
RefCntReleaseScope<File> rs(file);
|
||||
if (!file->IsClosed()) {
|
||||
int64_t length = CObjectInt32OrInt64ToInt64(request[1]);
|
||||
Dart_CObject* io_buffer = CObject::NewIOBuffer(length);
|
||||
|
@ -920,7 +976,7 @@ CObject* File::ReadIntoRequest(const CObjectArray& request) {
|
|||
request[0]->IsIntptr() &&
|
||||
request[1]->IsInt32OrInt64()) {
|
||||
File* file = CObjectToFilePointer(request[0]);
|
||||
ASSERT(file != NULL);
|
||||
RefCntReleaseScope<File> rs(file);
|
||||
if (!file->IsClosed()) {
|
||||
int64_t length = CObjectInt32OrInt64ToInt64(request[1]);
|
||||
Dart_CObject* io_buffer = CObject::NewIOBuffer(length);
|
||||
|
@ -980,7 +1036,7 @@ CObject* File::WriteFromRequest(const CObjectArray& request) {
|
|||
request[2]->IsInt32OrInt64() &&
|
||||
request[3]->IsInt32OrInt64()) {
|
||||
File* file = CObjectToFilePointer(request[0]);
|
||||
ASSERT(file != NULL);
|
||||
RefCntReleaseScope<File> rs(file);
|
||||
if (!file->IsClosed()) {
|
||||
int64_t start = CObjectInt32OrInt64ToInt64(request[2]);
|
||||
int64_t end = CObjectInt32OrInt64ToInt64(request[3]);
|
||||
|
@ -1143,7 +1199,7 @@ CObject* File::LockRequest(const CObjectArray& request) {
|
|||
request[2]->IsInt32OrInt64() &&
|
||||
request[3]->IsInt32OrInt64()) {
|
||||
File* file = CObjectToFilePointer(request[0]);
|
||||
ASSERT(file != NULL);
|
||||
RefCntReleaseScope<File> rs(file);
|
||||
if (!file->IsClosed()) {
|
||||
int64_t lock = CObjectInt32OrInt64ToInt64(request[1]);
|
||||
int64_t start = CObjectInt32OrInt64ToInt64(request[2]);
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
|
||||
#include "bin/builtin.h"
|
||||
#include "bin/dartutils.h"
|
||||
#include "bin/log.h"
|
||||
#include "bin/reference_counting.h"
|
||||
|
||||
namespace dart {
|
||||
namespace bin {
|
||||
|
@ -19,7 +21,7 @@ namespace bin {
|
|||
// Forward declaration.
|
||||
class FileHandle;
|
||||
|
||||
class File {
|
||||
class File : public ReferenceCounted<File> {
|
||||
public:
|
||||
enum FileOpenMode {
|
||||
kRead = 0,
|
||||
|
@ -82,8 +84,6 @@ class File {
|
|||
kLockMax = 2
|
||||
};
|
||||
|
||||
~File();
|
||||
|
||||
intptr_t GetFD();
|
||||
|
||||
// Read/Write attempt to transfer num_bytes to/from buffer. It returns
|
||||
|
@ -124,6 +124,26 @@ class File {
|
|||
// Returns whether the file has been closed.
|
||||
bool IsClosed();
|
||||
|
||||
// Calls the platform-specific functions to close the file.
|
||||
void Close();
|
||||
|
||||
// Returns the weak persistent handle for the File's Dart wrapper.
|
||||
Dart_WeakPersistentHandle WeakHandle() const { return weak_handle_; }
|
||||
|
||||
// Set the weak persistent handle for the File's Dart wrapper.
|
||||
void SetWeakHandle(Dart_WeakPersistentHandle handle) {
|
||||
ASSERT(weak_handle_ == NULL);
|
||||
weak_handle_ = handle;
|
||||
}
|
||||
|
||||
// Deletes the weak persistent handle for the File's Dart wrapper. Call
|
||||
// when the file is explicitly closed and the finalizer is no longer
|
||||
// needed.
|
||||
void DeleteWeakHandle(Dart_Isolate isolate) {
|
||||
Dart_DeleteWeakPersistentHandle(isolate, weak_handle_);
|
||||
weak_handle_ = NULL;
|
||||
}
|
||||
|
||||
// Open the file with the given path. The file is always opened for
|
||||
// reading. If mode contains kWrite the file is opened for both
|
||||
// reading and writing. If mode contains kWrite and the file does
|
||||
|
@ -190,8 +210,12 @@ class File {
|
|||
static CObject* LockRequest(const CObjectArray& request);
|
||||
|
||||
private:
|
||||
explicit File(FileHandle* handle) : handle_(handle) { }
|
||||
void Close();
|
||||
explicit File(FileHandle* handle) :
|
||||
ReferenceCounted(),
|
||||
handle_(handle),
|
||||
weak_handle_(NULL) {}
|
||||
|
||||
~File();
|
||||
|
||||
static File* FileOpenW(const wchar_t* system_name, FileOpenMode mode);
|
||||
|
||||
|
@ -200,6 +224,12 @@ class File {
|
|||
// FileHandle is an OS specific class which stores data about the file.
|
||||
FileHandle* handle_; // OS specific handle for the file.
|
||||
|
||||
// We retain the weak handle because we can do cleanup eagerly when Dart code
|
||||
// calls closeSync(). In that case, we delete the weak handle so that the
|
||||
// finalizer doesn't run.
|
||||
Dart_WeakPersistentHandle weak_handle_;
|
||||
|
||||
friend class ReferenceCounted<File>;
|
||||
DISALLOW_COPY_AND_ASSIGN(File);
|
||||
};
|
||||
|
||||
|
|
|
@ -39,7 +39,9 @@ class FileHandle {
|
|||
|
||||
|
||||
File::~File() {
|
||||
Close();
|
||||
if (!IsClosed()) {
|
||||
Close();
|
||||
}
|
||||
delete handle_;
|
||||
}
|
||||
|
||||
|
@ -197,10 +199,7 @@ File* File::Open(const char* path, FileOpenMode mode) {
|
|||
|
||||
|
||||
File* File::OpenStdio(int fd) {
|
||||
if ((fd < 0) || (2 < fd)) {
|
||||
return NULL;
|
||||
}
|
||||
return new File(new FileHandle(fd));
|
||||
return ((fd < 0) || (2 < fd)) ? NULL : new File(new FileHandle(fd));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -38,7 +38,9 @@ class FileHandle {
|
|||
|
||||
|
||||
File::~File() {
|
||||
Close();
|
||||
if (!IsClosed()) {
|
||||
Close();
|
||||
}
|
||||
delete handle_;
|
||||
}
|
||||
|
||||
|
@ -196,10 +198,7 @@ File* File::Open(const char* path, FileOpenMode mode) {
|
|||
|
||||
|
||||
File* File::OpenStdio(int fd) {
|
||||
if ((fd < 0) || (2 < fd)) {
|
||||
return NULL;
|
||||
}
|
||||
return new File(new FileHandle(fd));
|
||||
return ((fd < 0) || (2 < fd)) ? NULL : new File(new FileHandle(fd));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -40,7 +40,9 @@ class FileHandle {
|
|||
|
||||
|
||||
File::~File() {
|
||||
Close();
|
||||
if (!IsClosed()) {
|
||||
Close();
|
||||
}
|
||||
delete handle_;
|
||||
}
|
||||
|
||||
|
@ -199,10 +201,7 @@ File* File::Open(const char* path, FileOpenMode mode) {
|
|||
|
||||
|
||||
File* File::OpenStdio(int fd) {
|
||||
if ((fd < 0) || (2 < fd)) {
|
||||
return NULL;
|
||||
}
|
||||
return new File(new FileHandle(fd));
|
||||
return ((fd < 0) || (2 < fd)) ? NULL : new File(new FileHandle(fd));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -22,24 +22,34 @@ patch class _File {
|
|||
}
|
||||
|
||||
|
||||
patch class _RandomAccessFile {
|
||||
/* patch */ static int _close(int id) native "File_Close";
|
||||
/* patch */ static int _getFD(int id) native "File_GetFD";
|
||||
/* patch */ static _readByte(int id) native "File_ReadByte";
|
||||
/* patch */ static _read(int id, int bytes) native "File_Read";
|
||||
/* patch */ static _readInto(int id, List<int> buffer, int start, int end)
|
||||
native "File_ReadInto";
|
||||
/* patch */ static _writeByte(int id, int value) native "File_WriteByte";
|
||||
/* patch */ static _writeFrom(int id, List<int> buffer, int start, int end)
|
||||
native "File_WriteFrom";
|
||||
/* patch */ static _position(int id) native "File_Position";
|
||||
/* patch */ static _setPosition(int id, int position)
|
||||
native "File_SetPosition";
|
||||
/* patch */ static _truncate(int id, int length) native "File_Truncate";
|
||||
/* patch */ static _length(int id) native "File_Length";
|
||||
/* patch */ static _flush(int id) native "File_Flush";
|
||||
/* patch */ static _lock(int id, int lock, int start, int end)
|
||||
native "File_Lock";
|
||||
patch class _RandomAccessFileOps {
|
||||
/* patch */ factory _RandomAccessFileOps(int pointer)
|
||||
=> new _RandomAccessFileOpsImpl(pointer);
|
||||
}
|
||||
|
||||
|
||||
class _RandomAccessFileOpsImpl extends NativeFieldWrapperClass1
|
||||
implements _RandomAccessFileOps {
|
||||
_RandomAccessFileOpsImpl._();
|
||||
|
||||
factory _RandomAccessFileOpsImpl(int pointer)
|
||||
=> new _RandomAccessFileOpsImpl._().._setPointer(pointer);
|
||||
|
||||
void _setPointer(int pointer) native "File_SetPointer";
|
||||
|
||||
int getPointer() native "File_GetPointer";
|
||||
int close() native "File_Close";
|
||||
readByte() native "File_ReadByte";
|
||||
read(int bytes) native "File_Read";
|
||||
readInto(List<int> buffer, int start, int end) native "File_ReadInto";
|
||||
writeByte(int value) native "File_WriteByte";
|
||||
writeFrom(List<int> buffer, int start, int end) native "File_WriteFrom";
|
||||
position() native "File_Position";
|
||||
setPosition(int position) native "File_SetPosition";
|
||||
truncate(int length) native "File_Truncate";
|
||||
length() native "File_Length";
|
||||
flush() native "File_Flush";
|
||||
lock(int lock, int start, int end) native "File_Lock";
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ TEST_CASE(Read) {
|
|||
buffer[13] = '\0';
|
||||
EXPECT_STREQ("// Copyright ", buffer);
|
||||
EXPECT(!file->WriteByte(1)); // Cannot write to a read-only file.
|
||||
delete file;
|
||||
file->Release();
|
||||
}
|
||||
|
||||
|
||||
|
@ -42,7 +42,7 @@ TEST_CASE(FileLength) {
|
|||
File* file = File::Open(kFilename, File::kRead);
|
||||
EXPECT(file != NULL);
|
||||
EXPECT_EQ(42, file->Length());
|
||||
delete file;
|
||||
file->Release();
|
||||
}
|
||||
|
||||
|
||||
|
@ -56,7 +56,7 @@ TEST_CASE(FilePosition) {
|
|||
EXPECT_EQ(12, file->Position());
|
||||
EXPECT(file->ReadFully(buf, 6));
|
||||
EXPECT_EQ(18, file->Position());
|
||||
delete file;
|
||||
file->Release();
|
||||
}
|
||||
|
||||
} // namespace bin
|
||||
|
|
|
@ -11,6 +11,19 @@
|
|||
namespace dart {
|
||||
namespace bin {
|
||||
|
||||
|
||||
void FUNCTION_NAME(File_GetPointer)(Dart_NativeArguments args) {
|
||||
Dart_ThrowException(DartUtils::NewInternalError(
|
||||
"File is not supported on this platform"));
|
||||
}
|
||||
|
||||
|
||||
void FUNCTION_NAME(File_SetPointer)(Dart_NativeArguments args) {
|
||||
Dart_ThrowException(DartUtils::NewInternalError(
|
||||
"File is not supported on this platform"));
|
||||
}
|
||||
|
||||
|
||||
void FUNCTION_NAME(File_Open)(Dart_NativeArguments args) {
|
||||
Dart_ThrowException(DartUtils::NewInternalError(
|
||||
"File is not supported on this platform"));
|
||||
|
@ -29,12 +42,6 @@ void FUNCTION_NAME(File_Close)(Dart_NativeArguments args) {
|
|||
}
|
||||
|
||||
|
||||
void FUNCTION_NAME(File_GetFD)(Dart_NativeArguments args) {
|
||||
Dart_ThrowException(DartUtils::NewInternalError(
|
||||
"File is not supported on this platform"));
|
||||
}
|
||||
|
||||
|
||||
void FUNCTION_NAME(File_ReadByte)(Dart_NativeArguments args) {
|
||||
Dart_ThrowException(DartUtils::NewInternalError(
|
||||
"File is not supported on this platform"));
|
||||
|
|
|
@ -38,7 +38,9 @@ class FileHandle {
|
|||
|
||||
|
||||
File::~File() {
|
||||
Close();
|
||||
if (!IsClosed()) {
|
||||
Close();
|
||||
}
|
||||
delete handle_;
|
||||
}
|
||||
|
||||
|
|
|
@ -214,7 +214,7 @@ static void WriteSnapshotFile(const char* filename,
|
|||
if (!file->WriteFully(buffer, size)) {
|
||||
Log::PrintErr("Error: Failed to write snapshot file.\n\n");
|
||||
}
|
||||
delete file;
|
||||
file->Release();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -31,9 +31,10 @@ namespace bin {
|
|||
V(Directory_List, 3) \
|
||||
V(EventHandler_SendData, 3) \
|
||||
V(EventHandler_TimerMillisecondClock, 0) \
|
||||
V(File_GetPointer, 1) \
|
||||
V(File_SetPointer, 2) \
|
||||
V(File_Open, 2) \
|
||||
V(File_Exists, 1) \
|
||||
V(File_GetFD, 1) \
|
||||
V(File_Close, 1) \
|
||||
V(File_ReadByte, 1) \
|
||||
V(File_WriteByte, 2) \
|
||||
|
|
|
@ -1099,7 +1099,7 @@ static void WriteSnapshotFile(const char* snapshot_directory,
|
|||
"Unable to open file %s for writing snapshot\n",
|
||||
qualified_filename);
|
||||
}
|
||||
delete file;
|
||||
file->Release();
|
||||
if (concat != NULL) {
|
||||
delete concat;
|
||||
}
|
||||
|
|
|
@ -135,58 +135,10 @@ class _File {
|
|||
}
|
||||
|
||||
@patch
|
||||
class _RandomAccessFile {
|
||||
class _RandomAccessFileOps {
|
||||
@patch
|
||||
static int _close(int id) {
|
||||
throw new UnsupportedError("RandomAccessFile._close");
|
||||
}
|
||||
@patch
|
||||
static int _getFD(int id) {
|
||||
throw new UnsupportedError("RandomAccessFile._getFD");
|
||||
}
|
||||
@patch
|
||||
static _readByte(int id) {
|
||||
throw new UnsupportedError("RandomAccessFile._readByte");
|
||||
}
|
||||
@patch
|
||||
static _read(int id, int bytes) {
|
||||
throw new UnsupportedError("RandomAccessFile._read");
|
||||
}
|
||||
@patch
|
||||
static _readInto(int id, List<int> buffer, int start, int end) {
|
||||
throw new UnsupportedError("RandomAccessFile._readInto");
|
||||
}
|
||||
@patch
|
||||
static _writeByte(int id, int value) {
|
||||
throw new UnsupportedError("RandomAccessFile._writeByte");
|
||||
}
|
||||
@patch
|
||||
static _writeFrom(int id, List<int> buffer, int start, int end) {
|
||||
throw new UnsupportedError("RandomAccessFile._writeFrom");
|
||||
}
|
||||
@patch
|
||||
static _position(int id) {
|
||||
throw new UnsupportedError("RandomAccessFile._position");
|
||||
}
|
||||
@patch
|
||||
static _setPosition(int id, int position) {
|
||||
throw new UnsupportedError("RandomAccessFile._setPosition");
|
||||
}
|
||||
@patch
|
||||
static _truncate(int id, int length) {
|
||||
throw new UnsupportedError("RandomAccessFile._truncate");
|
||||
}
|
||||
@patch
|
||||
static _length(int id) {
|
||||
throw new UnsupportedError("RandomAccessFile._length");
|
||||
}
|
||||
@patch
|
||||
static _flush(int id) {
|
||||
throw new UnsupportedError("RandomAccessFile._flush");
|
||||
}
|
||||
@patch
|
||||
static _lock(int id, int lock, int start, int end) {
|
||||
throw new UnsupportedError("RandomAccessFile._lock");
|
||||
factory _RandomAccessFileOps(int pointer) {
|
||||
throw new UnsupportedError("RandomAccessFile");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -751,7 +751,7 @@ abstract class RandomAccessFile {
|
|||
* already unlocked".
|
||||
*/
|
||||
Future<RandomAccessFile> lock(
|
||||
[FileLock mode = FileLock.EXCLUSIVE, int start = 0, int end]);
|
||||
[FileLock mode = FileLock.EXCLUSIVE, int start = 0, int end = -1]);
|
||||
|
||||
/**
|
||||
* Synchronously locks the file or part of the file.
|
||||
|
@ -784,7 +784,8 @@ abstract class RandomAccessFile {
|
|||
* already unlocked".
|
||||
*
|
||||
*/
|
||||
void lockSync([FileLock mode = FileLock.EXCLUSIVE, int start = 0, int end]);
|
||||
void lockSync(
|
||||
[FileLock mode = FileLock.EXCLUSIVE, int start = 0, int end = -1]);
|
||||
|
||||
/**
|
||||
* Unlocks the file or part of the file.
|
||||
|
@ -800,7 +801,7 @@ abstract class RandomAccessFile {
|
|||
*
|
||||
* See [lock] for more details.
|
||||
*/
|
||||
Future<RandomAccessFile> unlock([int start = 0, int end]);
|
||||
Future<RandomAccessFile> unlock([int start = 0, int end = -1]);
|
||||
|
||||
/**
|
||||
* Synchronously unlocks the file or part of the file.
|
||||
|
@ -816,7 +817,7 @@ abstract class RandomAccessFile {
|
|||
*
|
||||
* See [lockSync] for more details.
|
||||
*/
|
||||
void unlockSync([int start = 0, int end]);
|
||||
void unlockSync([int start = 0, int end = -1]);
|
||||
|
||||
/**
|
||||
* Returns a human-readable string for this RandomAccessFile instance.
|
||||
|
|
|
@ -564,19 +564,43 @@ class _File extends FileSystemEntity implements File {
|
|||
}
|
||||
}
|
||||
|
||||
abstract class _RandomAccessFileOps {
|
||||
external factory _RandomAccessFileOps(int pointer);
|
||||
|
||||
class _RandomAccessFile
|
||||
implements RandomAccessFile {
|
||||
int getPointer();
|
||||
int close();
|
||||
readByte();
|
||||
read(int bytes);
|
||||
readInto(List<int> buffer, int start, int end);
|
||||
writeByte(int value);
|
||||
writeFrom(List<int> buffer, int start, int end);
|
||||
position();
|
||||
setPosition(int position);
|
||||
truncate(int length);
|
||||
length();
|
||||
flush();
|
||||
lock(int lock, int start, int end);
|
||||
}
|
||||
|
||||
class _RandomAccessFile implements RandomAccessFile {
|
||||
static bool _connectedResourceHandler = false;
|
||||
|
||||
final String path;
|
||||
int _id;
|
||||
|
||||
// Calling this function will increase the reference count on the native
|
||||
// object that implements the file operations. It should only be called to
|
||||
// pass the pointer to the IO Service, which will decrement the reference
|
||||
// count when it is finished with it.
|
||||
int _pointer() => _ops.getPointer();
|
||||
|
||||
bool _asyncDispatched = false;
|
||||
SendPort _fileService;
|
||||
|
||||
_FileResourceInfo _resourceInfo;
|
||||
_RandomAccessFileOps _ops;
|
||||
|
||||
_RandomAccessFile(this._id, this.path) {
|
||||
_RandomAccessFile(int pointer, this.path) {
|
||||
_ops = new _RandomAccessFileOps(pointer);
|
||||
_resourceInfo = new _FileResourceInfo(this);
|
||||
_maybeConnectHandler();
|
||||
}
|
||||
|
@ -587,12 +611,10 @@ class _RandomAccessFile
|
|||
}
|
||||
}
|
||||
|
||||
external static int _getFD(int id);
|
||||
|
||||
_maybeConnectHandler() {
|
||||
if (!_connectedResourceHandler) {
|
||||
// TODO(ricow): we probably need set these in some initialization code.
|
||||
// We need to make sure that these are always awailable from the
|
||||
// TODO(ricow): We probably need to set these in some initialization code.
|
||||
// We need to make sure that these are always available from the
|
||||
// observatory even if no files (or sockets for the socket ones) are
|
||||
// open.
|
||||
registerExtension('ext.dart.io.getOpenFiles',
|
||||
|
@ -604,9 +626,9 @@ class _RandomAccessFile
|
|||
}
|
||||
|
||||
Future<RandomAccessFile> close() {
|
||||
return _dispatch(_FILE_CLOSE, [_id], markClosed: true).then((result) {
|
||||
return _dispatch(_FILE_CLOSE, [_pointer()], markClosed: true).then((result) {
|
||||
if (result != -1) {
|
||||
_id = result;
|
||||
closed = closed || (result == 0);
|
||||
_maybePerformCleanup();
|
||||
return this;
|
||||
} else {
|
||||
|
@ -615,20 +637,18 @@ class _RandomAccessFile
|
|||
});
|
||||
}
|
||||
|
||||
external static int _close(int id);
|
||||
|
||||
void closeSync() {
|
||||
_checkAvailable();
|
||||
var id = _close(_id);
|
||||
var id = _ops.close();
|
||||
if (id == -1) {
|
||||
throw new FileSystemException("Cannot close file", path);
|
||||
}
|
||||
_id = id;
|
||||
closed = closed || (id == 0);
|
||||
_maybePerformCleanup();
|
||||
}
|
||||
|
||||
Future<int> readByte() {
|
||||
return _dispatch(_FILE_READ_BYTE, [_id]).then((response) {
|
||||
return _dispatch(_FILE_READ_BYTE, [_pointer()]).then((response) {
|
||||
if (_isErrorResponse(response)) {
|
||||
throw _exceptionFromResponse(response, "readByte failed", path);
|
||||
}
|
||||
|
@ -637,11 +657,9 @@ class _RandomAccessFile
|
|||
});
|
||||
}
|
||||
|
||||
external static _readByte(int id);
|
||||
|
||||
int readByteSync() {
|
||||
_checkAvailable();
|
||||
var result = _readByte(_id);
|
||||
var result = _ops.readByte();
|
||||
if (result is OSError) {
|
||||
throw new FileSystemException("readByte failed", path, result);
|
||||
}
|
||||
|
@ -653,7 +671,7 @@ class _RandomAccessFile
|
|||
if (bytes is !int) {
|
||||
throw new ArgumentError(bytes);
|
||||
}
|
||||
return _dispatch(_FILE_READ, [_id, bytes]).then((response) {
|
||||
return _dispatch(_FILE_READ, [_pointer(), bytes]).then((response) {
|
||||
if (_isErrorResponse(response)) {
|
||||
throw _exceptionFromResponse(response, "read failed", path);
|
||||
}
|
||||
|
@ -662,14 +680,12 @@ class _RandomAccessFile
|
|||
});
|
||||
}
|
||||
|
||||
external static _read(int id, int bytes);
|
||||
|
||||
List<int> readSync(int bytes) {
|
||||
_checkAvailable();
|
||||
if (bytes is !int) {
|
||||
throw new ArgumentError(bytes);
|
||||
}
|
||||
var result = _read(_id, bytes);
|
||||
var result = _ops.read(bytes);
|
||||
if (result is OSError) {
|
||||
throw new FileSystemException("readSync failed", path, result);
|
||||
}
|
||||
|
@ -678,15 +694,17 @@ class _RandomAccessFile
|
|||
}
|
||||
|
||||
Future<int> readInto(List<int> buffer, [int start = 0, int end]) {
|
||||
if (buffer is !List ||
|
||||
(start != null && start is !int) ||
|
||||
(end != null && end is !int)) {
|
||||
if ((buffer is !List) ||
|
||||
((start != null) && (start is !int)) ||
|
||||
((end != null) && (end is !int))) {
|
||||
throw new ArgumentError();
|
||||
}
|
||||
end = RangeError.checkValidRange(start, end, buffer.length);
|
||||
if (end == start) return new Future.value(0);
|
||||
if (end == start) {
|
||||
return new Future.value(0);
|
||||
}
|
||||
int length = end - start;
|
||||
return _dispatch(_FILE_READ_INTO, [_id, length]).then((response) {
|
||||
return _dispatch(_FILE_READ_INTO, [_pointer(), length]).then((response) {
|
||||
if (_isErrorResponse(response)) {
|
||||
throw _exceptionFromResponse(response, "readInto failed", path);
|
||||
}
|
||||
|
@ -698,18 +716,18 @@ class _RandomAccessFile
|
|||
});
|
||||
}
|
||||
|
||||
external static _readInto(int id, List<int> buffer, int start, int end);
|
||||
|
||||
int readIntoSync(List<int> buffer, [int start = 0, int end]) {
|
||||
_checkAvailable();
|
||||
if (buffer is !List ||
|
||||
(start != null && start is !int) ||
|
||||
(end != null && end is !int)) {
|
||||
if ((buffer is !List) ||
|
||||
((start != null) && (start is !int)) ||
|
||||
((end != null) && (end is !int))) {
|
||||
throw new ArgumentError();
|
||||
}
|
||||
end = RangeError.checkValidRange(start, end, buffer.length);
|
||||
if (end == start) return 0;
|
||||
var result = _readInto(_id, buffer, start, end);
|
||||
if (end == start) {
|
||||
return 0;
|
||||
}
|
||||
var result = _ops.readInto(buffer, start, end);
|
||||
if (result is OSError) {
|
||||
throw new FileSystemException("readInto failed", path, result);
|
||||
}
|
||||
|
@ -721,7 +739,7 @@ class _RandomAccessFile
|
|||
if (value is !int) {
|
||||
throw new ArgumentError(value);
|
||||
}
|
||||
return _dispatch(_FILE_WRITE_BYTE, [_id, value]).then((response) {
|
||||
return _dispatch(_FILE_WRITE_BYTE, [_pointer(), value]).then((response) {
|
||||
if (_isErrorResponse(response)) {
|
||||
throw _exceptionFromResponse(response, "writeByte failed", path);
|
||||
}
|
||||
|
@ -730,14 +748,12 @@ class _RandomAccessFile
|
|||
});
|
||||
}
|
||||
|
||||
external static _writeByte(int id, int value);
|
||||
|
||||
int writeByteSync(int value) {
|
||||
_checkAvailable();
|
||||
if (value is !int) {
|
||||
throw new ArgumentError(value);
|
||||
}
|
||||
var result = _writeByte(_id, value);
|
||||
var result = _ops.writeByte(value);
|
||||
if (result is OSError) {
|
||||
throw new FileSystemException("writeByte failed", path, result);
|
||||
}
|
||||
|
@ -748,12 +764,14 @@ class _RandomAccessFile
|
|||
Future<RandomAccessFile> writeFrom(
|
||||
List<int> buffer, [int start = 0, int end]) {
|
||||
if ((buffer is !List) ||
|
||||
(start != null && start is !int) ||
|
||||
(end != null && end is !int)) {
|
||||
((start != null) && (start is !int)) ||
|
||||
((end != null) && (end is !int))) {
|
||||
throw new ArgumentError("Invalid arguments to writeFrom");
|
||||
}
|
||||
end = RangeError.checkValidRange(start, end, buffer.length);
|
||||
if (end == start) return new Future.value(this);
|
||||
if (end == start) {
|
||||
return new Future.value(this);
|
||||
}
|
||||
_BufferAndStart result;
|
||||
try {
|
||||
result = _ensureFastAndSerializableByteData(buffer, start, end);
|
||||
|
@ -762,7 +780,7 @@ class _RandomAccessFile
|
|||
}
|
||||
|
||||
List request = new List(4);
|
||||
request[0] = _id;
|
||||
request[0] = _pointer();
|
||||
request[1] = result.buffer;
|
||||
request[2] = result.start;
|
||||
request[3] = end - (start - result.start);
|
||||
|
@ -775,23 +793,22 @@ class _RandomAccessFile
|
|||
});
|
||||
}
|
||||
|
||||
external static _writeFrom(int id, List<int> buffer, int start, int end);
|
||||
|
||||
void writeFromSync(List<int> buffer, [int start = 0, int end]) {
|
||||
_checkAvailable();
|
||||
if (buffer is !List ||
|
||||
(start != null && start is !int) ||
|
||||
(end != null && end is !int)) {
|
||||
if ((buffer is !List) ||
|
||||
((start != null) && (start is !int)) ||
|
||||
((end != null) && (end is !int))) {
|
||||
throw new ArgumentError("Invalid arguments to writeFromSync");
|
||||
}
|
||||
end = RangeError.checkValidRange(start, end, buffer.length);
|
||||
if (end == start) return;
|
||||
if (end == start) {
|
||||
return;
|
||||
}
|
||||
_BufferAndStart bufferAndStart =
|
||||
_ensureFastAndSerializableByteData(buffer, start, end);
|
||||
var result = _writeFrom(_id,
|
||||
bufferAndStart.buffer,
|
||||
bufferAndStart.start,
|
||||
end - (start - bufferAndStart.start));
|
||||
var result = _ops.writeFrom(bufferAndStart.buffer,
|
||||
bufferAndStart.start,
|
||||
end - (start - bufferAndStart.start));
|
||||
if (result is OSError) {
|
||||
throw new FileSystemException("writeFrom failed", path, result);
|
||||
}
|
||||
|
@ -816,7 +833,7 @@ class _RandomAccessFile
|
|||
}
|
||||
|
||||
Future<int> position() {
|
||||
return _dispatch(_FILE_POSITION, [_id]).then((response) {
|
||||
return _dispatch(_FILE_POSITION, [_pointer()]).then((response) {
|
||||
if (_isErrorResponse(response)) {
|
||||
throw _exceptionFromResponse(response, "position failed", path);
|
||||
}
|
||||
|
@ -824,11 +841,9 @@ class _RandomAccessFile
|
|||
});
|
||||
}
|
||||
|
||||
external static _position(int id);
|
||||
|
||||
int positionSync() {
|
||||
_checkAvailable();
|
||||
var result = _position(_id);
|
||||
var result = _ops.position();
|
||||
if (result is OSError) {
|
||||
throw new FileSystemException("position failed", path, result);
|
||||
}
|
||||
|
@ -836,7 +851,7 @@ class _RandomAccessFile
|
|||
}
|
||||
|
||||
Future<RandomAccessFile> setPosition(int position) {
|
||||
return _dispatch(_FILE_SET_POSITION, [_id, position])
|
||||
return _dispatch(_FILE_SET_POSITION, [_pointer(), position])
|
||||
.then((response) {
|
||||
if (_isErrorResponse(response)) {
|
||||
throw _exceptionFromResponse(response, "setPosition failed", path);
|
||||
|
@ -845,18 +860,16 @@ class _RandomAccessFile
|
|||
});
|
||||
}
|
||||
|
||||
external static _setPosition(int id, int position);
|
||||
|
||||
void setPositionSync(int position) {
|
||||
_checkAvailable();
|
||||
var result = _setPosition(_id, position);
|
||||
var result = _ops.setPosition(position);
|
||||
if (result is OSError) {
|
||||
throw new FileSystemException("setPosition failed", path, result);
|
||||
}
|
||||
}
|
||||
|
||||
Future<RandomAccessFile> truncate(int length) {
|
||||
return _dispatch(_FILE_TRUNCATE, [_id, length]).then((response) {
|
||||
return _dispatch(_FILE_TRUNCATE, [_pointer(), length]).then((response) {
|
||||
if (_isErrorResponse(response)) {
|
||||
throw _exceptionFromResponse(response, "truncate failed", path);
|
||||
}
|
||||
|
@ -864,18 +877,16 @@ class _RandomAccessFile
|
|||
});
|
||||
}
|
||||
|
||||
external static _truncate(int id, int length);
|
||||
|
||||
void truncateSync(int length) {
|
||||
_checkAvailable();
|
||||
var result = _truncate(_id, length);
|
||||
var result = _ops.truncate(length);
|
||||
if (result is OSError) {
|
||||
throw new FileSystemException("truncate failed", path, result);
|
||||
}
|
||||
}
|
||||
|
||||
Future<int> length() {
|
||||
return _dispatch(_FILE_LENGTH, [_id]).then((response) {
|
||||
return _dispatch(_FILE_LENGTH, [_pointer()]).then((response) {
|
||||
if (_isErrorResponse(response)) {
|
||||
throw _exceptionFromResponse(response, "length failed", path);
|
||||
}
|
||||
|
@ -883,11 +894,9 @@ class _RandomAccessFile
|
|||
});
|
||||
}
|
||||
|
||||
external static _length(int id);
|
||||
|
||||
int lengthSync() {
|
||||
_checkAvailable();
|
||||
var result = _length(_id);
|
||||
var result = _ops.length();
|
||||
if (result is OSError) {
|
||||
throw new FileSystemException("length failed", path, result);
|
||||
}
|
||||
|
@ -895,7 +904,7 @@ class _RandomAccessFile
|
|||
}
|
||||
|
||||
Future<RandomAccessFile> flush() {
|
||||
return _dispatch(_FILE_FLUSH, [_id]).then((response) {
|
||||
return _dispatch(_FILE_FLUSH, [_pointer()]).then((response) {
|
||||
if (_isErrorResponse(response)) {
|
||||
throw _exceptionFromResponse(response,
|
||||
"flush failed",
|
||||
|
@ -905,11 +914,9 @@ class _RandomAccessFile
|
|||
});
|
||||
}
|
||||
|
||||
external static _flush(int id);
|
||||
|
||||
void flushSync() {
|
||||
_checkAvailable();
|
||||
var result = _flush(_id);
|
||||
var result = _ops.flush();
|
||||
if (result is OSError) {
|
||||
throw new FileSystemException("flush failed", path, result);
|
||||
}
|
||||
|
@ -920,19 +927,15 @@ class _RandomAccessFile
|
|||
static final int LOCK_EXCLUSIVE = 2;
|
||||
|
||||
Future<RandomAccessFile> lock(
|
||||
[FileLock mode = FileLock.EXCLUSIVE, int start = 0, int end]) {
|
||||
if ((start != null && start is !int) ||
|
||||
(end != null && end is !int) ||
|
||||
mode is !FileLock) {
|
||||
[FileLock mode = FileLock.EXCLUSIVE, int start = 0, int end = -1]) {
|
||||
if ((mode is !FileLock) || (start is !int) || (end is !int)) {
|
||||
throw new ArgumentError();
|
||||
}
|
||||
if (start == null) start = 0;
|
||||
if (end == null) end = -1;
|
||||
if (start < 0 || end < -1 || (end != -1 && start >= end)) {
|
||||
if ((start < 0) || (end < -1) || ((end != -1) && (start >= end))) {
|
||||
throw new ArgumentError();
|
||||
}
|
||||
int lock = mode == FileLock.EXCLUSIVE ? LOCK_EXCLUSIVE : LOCK_SHARED;
|
||||
return _dispatch(_FILE_LOCK, [_id, lock, start, end])
|
||||
int lock = (mode == FileLock.EXCLUSIVE) ? LOCK_EXCLUSIVE : LOCK_SHARED;
|
||||
return _dispatch(_FILE_LOCK, [_pointer(), lock, start, end])
|
||||
.then((response) {
|
||||
if (_isErrorResponse(response)) {
|
||||
throw _exceptionFromResponse(response, 'lock failed', path);
|
||||
|
@ -941,15 +944,14 @@ class _RandomAccessFile
|
|||
});
|
||||
}
|
||||
|
||||
Future<RandomAccessFile> unlock([int start = 0, int end]) {
|
||||
if ((start != null && start is !int) ||
|
||||
(end != null && end is !int)) {
|
||||
Future<RandomAccessFile> unlock([int start = 0, int end = -1]) {
|
||||
if ((start is !int) || (end is !int)) {
|
||||
throw new ArgumentError();
|
||||
}
|
||||
if (start == null) start = 0;
|
||||
if (end == null) end = -1;
|
||||
if (start == end) throw new ArgumentError();
|
||||
return _dispatch(_FILE_LOCK, [_id, LOCK_UNLOCK, start, end])
|
||||
if (start == end) {
|
||||
throw new ArgumentError();
|
||||
}
|
||||
return _dispatch(_FILE_LOCK, [_pointer(), LOCK_UNLOCK, start, end])
|
||||
.then((response) {
|
||||
if (_isErrorResponse(response)) {
|
||||
throw _exceptionFromResponse(response, 'unlock failed', path);
|
||||
|
@ -958,43 +960,37 @@ class _RandomAccessFile
|
|||
});
|
||||
}
|
||||
|
||||
external static _lock(int id, int lock, int start, int end);
|
||||
|
||||
void lockSync([FileLock mode = FileLock.EXCLUSIVE, int start = 0, int end]) {
|
||||
void lockSync(
|
||||
[FileLock mode = FileLock.EXCLUSIVE, int start = 0, int end = -1]) {
|
||||
_checkAvailable();
|
||||
if ((start != null && start is !int) ||
|
||||
(end != null && end is !int) ||
|
||||
mode is !FileLock) {
|
||||
if ((mode is !FileLock) || (start is !int) || (end is !int)) {
|
||||
throw new ArgumentError();
|
||||
}
|
||||
if (start == null) start = 0;
|
||||
if (end == null) end = -1;
|
||||
if (start < 0 || end < -1 || (end != -1 && start >= end)) {
|
||||
if ((start < 0) || (end < -1) || ((end != -1) && (start >= end))) {
|
||||
throw new ArgumentError();
|
||||
}
|
||||
int lock = mode == FileLock.EXCLUSIVE ? LOCK_EXCLUSIVE : LOCK_SHARED;
|
||||
var result = _lock(_id, lock, start, end);
|
||||
int lock = (mode == FileLock.EXCLUSIVE) ? LOCK_EXCLUSIVE : LOCK_SHARED;
|
||||
var result = _ops.lock(lock, start, end);
|
||||
if (result is OSError) {
|
||||
throw new FileSystemException('lock failed', path, result);
|
||||
}
|
||||
}
|
||||
|
||||
void unlockSync([int start = 0, int end]) {
|
||||
void unlockSync([int start = 0, int end = -1]) {
|
||||
_checkAvailable();
|
||||
if ((start != null && start is !int) ||
|
||||
(end != null && end is !int)) {
|
||||
if ((start is !int) || (end is !int)) {
|
||||
throw new ArgumentError();
|
||||
}
|
||||
if (start == null) start = 0;
|
||||
if (end == null) end = -1;
|
||||
if (start == end) throw new ArgumentError();
|
||||
var result = _lock(_id, LOCK_UNLOCK, start, end);
|
||||
if (start == end) {
|
||||
throw new ArgumentError();
|
||||
}
|
||||
var result = _ops.lock(LOCK_UNLOCK, start, end);
|
||||
if (result is OSError) {
|
||||
throw new FileSystemException('unlock failed', path, result);
|
||||
}
|
||||
}
|
||||
|
||||
bool get closed => _id == 0;
|
||||
bool closed = false;
|
||||
|
||||
Future _dispatch(int request, List data, { bool markClosed: false }) {
|
||||
if (closed) {
|
||||
|
@ -1005,9 +1001,9 @@ class _RandomAccessFile
|
|||
return new Future.error(new FileSystemException(msg, path));
|
||||
}
|
||||
if (markClosed) {
|
||||
// Set the id_ to 0 (NULL) to ensure the no more async requests
|
||||
// can be issued for this file.
|
||||
_id = 0;
|
||||
// Set closed to true to ensure that no more async requests can be issued
|
||||
// for this file.
|
||||
closed = true;
|
||||
}
|
||||
_asyncDispatched = true;
|
||||
return _IOService._dispatch(request, data)
|
||||
|
|
|
@ -36,11 +36,11 @@ check(String path, int start, int end, FileLock mode, {bool locked}) {
|
|||
}
|
||||
|
||||
checkLocked(String path,
|
||||
[int start, int end, FileLock mode = FileLock.EXCLUSIVE]) =>
|
||||
[int start = 0, int end = -1, FileLock mode = FileLock.EXCLUSIVE]) =>
|
||||
check(path, start, end, mode, locked: true);
|
||||
|
||||
checkNotLocked(String path,
|
||||
[int start, int end, FileLock mode = FileLock.EXCLUSIVE]) =>
|
||||
[int start = 0, int end = -1, FileLock mode = FileLock.EXCLUSIVE]) =>
|
||||
check(path, start, end, mode, locked: false);
|
||||
|
||||
void testLockWholeFile() {
|
||||
|
|
Loading…
Reference in a new issue