| 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
|
|
|