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.
5 #include "ppapi/native_client/src/trusted/plugin/local_temp_file.h"
7 #include "native_client/src/include/portability_io.h"
8 #include "native_client/src/shared/platform/nacl_check.h"
10 #include "ppapi/c/ppb_file_io.h"
11 #include "ppapi/cpp/file_io.h"
12 #include "ppapi/cpp/file_ref.h"
13 #include "ppapi/cpp/file_system.h"
15 #include "ppapi/native_client/src/trusted/plugin/plugin.h"
16 #include "ppapi/native_client/src/trusted/plugin/utility.h"
18 //////////////////////////////////////////////////////////////////////
19 // Local temporary file access.
20 //////////////////////////////////////////////////////////////////////
24 nacl::string
Random32CharHexString(struct NaClDescRng
* rng
) {
25 struct NaClDesc
* desc
= reinterpret_cast<struct NaClDesc
*>(rng
);
26 const struct NaClDescVtbl
* vtbl
=
27 reinterpret_cast<const struct NaClDescVtbl
*>(desc
->base
.vtbl
);
29 nacl::string hex_string
;
30 const int32_t kTempFileNameWords
= 4;
31 for (int32_t i
= 0; i
< kTempFileNameWords
; ++i
) {
33 CHECK(sizeof num
== vtbl
->Read(desc
,
34 reinterpret_cast<char*>(&num
),
37 SNPRINTF(frag
, sizeof frag
, "%08x", num
);
38 hex_string
+= nacl::string(frag
);
43 // Some constants for LocalTempFile::GetFD readability.
44 const bool kReadOnly
= false;
45 const bool kWriteable
= true;
48 uint32_t LocalTempFile::next_identifier
= 0;
50 LocalTempFile::LocalTempFile(Plugin
* plugin
,
51 pp::FileSystem
* file_system
,
52 const nacl::string
&base_dir
)
54 file_system_(file_system
),
56 PLUGIN_PRINTF(("LocalTempFile::LocalTempFile (plugin=%p, "
58 static_cast<void*>(plugin
), static_cast<void*>(file_system
)));
62 LocalTempFile::LocalTempFile(Plugin
* plugin
,
63 pp::FileSystem
* file_system
,
64 const nacl::string
&base_dir
,
65 const nacl::string
&filename
)
67 file_system_(file_system
),
69 filename_(base_dir
+ "/" + filename
) {
70 PLUGIN_PRINTF(("LocalTempFile::LocalTempFile (plugin=%p, "
71 "file_system=%p, filename=%s)\n",
72 static_cast<void*>(plugin
), static_cast<void*>(file_system
),
74 file_ref_
.reset(new pp::FileRef(*file_system_
, filename_
.c_str()));
78 void LocalTempFile::Initialize() {
79 callback_factory_
.Initialize(this);
80 rng_desc_
= (struct NaClDescRng
*) malloc(sizeof *rng_desc_
);
81 CHECK(rng_desc_
!= NULL
);
82 CHECK(NaClDescRngCtor(rng_desc_
));
83 file_io_trusted_
= static_cast<const PPB_FileIOTrusted
*>(
84 pp::Module::Get()->GetBrowserInterface(PPB_FILEIOTRUSTED_INTERFACE
));
86 SNPRINTF(reinterpret_cast<char *>(identifier_
), sizeof identifier_
,
87 "%" NACL_PRIu32
, next_identifier
);
90 LocalTempFile::~LocalTempFile() {
91 PLUGIN_PRINTF(("LocalTempFile::~LocalTempFile\n"));
92 NaClDescUnref(reinterpret_cast<NaClDesc
*>(rng_desc_
));
95 void LocalTempFile::OpenWrite(const pp::CompletionCallback
& cb
) {
97 // If we don't already have a filename, generate one.
98 if (filename_
== "") {
99 // Get a random temp file name.
100 filename_
= base_dir_
+ "/" + Random32CharHexString(rng_desc_
);
101 // Remember the ref used to open for writing and reading.
102 file_ref_
.reset(new pp::FileRef(*file_system_
, filename_
.c_str()));
104 PLUGIN_PRINTF(("LocalTempFile::OpenWrite: %s\n", filename_
.c_str()));
105 // Open the writeable file.
106 write_io_
.reset(new pp::FileIO(plugin_
));
107 pp::CompletionCallback open_write_cb
=
108 callback_factory_
.NewCallback(&LocalTempFile::WriteFileDidOpen
);
109 write_io_
->Open(*file_ref_
,
110 PP_FILEOPENFLAG_WRITE
|
111 PP_FILEOPENFLAG_CREATE
|
112 PP_FILEOPENFLAG_EXCLUSIVE
,
116 int32_t LocalTempFile::GetFD(int32_t pp_error
,
117 const pp::Resource
& resource
,
119 PLUGIN_PRINTF(("LocalTempFile::GetFD (pp_error=%" NACL_PRId32
120 ", is_writable=%d)\n", pp_error
, is_writable
));
121 if (pp_error
!= PP_OK
) {
122 PLUGIN_PRINTF(("LocalTempFile::GetFD pp_error != PP_OK\n"));
126 file_io_trusted_
->GetOSFileDescriptor(resource
.pp_resource());
128 // Convert the Windows HANDLE from Pepper to a POSIX file descriptor.
129 int32_t open_flags
= ((is_writable
? _O_RDWR
: _O_RDONLY
) | _O_BINARY
);
130 int32_t posix_desc
= _open_osfhandle(file_desc
, open_flags
);
131 if (posix_desc
== -1) {
132 // Close the Windows HANDLE if it can't be converted.
133 CloseHandle(reinterpret_cast<HANDLE
>(file_desc
));
134 PLUGIN_PRINTF(("LocalTempFile::GetFD _open_osfhandle failed.\n"));
135 return NACL_NO_FILE_DESC
;
137 file_desc
= posix_desc
;
139 int32_t file_desc_ok_to_close
= DUP(file_desc
);
140 if (file_desc_ok_to_close
== NACL_NO_FILE_DESC
) {
141 PLUGIN_PRINTF(("LocalTempFile::GetFD dup failed.\n"));
144 return file_desc_ok_to_close
;
147 void LocalTempFile::WriteFileDidOpen(int32_t pp_error
) {
148 PLUGIN_PRINTF(("LocalTempFile::WriteFileDidOpen (pp_error=%"
149 NACL_PRId32
")\n", pp_error
));
150 if (pp_error
== PP_ERROR_FILEEXISTS
) {
151 // Filenames clashed, retry.
153 OpenWrite(done_callback_
);
155 // Run the client's completion callback.
156 pp::Core
* core
= pp::Module::Get()->core();
157 if (pp_error
!= PP_OK
) {
158 core
->CallOnMainThread(0, done_callback_
, pp_error
);
161 // Remember the object temporary file descriptor.
162 int32_t fd
= GetFD(pp_error
, *write_io_
, kWriteable
);
164 core
->CallOnMainThread(0, done_callback_
, pp_error
);
167 // The descriptor for a writeable file needs to have quota management.
168 write_wrapper_
.reset(
169 plugin_
->wrapper_factory()->MakeFileDescQuota(fd
, O_RDWR
, identifier_
));
170 core
->CallOnMainThread(0, done_callback_
, PP_OK
);
173 void LocalTempFile::OpenRead(const pp::CompletionCallback
& cb
) {
174 PLUGIN_PRINTF(("LocalTempFile::OpenRead: %s\n", filename_
.c_str()));
176 // Open the read only file.
177 read_io_
.reset(new pp::FileIO(plugin_
));
178 pp::CompletionCallback open_read_cb
=
179 callback_factory_
.NewCallback(&LocalTempFile::ReadFileDidOpen
);
180 read_io_
->Open(*file_ref_
, PP_FILEOPENFLAG_READ
, open_read_cb
);
183 void LocalTempFile::ReadFileDidOpen(int32_t pp_error
) {
184 PLUGIN_PRINTF(("LocalTempFile::ReadFileDidOpen (pp_error=%"
185 NACL_PRId32
")\n", pp_error
));
186 // Run the client's completion callback.
187 pp::Core
* core
= pp::Module::Get()->core();
188 if (pp_error
!= PP_OK
) {
189 core
->CallOnMainThread(0, done_callback_
, pp_error
);
192 // Remember the object temporary file descriptor.
193 int32_t fd
= GetFD(pp_error
, *read_io_
, kReadOnly
);
195 core
->CallOnMainThread(0, done_callback_
, PP_ERROR_FAILED
);
198 read_wrapper_
.reset(plugin_
->wrapper_factory()->MakeFileDesc(fd
, O_RDONLY
));
199 core
->CallOnMainThread(0, done_callback_
, PP_OK
);
202 void LocalTempFile::Close(const pp::CompletionCallback
& cb
) {
203 PLUGIN_PRINTF(("LocalTempFile::Close: %s\n", filename_
.c_str()));
204 // Close the open DescWrappers and FileIOs.
205 if (write_io_
.get() != NULL
) {
208 write_wrapper_
.reset(NULL
);
209 write_io_
.reset(NULL
);
210 if (read_io_
.get() != NULL
) {
213 read_wrapper_
.reset(NULL
);
214 read_io_
.reset(NULL
);
215 // Run the client's completion callback.
216 pp::Core
* core
= pp::Module::Get()->core();
217 core
->CallOnMainThread(0, cb
, PP_OK
);
220 void LocalTempFile::Delete(const pp::CompletionCallback
& cb
) {
221 PLUGIN_PRINTF(("LocalTempFile::Delete: %s\n", filename_
.c_str()));
222 file_ref_
->Delete(cb
);
225 void LocalTempFile::Rename(const nacl::string
& new_name
,
226 const pp::CompletionCallback
& cb
) {
227 // Rename the temporary file.
228 filename_
= base_dir_
+ "/" + new_name
;
229 PLUGIN_PRINTF(("LocalTempFile::Rename %s to %s\n",
230 file_ref_
->GetName().AsString().c_str(),
232 // Remember the old ref until the rename is complete.
233 old_ref_
.reset(file_ref_
.release());
234 file_ref_
.reset(new pp::FileRef(*file_system_
, filename_
.c_str()));
235 old_ref_
->Rename(*file_ref_
, cb
);
238 void LocalTempFile::FinishRename() {
239 // Now we can release the old ref.
240 old_ref_
.reset(NULL
);
243 } // namespace plugin