Index: chrome/browser/nacl_host/pnacl_file_host.cc |
diff --git a/chrome/browser/nacl_host/pnacl_file_host.cc b/chrome/browser/nacl_host/pnacl_file_host.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..993b4363e00f5a730055ab7c0d9455327b19db67 |
--- /dev/null |
+++ b/chrome/browser/nacl_host/pnacl_file_host.cc |
@@ -0,0 +1,186 @@ |
+// 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 "chrome/browser/nacl_host/pnacl_file_host.h" |
+ |
+#include <stdio.h> |
+ |
+#include "base/bind.h" |
+#include "base/file_path.h" |
+#include "base/file_util.h" |
+#include "base/memory/ref_counted.h" |
+#include "base/path_service.h" |
+#include "base/platform_file.h" |
+#include "chrome/common/chrome_paths.h" |
+#include "chrome/common/render_messages.h" |
+#include "chrome/browser/renderer_host/chrome_render_message_filter.h" |
+#include "content/public/browser/browser_thread.h" |
+#include "native_client/src/shared/imc/nacl_imc.h" |
+ |
+using content::BrowserThread; |
+ |
+namespace { |
+ |
+// Need the DuplicateHandle good to send the handle over to the |
+// plugin process. |
+// TODO(jvoung): share some code with nacl_process_host if possible. |
+bool SendHandleToNaClPlugin( |
+ base::ProcessHandle target_processh, |
+ nacl::Handle sourceh, |
+ bool close_source, |
+ nacl::FileDescriptor* handle_for_plugin) { |
+#if defined(OS_WIN) |
+ HANDLE channel; |
+ int flags = DUPLICATE_SAME_ACCESS; |
+ if (close_source) |
+ flags |= DUPLICATE_CLOSE_SOURCE; |
+ if (!DuplicateHandle(GetCurrentProcess(), |
+ reinterpret_cast<HANDLE>(sourceh), |
+ target_processh, |
+ &channel, |
+ 0, // Unused given DUPLICATE_SAME_ACCESS. |
+ FALSE, |
+ flags)) { |
+ LOG(ERROR) << "DuplicateHandle() failed"; |
+ return false; |
+ } |
+ *handle_for_plugin = reinterpret_cast<nacl::FileDescriptor>(channel); |
+#else |
+ nacl::FileDescriptor channel; |
+ channel.fd = sourceh; |
+ channel.auto_close = close_source; |
+ *handle_for_plugin = channel; |
+#endif |
+ return true; |
+} |
+ |
+void NotifyRendererOfError( |
+ ChromeRenderMessageFilter* chrome_render_message_filter, |
+ IPC::Message* reply_msg) { |
+ reply_msg->set_reply_error(); |
+ chrome_render_message_filter->Send(reply_msg); |
+} |
+ |
+// This only ever runs on the BrowserThread::FILE thread. |
+// TODO(jvoung): assert that. |
+void DoOpenPnaclFile( |
+ ChromeRenderMessageFilter* chrome_render_message_filter, |
+ std::string filename, |
+ IPC::Message* reply_msg) { |
+ FilePath full_filepath; |
+ |
+ // Do some validation. |
+ if (!pnacl_file_host::PnaclCanOpenFile(filename, &full_filepath)) { |
+ LOG(ERROR) << "Failed to validate Pnacl filename: " << filename; |
+ NotifyRendererOfError(chrome_render_message_filter, reply_msg); |
+ return; |
+ } |
+ |
+ base::PlatformFile file_to_open; |
+ if (!pnacl_file_host::PnaclDoOpenFile(full_filepath, &file_to_open)) { |
+ NotifyRendererOfError(chrome_render_message_filter, reply_msg); |
+ } |
+ |
+ |
+ // Send the reply! |
+ // Do any DuplicateHandle magic that is necessary first. |
+ nacl::FileDescriptor target_desc; |
+ SendHandleToNaClPlugin(chrome_render_message_filter->peer_handle(), |
+ file_to_open, |
+ true /* Close source */, |
+ &target_desc); |
+ ChromeViewHostMsg_GetReadonlyPnaclFD::WriteReplyParams( |
+ reply_msg, target_desc); |
+ chrome_render_message_filter->Send(reply_msg); |
+} |
+ |
+} // namespace |
+ |
+namespace pnacl_file_host { |
+ |
+void GetReadonlyPnaclFd( |
+ ChromeRenderMessageFilter* chrome_render_message_filter, |
+ const std::string& filename, |
+ IPC::Message* reply_msg) { |
+ fprintf(stderr, "In GetReadonlyPnaclFd: %s\n", filename.c_str()); |
+ |
+ if (!BrowserThread::PostTask( |
+ BrowserThread::FILE, FROM_HERE, |
+ base::Bind(&DoOpenPnaclFile, |
+ make_scoped_refptr(chrome_render_message_filter), |
+ filename, |
+ reply_msg))) { |
+ NotifyRendererOfError(chrome_render_message_filter, reply_msg); |
+ } |
+} |
+ |
+bool PnaclCanOpenFile(const std::string& filename, |
+ FilePath *file_to_open) { |
+ // Do some validation. |
+ // The file must use only ASCII characters. |
+ if (!IsStringASCII(filename)) { |
+ LOG(ERROR) << "not ASCII: " << filename; |
+ return false; |
+ } |
+ |
+ if (filename.find('%') != std::string::npos || |
+ filename.find('$') != std::string::npos) { |
+ LOG(ERROR) << "Has funny symbols " << filename; |
+ return false; |
+ } |
+ |
+#if defined(OS_WIN) |
+ FilePath file_to_find(ASCIIToUTF16(filename)); |
+#elif defined(OS_POSIX) |
+ FilePath file_to_find(filename); |
+#endif |
+ |
+ if (file_to_find.empty() || file_util::IsDot(file_to_find)) { |
+ LOG(ERROR) << "Empty or dot " << file_to_find.LossyDisplayName(); |
+ return false; |
+ } |
+ |
+ // Disallow peeking outside of the pnacl component directory. |
+ if (file_to_find.ReferencesParent() || file_to_find.IsAbsolute()) { |
+ LOG(ERROR) << "ReferencesParent or IsAbsolute: " |
+ << file_to_find.LossyDisplayName(); |
+ return false; |
+ } |
+ |
+ // Disallow special shell characters, just in case... |
+ |
+ FilePath pnacl_dir; |
+ if (!PathService::Get(chrome::DIR_PNACL_COMPONENT, &pnacl_dir)) { |
+ LOG(ERROR) << "No DIR_PNACL_COMPONENT"; |
+ return false; |
+ } |
+ if (pnacl_dir.empty()) { |
+ LOG(ERROR) << "pnacl_dir is empty: " << pnacl_dir.LossyDisplayName(); |
+ return false; |
+ } |
+ |
+ FilePath full_path = pnacl_dir.Append(file_to_find); |
+ *file_to_open = full_path; |
+ return true; |
+} |
+ |
+bool PnaclDoOpenFile(const FilePath& file_to_open, |
+ base::PlatformFile* out_file) { |
+ base::PlatformFileError error_code; |
+ *out_file = base::CreatePlatformFile(file_to_open, |
+ base::PLATFORM_FILE_OPEN | |
+ base::PLATFORM_FILE_READ | |
+ base::PLATFORM_FILE_SHARE_DELETE, |
+ NULL, |
+ &error_code); |
+ if (error_code != base::PLATFORM_FILE_OK) { |
+ LOG(ERROR) << "Failed to open Pnacl file \"" |
+ << file_to_open.LossyDisplayName() |
+ << "\": " << error_code; |
+ return false; |
+ } |
+ return true; |
+} |
+ |
+} // namespace pnacl_file_host |