Index: ppapi/native_client/src/trusted/plugin/local_temp_file.cc |
diff --git a/ppapi/native_client/src/trusted/plugin/local_temp_file.cc b/ppapi/native_client/src/trusted/plugin/local_temp_file.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..d22fbf88108aedda27ca131c1d0240bf11739d17 |
--- /dev/null |
+++ b/ppapi/native_client/src/trusted/plugin/local_temp_file.cc |
@@ -0,0 +1,242 @@ |
+// Copyright (c) 2012 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "native_client/src/trusted/plugin/local_temp_file.h" |
+ |
+#include "native_client/src/include/portability_io.h" |
+#include "native_client/src/shared/platform/nacl_check.h" |
+#include "native_client/src/trusted/plugin/plugin.h" |
+#include "native_client/src/trusted/plugin/utility.h" |
+ |
+#include "ppapi/c/ppb_file_io.h" |
+#include "ppapi/cpp/file_io.h" |
+#include "ppapi/cpp/file_ref.h" |
+#include "ppapi/cpp/file_system.h" |
+ |
+////////////////////////////////////////////////////////////////////// |
+// Local temporary file access. |
+////////////////////////////////////////////////////////////////////// |
+namespace plugin { |
+ |
+namespace { |
+nacl::string Random32CharHexString(struct NaClDescRng* rng) { |
+ struct NaClDesc* desc = reinterpret_cast<struct NaClDesc*>(rng); |
+ const struct NaClDescVtbl* vtbl = |
+ reinterpret_cast<const struct NaClDescVtbl*>(desc->base.vtbl); |
+ |
+ nacl::string hex_string; |
+ const int32_t kTempFileNameWords = 4; |
+ for (int32_t i = 0; i < kTempFileNameWords; ++i) { |
+ int32_t num; |
+ CHECK(sizeof num == vtbl->Read(desc, |
+ reinterpret_cast<char*>(&num), |
+ sizeof num)); |
+ char frag[16]; |
+ SNPRINTF(frag, sizeof frag, "%08x", num); |
+ hex_string += nacl::string(frag); |
+ } |
+ return hex_string; |
+} |
+ |
+// Some constants for LocalTempFile::GetFD readability. |
+const bool kReadOnly = false; |
+const bool kWriteable = true; |
+} // namespace |
+ |
+uint32_t LocalTempFile::next_identifier = 0; |
+ |
+LocalTempFile::LocalTempFile(Plugin* plugin, |
+ pp::FileSystem* file_system, |
+ const nacl::string &base_dir) |
+ : plugin_(plugin), |
+ file_system_(file_system), |
+ base_dir_(base_dir) { |
+ PLUGIN_PRINTF(("LocalTempFile::LocalTempFile (plugin=%p, " |
+ "file_system=%p)\n", |
+ static_cast<void*>(plugin), static_cast<void*>(file_system))); |
+ Initialize(); |
+} |
+ |
+LocalTempFile::LocalTempFile(Plugin* plugin, |
+ pp::FileSystem* file_system, |
+ const nacl::string &base_dir, |
+ const nacl::string &filename) |
+ : plugin_(plugin), |
+ file_system_(file_system), |
+ base_dir_(base_dir), |
+ filename_(base_dir + "/" + filename) { |
+ PLUGIN_PRINTF(("LocalTempFile::LocalTempFile (plugin=%p, " |
+ "file_system=%p, filename=%s)\n", |
+ static_cast<void*>(plugin), static_cast<void*>(file_system), |
+ filename.c_str())); |
+ file_ref_.reset(new pp::FileRef(*file_system_, filename_.c_str())); |
+ Initialize(); |
+} |
+ |
+void LocalTempFile::Initialize() { |
+ callback_factory_.Initialize(this); |
+ rng_desc_ = (struct NaClDescRng *) malloc(sizeof *rng_desc_); |
+ CHECK(rng_desc_ != NULL); |
+ CHECK(NaClDescRngCtor(rng_desc_)); |
+ file_io_trusted_ = static_cast<const PPB_FileIOTrusted*>( |
+ pp::Module::Get()->GetBrowserInterface(PPB_FILEIOTRUSTED_INTERFACE)); |
+ ++next_identifier; |
+ SNPRINTF(reinterpret_cast<char *>(identifier_), sizeof identifier_, |
+ "%"NACL_PRIu32, next_identifier); |
+} |
+ |
+LocalTempFile::~LocalTempFile() { |
+ PLUGIN_PRINTF(("LocalTempFile::~LocalTempFile\n")); |
+ NaClDescUnref(reinterpret_cast<NaClDesc*>(rng_desc_)); |
+} |
+ |
+void LocalTempFile::OpenWrite(const pp::CompletionCallback& cb) { |
+ done_callback_ = cb; |
+ // If we don't already have a filename, generate one. |
+ if (filename_ == "") { |
+ // Get a random temp file name. |
+ filename_ = base_dir_ + "/" + Random32CharHexString(rng_desc_); |
+ // Remember the ref used to open for writing and reading. |
+ file_ref_.reset(new pp::FileRef(*file_system_, filename_.c_str())); |
+ } |
+ PLUGIN_PRINTF(("LocalTempFile::OpenWrite: %s\n", filename_.c_str())); |
+ // Open the writeable file. |
+ write_io_.reset(new pp::FileIO(plugin_)); |
+ pp::CompletionCallback open_write_cb = |
+ callback_factory_.NewCallback(&LocalTempFile::WriteFileDidOpen); |
+ write_io_->Open(*file_ref_, |
+ PP_FILEOPENFLAG_WRITE | |
+ PP_FILEOPENFLAG_CREATE | |
+ PP_FILEOPENFLAG_EXCLUSIVE, |
+ open_write_cb); |
+} |
+ |
+int32_t LocalTempFile::GetFD(int32_t pp_error, |
+ const pp::Resource& resource, |
+ bool is_writable) { |
+ PLUGIN_PRINTF(("LocalTempFile::GetFD (pp_error=%"NACL_PRId32 |
+ ", is_writable=%d)\n", pp_error, is_writable)); |
+ if (pp_error != PP_OK) { |
+ PLUGIN_PRINTF(("LocalTempFile::GetFD pp_error != PP_OK\n")); |
+ return -1; |
+ } |
+ int32_t file_desc = |
+ file_io_trusted_->GetOSFileDescriptor(resource.pp_resource()); |
+#if NACL_WINDOWS |
+ // Convert the Windows HANDLE from Pepper to a POSIX file descriptor. |
+ int32_t open_flags = ((is_writable ? _O_RDWR : _O_RDONLY) | _O_BINARY); |
+ int32_t posix_desc = _open_osfhandle(file_desc, open_flags); |
+ if (posix_desc == -1) { |
+ // Close the Windows HANDLE if it can't be converted. |
+ CloseHandle(reinterpret_cast<HANDLE>(file_desc)); |
+ PLUGIN_PRINTF(("LocalTempFile::GetFD _open_osfhandle failed.\n")); |
+ return NACL_NO_FILE_DESC; |
+ } |
+ file_desc = posix_desc; |
+#endif |
+ int32_t file_desc_ok_to_close = DUP(file_desc); |
+ if (file_desc_ok_to_close == NACL_NO_FILE_DESC) { |
+ PLUGIN_PRINTF(("LocalTempFile::GetFD dup failed.\n")); |
+ return -1; |
+ } |
+ return file_desc_ok_to_close; |
+} |
+ |
+void LocalTempFile::WriteFileDidOpen(int32_t pp_error) { |
+ PLUGIN_PRINTF(("LocalTempFile::WriteFileDidOpen (pp_error=%" |
+ NACL_PRId32")\n", pp_error)); |
+ if (pp_error == PP_ERROR_FILEEXISTS) { |
+ // Filenames clashed, retry. |
+ filename_ = ""; |
+ OpenWrite(done_callback_); |
+ } |
+ // Run the client's completion callback. |
+ pp::Core* core = pp::Module::Get()->core(); |
+ if (pp_error != PP_OK) { |
+ core->CallOnMainThread(0, done_callback_, pp_error); |
+ return; |
+ } |
+ // Remember the object temporary file descriptor. |
+ int32_t fd = GetFD(pp_error, *write_io_, kWriteable); |
+ if (fd < 0) { |
+ core->CallOnMainThread(0, done_callback_, pp_error); |
+ return; |
+ } |
+ // The descriptor for a writeable file needs to have quota management. |
+ write_wrapper_.reset( |
+ plugin_->wrapper_factory()->MakeFileDescQuota(fd, O_RDWR, identifier_)); |
+ core->CallOnMainThread(0, done_callback_, PP_OK); |
+} |
+ |
+void LocalTempFile::OpenRead(const pp::CompletionCallback& cb) { |
+ PLUGIN_PRINTF(("LocalTempFile::OpenRead: %s\n", filename_.c_str())); |
+ done_callback_ = cb; |
+ // Open the read only file. |
+ read_io_.reset(new pp::FileIO(plugin_)); |
+ pp::CompletionCallback open_read_cb = |
+ callback_factory_.NewCallback(&LocalTempFile::ReadFileDidOpen); |
+ read_io_->Open(*file_ref_, PP_FILEOPENFLAG_READ, open_read_cb); |
+} |
+ |
+void LocalTempFile::ReadFileDidOpen(int32_t pp_error) { |
+ PLUGIN_PRINTF(("LocalTempFile::ReadFileDidOpen (pp_error=%" |
+ NACL_PRId32")\n", pp_error)); |
+ // Run the client's completion callback. |
+ pp::Core* core = pp::Module::Get()->core(); |
+ if (pp_error != PP_OK) { |
+ core->CallOnMainThread(0, done_callback_, pp_error); |
+ return; |
+ } |
+ // Remember the object temporary file descriptor. |
+ int32_t fd = GetFD(pp_error, *read_io_, kReadOnly); |
+ if (fd < 0) { |
+ core->CallOnMainThread(0, done_callback_, PP_ERROR_FAILED); |
+ return; |
+ } |
+ read_wrapper_.reset(plugin_->wrapper_factory()->MakeFileDesc(fd, O_RDONLY)); |
+ core->CallOnMainThread(0, done_callback_, PP_OK); |
+} |
+ |
+void LocalTempFile::Close(const pp::CompletionCallback& cb) { |
+ PLUGIN_PRINTF(("LocalTempFile::Close: %s\n", filename_.c_str())); |
+ // Close the open DescWrappers and FileIOs. |
+ if (write_io_.get() != NULL) { |
+ write_io_->Close(); |
+ } |
+ write_wrapper_.reset(NULL); |
+ write_io_.reset(NULL); |
+ if (read_io_.get() != NULL) { |
+ read_io_->Close(); |
+ } |
+ read_wrapper_.reset(NULL); |
+ read_io_.reset(NULL); |
+ // Run the client's completion callback. |
+ pp::Core* core = pp::Module::Get()->core(); |
+ core->CallOnMainThread(0, cb, PP_OK); |
+} |
+ |
+void LocalTempFile::Delete(const pp::CompletionCallback& cb) { |
+ PLUGIN_PRINTF(("LocalTempFile::Delete: %s\n", filename_.c_str())); |
+ file_ref_->Delete(cb); |
+} |
+ |
+void LocalTempFile::Rename(const nacl::string& new_name, |
+ const pp::CompletionCallback& cb) { |
+ // Rename the temporary file. |
+ filename_ = base_dir_ + "/" + new_name; |
+ PLUGIN_PRINTF(("LocalTempFile::Rename %s to %s\n", |
+ file_ref_->GetName().AsString().c_str(), |
+ filename_.c_str())); |
+ // Remember the old ref until the rename is complete. |
+ old_ref_.reset(file_ref_.release()); |
+ file_ref_.reset(new pp::FileRef(*file_system_, filename_.c_str())); |
+ old_ref_->Rename(*file_ref_, cb); |
+} |
+ |
+void LocalTempFile::FinishRename() { |
+ // Now we can release the old ref. |
+ old_ref_.reset(NULL); |
+} |
+ |
+} // namespace plugin |