OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "native_client/src/trusted/plugin/local_temp_file.h" |
| 6 |
| 7 #include "native_client/src/include/portability_io.h" |
| 8 #include "native_client/src/shared/platform/nacl_check.h" |
| 9 #include "native_client/src/trusted/plugin/plugin.h" |
| 10 #include "native_client/src/trusted/plugin/utility.h" |
| 11 |
| 12 #include "ppapi/c/ppb_file_io.h" |
| 13 #include "ppapi/cpp/file_io.h" |
| 14 #include "ppapi/cpp/file_ref.h" |
| 15 #include "ppapi/cpp/file_system.h" |
| 16 |
| 17 ////////////////////////////////////////////////////////////////////// |
| 18 // Local temporary file access. |
| 19 ////////////////////////////////////////////////////////////////////// |
| 20 namespace plugin { |
| 21 |
| 22 namespace { |
| 23 nacl::string Random32CharHexString(struct NaClDescRng* rng) { |
| 24 struct NaClDesc* desc = reinterpret_cast<struct NaClDesc*>(rng); |
| 25 const struct NaClDescVtbl* vtbl = |
| 26 reinterpret_cast<const struct NaClDescVtbl*>(desc->base.vtbl); |
| 27 |
| 28 nacl::string hex_string; |
| 29 const int32_t kTempFileNameWords = 4; |
| 30 for (int32_t i = 0; i < kTempFileNameWords; ++i) { |
| 31 int32_t num; |
| 32 CHECK(sizeof num == vtbl->Read(desc, |
| 33 reinterpret_cast<char*>(&num), |
| 34 sizeof num)); |
| 35 char frag[16]; |
| 36 SNPRINTF(frag, sizeof frag, "%08x", num); |
| 37 hex_string += nacl::string(frag); |
| 38 } |
| 39 return hex_string; |
| 40 } |
| 41 |
| 42 // Some constants for LocalTempFile::GetFD readability. |
| 43 const bool kReadOnly = false; |
| 44 const bool kWriteable = true; |
| 45 } // namespace |
| 46 |
| 47 uint32_t LocalTempFile::next_identifier = 0; |
| 48 |
| 49 LocalTempFile::LocalTempFile(Plugin* plugin, |
| 50 pp::FileSystem* file_system, |
| 51 const nacl::string &base_dir) |
| 52 : plugin_(plugin), |
| 53 file_system_(file_system), |
| 54 base_dir_(base_dir) { |
| 55 PLUGIN_PRINTF(("LocalTempFile::LocalTempFile (plugin=%p, " |
| 56 "file_system=%p)\n", |
| 57 static_cast<void*>(plugin), static_cast<void*>(file_system))); |
| 58 Initialize(); |
| 59 } |
| 60 |
| 61 LocalTempFile::LocalTempFile(Plugin* plugin, |
| 62 pp::FileSystem* file_system, |
| 63 const nacl::string &base_dir, |
| 64 const nacl::string &filename) |
| 65 : plugin_(plugin), |
| 66 file_system_(file_system), |
| 67 base_dir_(base_dir), |
| 68 filename_(base_dir + "/" + filename) { |
| 69 PLUGIN_PRINTF(("LocalTempFile::LocalTempFile (plugin=%p, " |
| 70 "file_system=%p, filename=%s)\n", |
| 71 static_cast<void*>(plugin), static_cast<void*>(file_system), |
| 72 filename.c_str())); |
| 73 file_ref_.reset(new pp::FileRef(*file_system_, filename_.c_str())); |
| 74 Initialize(); |
| 75 } |
| 76 |
| 77 void LocalTempFile::Initialize() { |
| 78 callback_factory_.Initialize(this); |
| 79 rng_desc_ = (struct NaClDescRng *) malloc(sizeof *rng_desc_); |
| 80 CHECK(rng_desc_ != NULL); |
| 81 CHECK(NaClDescRngCtor(rng_desc_)); |
| 82 file_io_trusted_ = static_cast<const PPB_FileIOTrusted*>( |
| 83 pp::Module::Get()->GetBrowserInterface(PPB_FILEIOTRUSTED_INTERFACE)); |
| 84 ++next_identifier; |
| 85 SNPRINTF(reinterpret_cast<char *>(identifier_), sizeof identifier_, |
| 86 "%"NACL_PRIu32, next_identifier); |
| 87 } |
| 88 |
| 89 LocalTempFile::~LocalTempFile() { |
| 90 PLUGIN_PRINTF(("LocalTempFile::~LocalTempFile\n")); |
| 91 NaClDescUnref(reinterpret_cast<NaClDesc*>(rng_desc_)); |
| 92 } |
| 93 |
| 94 void LocalTempFile::OpenWrite(const pp::CompletionCallback& cb) { |
| 95 done_callback_ = cb; |
| 96 // If we don't already have a filename, generate one. |
| 97 if (filename_ == "") { |
| 98 // Get a random temp file name. |
| 99 filename_ = base_dir_ + "/" + Random32CharHexString(rng_desc_); |
| 100 // Remember the ref used to open for writing and reading. |
| 101 file_ref_.reset(new pp::FileRef(*file_system_, filename_.c_str())); |
| 102 } |
| 103 PLUGIN_PRINTF(("LocalTempFile::OpenWrite: %s\n", filename_.c_str())); |
| 104 // Open the writeable file. |
| 105 write_io_.reset(new pp::FileIO(plugin_)); |
| 106 pp::CompletionCallback open_write_cb = |
| 107 callback_factory_.NewCallback(&LocalTempFile::WriteFileDidOpen); |
| 108 write_io_->Open(*file_ref_, |
| 109 PP_FILEOPENFLAG_WRITE | |
| 110 PP_FILEOPENFLAG_CREATE | |
| 111 PP_FILEOPENFLAG_EXCLUSIVE, |
| 112 open_write_cb); |
| 113 } |
| 114 |
| 115 int32_t LocalTempFile::GetFD(int32_t pp_error, |
| 116 const pp::Resource& resource, |
| 117 bool is_writable) { |
| 118 PLUGIN_PRINTF(("LocalTempFile::GetFD (pp_error=%"NACL_PRId32 |
| 119 ", is_writable=%d)\n", pp_error, is_writable)); |
| 120 if (pp_error != PP_OK) { |
| 121 PLUGIN_PRINTF(("LocalTempFile::GetFD pp_error != PP_OK\n")); |
| 122 return -1; |
| 123 } |
| 124 int32_t file_desc = |
| 125 file_io_trusted_->GetOSFileDescriptor(resource.pp_resource()); |
| 126 #if NACL_WINDOWS |
| 127 // Convert the Windows HANDLE from Pepper to a POSIX file descriptor. |
| 128 int32_t open_flags = ((is_writable ? _O_RDWR : _O_RDONLY) | _O_BINARY); |
| 129 int32_t posix_desc = _open_osfhandle(file_desc, open_flags); |
| 130 if (posix_desc == -1) { |
| 131 // Close the Windows HANDLE if it can't be converted. |
| 132 CloseHandle(reinterpret_cast<HANDLE>(file_desc)); |
| 133 PLUGIN_PRINTF(("LocalTempFile::GetFD _open_osfhandle failed.\n")); |
| 134 return NACL_NO_FILE_DESC; |
| 135 } |
| 136 file_desc = posix_desc; |
| 137 #endif |
| 138 int32_t file_desc_ok_to_close = DUP(file_desc); |
| 139 if (file_desc_ok_to_close == NACL_NO_FILE_DESC) { |
| 140 PLUGIN_PRINTF(("LocalTempFile::GetFD dup failed.\n")); |
| 141 return -1; |
| 142 } |
| 143 return file_desc_ok_to_close; |
| 144 } |
| 145 |
| 146 void LocalTempFile::WriteFileDidOpen(int32_t pp_error) { |
| 147 PLUGIN_PRINTF(("LocalTempFile::WriteFileDidOpen (pp_error=%" |
| 148 NACL_PRId32")\n", pp_error)); |
| 149 if (pp_error == PP_ERROR_FILEEXISTS) { |
| 150 // Filenames clashed, retry. |
| 151 filename_ = ""; |
| 152 OpenWrite(done_callback_); |
| 153 } |
| 154 // Run the client's completion callback. |
| 155 pp::Core* core = pp::Module::Get()->core(); |
| 156 if (pp_error != PP_OK) { |
| 157 core->CallOnMainThread(0, done_callback_, pp_error); |
| 158 return; |
| 159 } |
| 160 // Remember the object temporary file descriptor. |
| 161 int32_t fd = GetFD(pp_error, *write_io_, kWriteable); |
| 162 if (fd < 0) { |
| 163 core->CallOnMainThread(0, done_callback_, pp_error); |
| 164 return; |
| 165 } |
| 166 // The descriptor for a writeable file needs to have quota management. |
| 167 write_wrapper_.reset( |
| 168 plugin_->wrapper_factory()->MakeFileDescQuota(fd, O_RDWR, identifier_)); |
| 169 core->CallOnMainThread(0, done_callback_, PP_OK); |
| 170 } |
| 171 |
| 172 void LocalTempFile::OpenRead(const pp::CompletionCallback& cb) { |
| 173 PLUGIN_PRINTF(("LocalTempFile::OpenRead: %s\n", filename_.c_str())); |
| 174 done_callback_ = cb; |
| 175 // Open the read only file. |
| 176 read_io_.reset(new pp::FileIO(plugin_)); |
| 177 pp::CompletionCallback open_read_cb = |
| 178 callback_factory_.NewCallback(&LocalTempFile::ReadFileDidOpen); |
| 179 read_io_->Open(*file_ref_, PP_FILEOPENFLAG_READ, open_read_cb); |
| 180 } |
| 181 |
| 182 void LocalTempFile::ReadFileDidOpen(int32_t pp_error) { |
| 183 PLUGIN_PRINTF(("LocalTempFile::ReadFileDidOpen (pp_error=%" |
| 184 NACL_PRId32")\n", pp_error)); |
| 185 // Run the client's completion callback. |
| 186 pp::Core* core = pp::Module::Get()->core(); |
| 187 if (pp_error != PP_OK) { |
| 188 core->CallOnMainThread(0, done_callback_, pp_error); |
| 189 return; |
| 190 } |
| 191 // Remember the object temporary file descriptor. |
| 192 int32_t fd = GetFD(pp_error, *read_io_, kReadOnly); |
| 193 if (fd < 0) { |
| 194 core->CallOnMainThread(0, done_callback_, PP_ERROR_FAILED); |
| 195 return; |
| 196 } |
| 197 read_wrapper_.reset(plugin_->wrapper_factory()->MakeFileDesc(fd, O_RDONLY)); |
| 198 core->CallOnMainThread(0, done_callback_, PP_OK); |
| 199 } |
| 200 |
| 201 void LocalTempFile::Close(const pp::CompletionCallback& cb) { |
| 202 PLUGIN_PRINTF(("LocalTempFile::Close: %s\n", filename_.c_str())); |
| 203 // Close the open DescWrappers and FileIOs. |
| 204 if (write_io_.get() != NULL) { |
| 205 write_io_->Close(); |
| 206 } |
| 207 write_wrapper_.reset(NULL); |
| 208 write_io_.reset(NULL); |
| 209 if (read_io_.get() != NULL) { |
| 210 read_io_->Close(); |
| 211 } |
| 212 read_wrapper_.reset(NULL); |
| 213 read_io_.reset(NULL); |
| 214 // Run the client's completion callback. |
| 215 pp::Core* core = pp::Module::Get()->core(); |
| 216 core->CallOnMainThread(0, cb, PP_OK); |
| 217 } |
| 218 |
| 219 void LocalTempFile::Delete(const pp::CompletionCallback& cb) { |
| 220 PLUGIN_PRINTF(("LocalTempFile::Delete: %s\n", filename_.c_str())); |
| 221 file_ref_->Delete(cb); |
| 222 } |
| 223 |
| 224 void LocalTempFile::Rename(const nacl::string& new_name, |
| 225 const pp::CompletionCallback& cb) { |
| 226 // Rename the temporary file. |
| 227 filename_ = base_dir_ + "/" + new_name; |
| 228 PLUGIN_PRINTF(("LocalTempFile::Rename %s to %s\n", |
| 229 file_ref_->GetName().AsString().c_str(), |
| 230 filename_.c_str())); |
| 231 // Remember the old ref until the rename is complete. |
| 232 old_ref_.reset(file_ref_.release()); |
| 233 file_ref_.reset(new pp::FileRef(*file_system_, filename_.c_str())); |
| 234 old_ref_->Rename(*file_ref_, cb); |
| 235 } |
| 236 |
| 237 void LocalTempFile::FinishRename() { |
| 238 // Now we can release the old ref. |
| 239 old_ref_.reset(NULL); |
| 240 } |
| 241 |
| 242 } // namespace plugin |
OLD | NEW |