1// Copyright 2013 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 "content/browser/renderer_host/pepper/pepper_file_ref_host.h"
6
7#include <string>
8
9#include "content/browser/renderer_host/pepper/pepper_external_file_ref_backend.h"
10#include "content/browser/renderer_host/pepper/pepper_file_system_browser_host.h"
11#include "content/browser/renderer_host/pepper/pepper_internal_file_ref_backend.h"
12#include "ppapi/c/pp_errors.h"
13#include "ppapi/c/pp_file_info.h"
14#include "ppapi/c/pp_instance.h"
15#include "ppapi/c/pp_resource.h"
16#include "ppapi/host/dispatch_host_message.h"
17#include "ppapi/host/ppapi_host.h"
18#include "ppapi/proxy/ppapi_messages.h"
19#include "ppapi/shared_impl/file_ref_util.h"
20#include "storage/browser/fileapi/file_permission_policy.h"
21
22using ppapi::host::ResourceHost;
23
24namespace content {
25
26PepperFileRefBackend::~PepperFileRefBackend() {}
27
28PepperFileRefHost::PepperFileRefHost(BrowserPpapiHost* host,
29                                     PP_Instance instance,
30                                     PP_Resource resource,
31                                     PP_Resource file_system,
32                                     const std::string& path)
33    : ResourceHost(host->GetPpapiHost(), instance, resource),
34      host_(host),
35      fs_type_(PP_FILESYSTEMTYPE_INVALID) {
36  if (!ppapi::IsValidInternalPath(path))
37    return;
38
39  int render_process_id;
40  int unused;
41  if (!host->GetRenderFrameIDsForInstance(
42          instance, &render_process_id, &unused)) {
43    return;
44  }
45
46  ResourceHost* fs_resource_host =
47      host->GetPpapiHost()->GetResourceHost(file_system);
48  if (fs_resource_host == NULL) {
49    DLOG(ERROR) << "Couldn't find FileSystem host: " << resource
50                << " path: " << path;
51    return;
52  }
53
54  if (!fs_resource_host->IsFileSystemHost()) {
55    DLOG(ERROR) << "Filesystem PP_Resource is not PepperFileSystemBrowserHost";
56    return;
57  }
58
59  PepperFileSystemBrowserHost* file_system_host =
60      static_cast<PepperFileSystemBrowserHost*>(fs_resource_host);
61  file_system_host_ = file_system_host->AsWeakPtr();
62  fs_type_ = file_system_host->GetType();
63  if ((fs_type_ != PP_FILESYSTEMTYPE_LOCALPERSISTENT) &&
64      (fs_type_ != PP_FILESYSTEMTYPE_LOCALTEMPORARY) &&
65      (fs_type_ != PP_FILESYSTEMTYPE_EXTERNAL) &&
66      (fs_type_ != PP_FILESYSTEMTYPE_ISOLATED)) {
67    DLOG(ERROR) << "Unsupported filesystem type: " << fs_type_;
68    return;
69  }
70  if ((fs_type_ == PP_FILESYSTEMTYPE_EXTERNAL) &&
71      (!file_system_host->GetRootUrl().is_valid())) {
72    DLOG(ERROR) << "Native external filesystems are not supported by this "
73                << "constructor.";
74    return;
75  }
76
77  backend_.reset(new PepperInternalFileRefBackend(host->GetPpapiHost(),
78                                                  render_process_id,
79                                                  file_system_host->AsWeakPtr(),
80                                                  path));
81}
82
83PepperFileRefHost::PepperFileRefHost(BrowserPpapiHost* host,
84                                     PP_Instance instance,
85                                     PP_Resource resource,
86                                     const base::FilePath& external_path)
87    : ResourceHost(host->GetPpapiHost(), instance, resource),
88      host_(host),
89      fs_type_(PP_FILESYSTEMTYPE_EXTERNAL) {
90  if (!ppapi::IsValidExternalPath(external_path))
91    return;
92
93  int render_process_id;
94  int unused;
95  if (!host->GetRenderFrameIDsForInstance(
96          instance, &render_process_id, &unused)) {
97    return;
98  }
99
100  backend_.reset(new PepperExternalFileRefBackend(
101      host->GetPpapiHost(), render_process_id, external_path));
102}
103
104PepperFileRefHost::~PepperFileRefHost() {}
105
106bool PepperFileRefHost::IsFileRefHost() { return true; }
107
108PP_FileSystemType PepperFileRefHost::GetFileSystemType() const {
109  return fs_type_;
110}
111
112storage::FileSystemURL PepperFileRefHost::GetFileSystemURL() const {
113  if (backend_)
114    return backend_->GetFileSystemURL();
115  return storage::FileSystemURL();
116}
117
118base::FilePath PepperFileRefHost::GetExternalFilePath() const {
119  if (backend_)
120    return backend_->GetExternalFilePath();
121  return base::FilePath();
122}
123
124base::WeakPtr<PepperFileSystemBrowserHost>
125PepperFileRefHost::GetFileSystemHost() const {
126  return file_system_host_;
127}
128
129int32_t PepperFileRefHost::CanRead() const {
130  if (backend_)
131    return backend_->CanRead();
132  return PP_ERROR_FAILED;
133}
134
135int32_t PepperFileRefHost::CanWrite() const {
136  if (backend_)
137    return backend_->CanWrite();
138  return PP_ERROR_FAILED;
139}
140
141int32_t PepperFileRefHost::CanCreate() const {
142  if (backend_)
143    return backend_->CanCreate();
144  return PP_ERROR_FAILED;
145}
146
147int32_t PepperFileRefHost::CanReadWrite() const {
148  if (backend_)
149    return backend_->CanReadWrite();
150  return PP_ERROR_FAILED;
151}
152
153int32_t PepperFileRefHost::OnResourceMessageReceived(
154    const IPC::Message& msg,
155    ppapi::host::HostMessageContext* context) {
156  if (!backend_)
157    return PP_ERROR_FAILED;
158
159  PPAPI_BEGIN_MESSAGE_MAP(PepperFileRefHost, msg)
160    PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FileRef_MakeDirectory,
161                                      OnMakeDirectory)
162    PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FileRef_Touch, OnTouch)
163    PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_FileRef_Delete, OnDelete)
164    PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FileRef_Rename, OnRename)
165    PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_FileRef_Query, OnQuery)
166    PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(
167        PpapiHostMsg_FileRef_ReadDirectoryEntries, OnReadDirectoryEntries)
168    PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_FileRef_GetAbsolutePath,
169                                        OnGetAbsolutePath)
170  PPAPI_END_MESSAGE_MAP()
171  return PP_ERROR_FAILED;
172}
173
174int32_t PepperFileRefHost::OnMakeDirectory(
175    ppapi::host::HostMessageContext* context,
176    int32_t make_directory_flags) {
177  int32_t rv = CanCreate();
178  if (rv != PP_OK)
179    return rv;
180  return backend_->MakeDirectory(context->MakeReplyMessageContext(),
181                                 make_directory_flags);
182}
183
184int32_t PepperFileRefHost::OnTouch(ppapi::host::HostMessageContext* context,
185                                   PP_Time last_access_time,
186                                   PP_Time last_modified_time) {
187  // TODO(teravest): Change this to be kWriteFilePermissions here and in
188  // fileapi_message_filter.
189  int32_t rv = CanCreate();
190  if (rv != PP_OK)
191    return rv;
192  return backend_->Touch(
193      context->MakeReplyMessageContext(), last_access_time, last_modified_time);
194}
195
196int32_t PepperFileRefHost::OnDelete(ppapi::host::HostMessageContext* context) {
197  int32_t rv = CanWrite();
198  if (rv != PP_OK)
199    return rv;
200  return backend_->Delete(context->MakeReplyMessageContext());
201}
202
203int32_t PepperFileRefHost::OnRename(ppapi::host::HostMessageContext* context,
204                                    PP_Resource new_file_ref) {
205  int32_t rv = CanReadWrite();
206  if (rv != PP_OK)
207    return rv;
208
209  ResourceHost* resource_host =
210      host_->GetPpapiHost()->GetResourceHost(new_file_ref);
211  if (!resource_host)
212    return PP_ERROR_BADRESOURCE;
213
214  PepperFileRefHost* file_ref_host = NULL;
215  if (resource_host->IsFileRefHost())
216    file_ref_host = static_cast<PepperFileRefHost*>(resource_host);
217  if (!file_ref_host)
218    return PP_ERROR_BADRESOURCE;
219
220  rv = file_ref_host->CanCreate();
221  if (rv != PP_OK)
222    return rv;
223
224  return backend_->Rename(context->MakeReplyMessageContext(), file_ref_host);
225}
226
227int32_t PepperFileRefHost::OnQuery(ppapi::host::HostMessageContext* context) {
228  int32_t rv = CanRead();
229  if (rv != PP_OK)
230    return rv;
231  return backend_->Query(context->MakeReplyMessageContext());
232}
233
234int32_t PepperFileRefHost::OnReadDirectoryEntries(
235    ppapi::host::HostMessageContext* context) {
236  int32_t rv = CanRead();
237  if (rv != PP_OK)
238    return rv;
239  return backend_->ReadDirectoryEntries(context->MakeReplyMessageContext());
240}
241
242int32_t PepperFileRefHost::OnGetAbsolutePath(
243    ppapi::host::HostMessageContext* context) {
244  if (!host_->GetPpapiHost()->permissions().HasPermission(
245          ppapi::PERMISSION_PRIVATE))
246    return PP_ERROR_NOACCESS;
247  return backend_->GetAbsolutePath(context->MakeReplyMessageContext());
248}
249
250}  // namespace content
251