summaryrefslogtreecommitdiffstats
path: root/ppapi/proxy/file_io_resource.cc
diff options
context:
space:
mode:
Diffstat (limited to 'ppapi/proxy/file_io_resource.cc')
-rw-r--r--ppapi/proxy/file_io_resource.cc231
1 files changed, 209 insertions, 22 deletions
diff --git a/ppapi/proxy/file_io_resource.cc b/ppapi/proxy/file_io_resource.cc
index ad07187..e86c321 100644
--- a/ppapi/proxy/file_io_resource.cc
+++ b/ppapi/proxy/file_io_resource.cc
@@ -80,9 +80,39 @@ int32_t FileIOResource::ReadOp::DoWork() {
file_handle_->raw_handle(), offset_, buffer_.get(), bytes_to_read_);
}
+FileIOResource::WriteOp::WriteOp(scoped_refptr<FileHandleHolder> file_handle,
+ int64_t offset,
+ const char* buffer,
+ int32_t bytes_to_write,
+ bool append)
+ : file_handle_(file_handle),
+ offset_(offset),
+ buffer_(buffer),
+ bytes_to_write_(bytes_to_write),
+ append_(append) {
+}
+
+FileIOResource::WriteOp::~WriteOp() {
+}
+
+int32_t FileIOResource::WriteOp::DoWork() {
+ // We can't just call WritePlatformFile in append mode, since NaCl doesn't
+ // implement fcntl, causing the function to call pwrite, which is incorrect.
+ if (append_) {
+ return base::WritePlatformFileAtCurrentPos(
+ file_handle_->raw_handle(), buffer_, bytes_to_write_);
+ } else {
+ return base::WritePlatformFile(
+ file_handle_->raw_handle(), offset_, buffer_, bytes_to_write_);
+ }
+}
+
FileIOResource::FileIOResource(Connection connection, PP_Instance instance)
: PluginResource(connection, instance),
file_system_type_(PP_FILESYSTEMTYPE_INVALID),
+ open_flags_(0),
+ max_written_offset_(0),
+ check_quota_(false),
called_close_(false) {
SendCreate(BROWSER, PpapiHostMsg_FileIO_Create());
}
@@ -113,6 +143,7 @@ int32_t FileIOResource::Open(PP_Resource file_ref,
if (rv != PP_OK)
return rv;
+ open_flags_ = open_flags;
file_system_type_ = create_info.file_system_type;
if (create_info.file_system_plugin_resource) {
@@ -239,22 +270,42 @@ int32_t FileIOResource::Write(int64_t offset,
const char* buffer,
int32_t bytes_to_write,
scoped_refptr<TrackedCallback> callback) {
+ if (!buffer)
+ return PP_ERROR_FAILED;
+ if (bytes_to_write < 0)
+ return PP_ERROR_FAILED;
+ if (!FileHandleHolder::IsValid(file_handle_))
+ return PP_ERROR_FAILED;
+
int32_t rv = state_manager_.CheckOperationState(
FileIOStateManager::OPERATION_WRITE, true);
if (rv != PP_OK)
return rv;
- // TODO(brettw) it would be nice to use a shared memory buffer for large
- // writes rather than having to copy to a string (which will involve a number
- // of extra copies to serialize over IPC).
- bytes_to_write = std::min(bytes_to_write, kMaxReadWriteSize);
- Call<PpapiPluginMsg_FileIO_GeneralReply>(BROWSER,
- PpapiHostMsg_FileIO_Write(offset, std::string(buffer, bytes_to_write)),
- base::Bind(&FileIOResource::OnPluginMsgGeneralComplete, this,
- callback));
-
state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_WRITE);
- return PP_OK_COMPLETIONPENDING;
+
+ if (check_quota_) {
+ int64_t actual_offset =
+ (open_flags_ & PP_FILEOPENFLAG_APPEND) ? max_written_offset_ : offset;
+
+ uint64_t max_offset = actual_offset + bytes_to_write;
+ if (max_offset > static_cast<uint64_t>(std::numeric_limits<int64_t>::max()))
+ return PP_ERROR_FAILED; // amount calculation would overflow.
+ int64_t increase = static_cast<int64_t>(max_offset) - max_written_offset_;
+ if (increase > 0) {
+ int64_t result =
+ file_system_resource_->AsPPB_FileSystem_API()->RequestQuota(
+ increase,
+ base::Bind(&FileIOResource::OnRequestWriteQuotaComplete,
+ this,
+ offset, buffer, bytes_to_write, callback));
+ if (result == PP_OK_COMPLETIONPENDING)
+ return PP_OK_COMPLETIONPENDING;
+ DCHECK(result == increase);
+ max_written_offset_ = max_offset;
+ }
+ }
+ return WriteValidated(offset, buffer, bytes_to_write, callback);
}
int32_t FileIOResource::SetLength(int64_t length,
@@ -263,13 +314,30 @@ int32_t FileIOResource::SetLength(int64_t length,
FileIOStateManager::OPERATION_EXCLUSIVE, true);
if (rv != PP_OK)
return rv;
+ if (length < 0)
+ return PP_ERROR_FAILED;
- Call<PpapiPluginMsg_FileIO_GeneralReply>(BROWSER,
- PpapiHostMsg_FileIO_SetLength(length),
- base::Bind(&FileIOResource::OnPluginMsgGeneralComplete, this,
- callback));
+ if (check_quota_) {
+ int64_t increase = length - max_written_offset_;
+ if (increase > 0) {
+ int32_t result =
+ file_system_resource_->AsPPB_FileSystem_API()->RequestQuota(
+ increase,
+ base::Bind(&FileIOResource::OnRequestSetLengthQuotaComplete,
+ this,
+ length, callback));
+ if (result == PP_OK_COMPLETIONPENDING) {
+ state_manager_.SetPendingOperation(
+ FileIOStateManager::OPERATION_EXCLUSIVE);
+ return PP_OK_COMPLETIONPENDING;
+ }
+ DCHECK(result == increase);
+ max_written_offset_ = length;
+ }
+ }
state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE);
+ SetLengthValidated(length, callback);
return PP_OK_COMPLETIONPENDING;
}
@@ -288,15 +356,29 @@ int32_t FileIOResource::Flush(scoped_refptr<TrackedCallback> callback) {
return PP_OK_COMPLETIONPENDING;
}
+int64_t FileIOResource::GetMaxWrittenOffset() const {
+ return max_written_offset_;
+}
+
+void FileIOResource::SetMaxWrittenOffset(int64_t max_written_offset) {
+ max_written_offset_ = max_written_offset;
+}
+
void FileIOResource::Close() {
if (called_close_)
return;
called_close_ = true;
+ if (check_quota_) {
+ check_quota_ = false;
+ file_system_resource_->AsPPB_FileSystem_API()->CloseQuotaFile(
+ pp_resource());
+ }
+
if (file_handle_)
file_handle_ = NULL;
- Post(BROWSER, PpapiHostMsg_FileIO_Close());
+ Post(BROWSER, PpapiHostMsg_FileIO_Close(max_written_offset_));
}
int32_t FileIOResource::RequestOSFileHandle(
@@ -380,6 +462,57 @@ int32_t FileIOResource::ReadValidated(int64_t offset,
return PP_OK_COMPLETIONPENDING;
}
+int32_t FileIOResource::WriteValidated(
+ int64_t offset,
+ const char* buffer,
+ int32_t bytes_to_write,
+ scoped_refptr<TrackedCallback> callback) {
+ bool append = (open_flags_ & PP_FILEOPENFLAG_APPEND) != 0;
+ if (callback->is_blocking()) {
+ int32_t result;
+ {
+ // Release the proxy lock while making a potentially slow file call.
+ ProxyAutoUnlock unlock;
+ if (append) {
+ result = base::WritePlatformFileAtCurrentPos(
+ file_handle_->raw_handle(), buffer, bytes_to_write);
+ } else {
+ result = base::WritePlatformFile(
+ file_handle_->raw_handle(), offset, buffer, bytes_to_write);
+ }
+ }
+ if (result < 0)
+ result = PP_ERROR_FAILED;
+
+ state_manager_.SetOperationFinished();
+ return result;
+ }
+
+ // For the non-blocking case, post a task to the file thread.
+ scoped_refptr<WriteOp> write_op(
+ new WriteOp(file_handle_, offset, buffer, bytes_to_write, append));
+ base::PostTaskAndReplyWithResult(
+ PpapiGlobals::Get()->GetFileTaskRunner(),
+ FROM_HERE,
+ Bind(&FileIOResource::WriteOp::DoWork, write_op),
+ RunWhileLocked(Bind(&TrackedCallback::Run, callback)));
+ callback->set_completion_task(
+ Bind(&FileIOResource::OnWriteComplete, this, write_op));
+
+ return PP_OK_COMPLETIONPENDING;
+}
+
+void FileIOResource::SetLengthValidated(
+ int64_t length,
+ scoped_refptr<TrackedCallback> callback) {
+ Call<PpapiPluginMsg_FileIO_GeneralReply>(BROWSER,
+ PpapiHostMsg_FileIO_SetLength(length),
+ base::Bind(&FileIOResource::OnPluginMsgGeneralComplete, this,
+ callback));
+
+ max_written_offset_ = length;
+}
+
int32_t FileIOResource::OnQueryComplete(scoped_refptr<QueryOp> query_op,
PP_FileInfo* info,
int32_t result) {
@@ -416,6 +549,49 @@ int32_t FileIOResource::OnReadComplete(scoped_refptr<ReadOp> read_op,
return result;
}
+void FileIOResource::OnRequestWriteQuotaComplete(
+ int64_t offset,
+ const char* buffer,
+ int32_t bytes_to_write,
+ scoped_refptr<TrackedCallback> callback,
+ int64_t granted) {
+ DCHECK(granted >= 0);
+ if (granted == 0) {
+ callback->Run(PP_ERROR_NOQUOTA);
+ return;
+ }
+ max_written_offset_ += granted;
+ int32_t result = WriteValidated(offset, buffer, bytes_to_write, callback);
+ if (result != PP_OK_COMPLETIONPENDING)
+ callback->Run(result);
+}
+
+void FileIOResource::OnRequestSetLengthQuotaComplete(
+ int64_t length,
+ scoped_refptr<TrackedCallback> callback,
+ int64_t granted) {
+ DCHECK(granted >= 0);
+ if (granted == 0) {
+ callback->Run(PP_ERROR_NOQUOTA);
+ return;
+ }
+
+ max_written_offset_ = length;
+ SetLengthValidated(length, callback);
+}
+
+int32_t FileIOResource::OnWriteComplete(scoped_refptr<WriteOp> write_op,
+ int32_t result) {
+ DCHECK(state_manager_.get_pending_operation() ==
+ FileIOStateManager::OPERATION_WRITE);
+ // |result| is the return value of WritePlatformFile; -1 indicates failure.
+ if (result < 0)
+ result = PP_ERROR_FAILED;
+
+ state_manager_.SetOperationFinished();
+ return result;
+}
+
void FileIOResource::OnPluginMsgGeneralComplete(
scoped_refptr<TrackedCallback> callback,
const ResourceMessageReplyParams& params) {
@@ -431,20 +607,31 @@ void FileIOResource::OnPluginMsgGeneralComplete(
void FileIOResource::OnPluginMsgOpenFileComplete(
scoped_refptr<TrackedCallback> callback,
- const ResourceMessageReplyParams& params) {
+ const ResourceMessageReplyParams& params,
+ PP_Resource quota_file_system,
+ int64_t max_written_offset) {
DCHECK(state_manager_.get_pending_operation() ==
FileIOStateManager::OPERATION_EXCLUSIVE);
// Release the FileRef resource.
file_ref_ = NULL;
- if (params.result() == PP_OK)
+ int32_t result = params.result();
+ if (result == PP_OK) {
state_manager_.SetOpenSucceed();
- int32_t result = params.result();
- IPC::PlatformFileForTransit transit_file;
- if ((result == PP_OK) && params.TakeFileHandleAtIndex(0, &transit_file)) {
- file_handle_ = new FileHandleHolder(
- IPC::PlatformFileForTransitToPlatformFile(transit_file));
+ if (quota_file_system) {
+ DCHECK(quota_file_system == file_system_resource_->pp_resource());
+ check_quota_ = true;
+ max_written_offset_ = max_written_offset;
+ file_system_resource_->AsPPB_FileSystem_API()->OpenQuotaFile(
+ pp_resource());
+ }
+
+ IPC::PlatformFileForTransit transit_file;
+ if (params.TakeFileHandleAtIndex(0, &transit_file)) {
+ file_handle_ = new FileHandleHolder(
+ IPC::PlatformFileForTransitToPlatformFile(transit_file));
+ }
}
// End this operation now, so the user's callback can execute another FileIO
// operation, assuming there are no other pending operations.