Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / content / browser / renderer_host / pepper / pepper_internal_file_ref_backend.cc
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_internal_file_ref_backend.h"
6
7 #include <string>
8
9 #include "base/callback.h"
10 #include "base/file_util.h"
11 #include "base/files/file_util_proxy.h"
12 #include "content/browser/child_process_security_policy_impl.h"
13 #include "content/browser/fileapi/browser_file_system_helper.h"
14 #include "content/browser/renderer_host/pepper/pepper_file_system_browser_host.h"
15 #include "content/public/browser/browser_context.h"
16 #include "content/public/browser/render_process_host.h"
17 #include "content/public/browser/storage_partition.h"
18 #include "net/base/escape.h"
19 #include "ppapi/c/pp_errors.h"
20 #include "ppapi/c/pp_file_info.h"
21 #include "ppapi/c/pp_instance.h"
22 #include "ppapi/c/pp_resource.h"
23 #include "ppapi/c/ppb_file_ref.h"
24 #include "ppapi/host/dispatch_host_message.h"
25 #include "ppapi/host/ppapi_host.h"
26 #include "ppapi/proxy/ppapi_messages.h"
27 #include "ppapi/shared_impl/file_ref_create_info.h"
28 #include "ppapi/shared_impl/file_ref_util.h"
29 #include "ppapi/shared_impl/file_type_conversion.h"
30 #include "ppapi/shared_impl/scoped_pp_var.h"
31 #include "ppapi/shared_impl/time_conversion.h"
32 #include "ppapi/shared_impl/var.h"
33 #include "ppapi/thunk/enter.h"
34 #include "ppapi/thunk/ppb_file_ref_api.h"
35 #include "ppapi/thunk/ppb_file_system_api.h"
36 #include "webkit/browser/fileapi/file_system_operation.h"
37 #include "webkit/browser/fileapi/file_system_operation_runner.h"
38 #include "webkit/browser/fileapi/file_system_url.h"
39 #include "webkit/common/fileapi/file_system_util.h"
40
41 using ppapi::host::PpapiHost;
42 using ppapi::host::ResourceHost;
43
44 namespace content {
45
46 PepperInternalFileRefBackend::PepperInternalFileRefBackend(
47     PpapiHost* host,
48     int render_process_id,
49     base::WeakPtr<PepperFileSystemBrowserHost> fs_host,
50     const std::string& path)
51     : host_(host),
52       render_process_id_(render_process_id),
53       fs_host_(fs_host),
54       fs_type_(fs_host->GetType()),
55       path_(path),
56       weak_factory_(this) {
57   ppapi::NormalizeInternalPath(&path_);
58 }
59
60 PepperInternalFileRefBackend::~PepperInternalFileRefBackend() {}
61
62 fileapi::FileSystemURL PepperInternalFileRefBackend::GetFileSystemURL() const {
63   if (!fs_url_.is_valid() && fs_host_.get() && fs_host_->IsOpened()) {
64     GURL fs_path =
65         fs_host_->GetRootUrl().Resolve(net::EscapePath(path_.substr(1)));
66     scoped_refptr<fileapi::FileSystemContext> fs_context =
67         GetFileSystemContext();
68     if (fs_context.get())
69       fs_url_ = fs_context->CrackURL(fs_path);
70   }
71   return fs_url_;
72 }
73
74 base::FilePath PepperInternalFileRefBackend::GetExternalFilePath() const {
75   return base::FilePath();
76 }
77
78 scoped_refptr<fileapi::FileSystemContext>
79 PepperInternalFileRefBackend::GetFileSystemContext() const {
80   if (!fs_host_.get())
81     return NULL;
82   return fs_host_->GetFileSystemContext();
83 }
84
85 void PepperInternalFileRefBackend::DidFinish(
86     ppapi::host::ReplyMessageContext context,
87     const IPC::Message& msg,
88     base::File::Error error) {
89   context.params.set_result(ppapi::FileErrorToPepperError(error));
90   host_->SendReply(context, msg);
91 }
92
93 int32_t PepperInternalFileRefBackend::MakeDirectory(
94     ppapi::host::ReplyMessageContext reply_context,
95     int32_t make_directory_flags) {
96   if (!GetFileSystemURL().is_valid())
97     return PP_ERROR_FAILED;
98
99   GetFileSystemContext()->operation_runner()->CreateDirectory(
100       GetFileSystemURL(),
101       !!(make_directory_flags & PP_MAKEDIRECTORYFLAG_EXCLUSIVE),
102       !!(make_directory_flags & PP_MAKEDIRECTORYFLAG_WITH_ANCESTORS),
103       base::Bind(&PepperInternalFileRefBackend::DidFinish,
104                  weak_factory_.GetWeakPtr(),
105                  reply_context,
106                  PpapiPluginMsg_FileRef_MakeDirectoryReply()));
107   return PP_OK_COMPLETIONPENDING;
108 }
109
110 int32_t PepperInternalFileRefBackend::Touch(
111     ppapi::host::ReplyMessageContext reply_context,
112     PP_Time last_access_time,
113     PP_Time last_modified_time) {
114   if (!GetFileSystemURL().is_valid())
115     return PP_ERROR_FAILED;
116
117   GetFileSystemContext()->operation_runner()->TouchFile(
118       GetFileSystemURL(),
119       ppapi::PPTimeToTime(last_access_time),
120       ppapi::PPTimeToTime(last_modified_time),
121       base::Bind(&PepperInternalFileRefBackend::DidFinish,
122                  weak_factory_.GetWeakPtr(),
123                  reply_context,
124                  PpapiPluginMsg_FileRef_TouchReply()));
125   return PP_OK_COMPLETIONPENDING;
126 }
127
128 int32_t PepperInternalFileRefBackend::Delete(
129     ppapi::host::ReplyMessageContext reply_context) {
130   if (!GetFileSystemURL().is_valid())
131     return PP_ERROR_FAILED;
132
133   GetFileSystemContext()->operation_runner()->Remove(
134       GetFileSystemURL(),
135       false,
136       base::Bind(&PepperInternalFileRefBackend::DidFinish,
137                  weak_factory_.GetWeakPtr(),
138                  reply_context,
139                  PpapiPluginMsg_FileRef_DeleteReply()));
140   return PP_OK_COMPLETIONPENDING;
141 }
142
143 int32_t PepperInternalFileRefBackend::Rename(
144     ppapi::host::ReplyMessageContext reply_context,
145     PepperFileRefHost* new_file_ref) {
146   if (!GetFileSystemURL().is_valid())
147     return PP_ERROR_FAILED;
148
149   fileapi::FileSystemURL new_url = new_file_ref->GetFileSystemURL();
150   if (!new_url.is_valid())
151     return PP_ERROR_FAILED;
152   if (!new_url.IsInSameFileSystem(GetFileSystemURL()))
153     return PP_ERROR_FAILED;
154
155   GetFileSystemContext()->operation_runner()->Move(
156       GetFileSystemURL(),
157       new_url,
158       fileapi::FileSystemOperation::OPTION_NONE,
159       base::Bind(&PepperInternalFileRefBackend::DidFinish,
160                  weak_factory_.GetWeakPtr(),
161                  reply_context,
162                  PpapiPluginMsg_FileRef_RenameReply()));
163   return PP_OK_COMPLETIONPENDING;
164 }
165
166 int32_t PepperInternalFileRefBackend::Query(
167     ppapi::host::ReplyMessageContext reply_context) {
168   if (!GetFileSystemURL().is_valid())
169     return PP_ERROR_FAILED;
170
171   GetFileSystemContext()->operation_runner()->GetMetadata(
172       GetFileSystemURL(),
173       base::Bind(&PepperInternalFileRefBackend::GetMetadataComplete,
174                  weak_factory_.GetWeakPtr(),
175                  reply_context));
176   return PP_OK_COMPLETIONPENDING;
177 }
178
179 void PepperInternalFileRefBackend::GetMetadataComplete(
180     ppapi::host::ReplyMessageContext reply_context,
181     base::File::Error error,
182     const base::File::Info& file_info) {
183   reply_context.params.set_result(ppapi::FileErrorToPepperError(error));
184
185   PP_FileInfo pp_file_info;
186   if (error == base::File::FILE_OK)
187     ppapi::FileInfoToPepperFileInfo(file_info, fs_type_, &pp_file_info);
188   else
189     memset(&pp_file_info, 0, sizeof(pp_file_info));
190
191   host_->SendReply(reply_context,
192                    PpapiPluginMsg_FileRef_QueryReply(pp_file_info));
193 }
194
195 int32_t PepperInternalFileRefBackend::ReadDirectoryEntries(
196     ppapi::host::ReplyMessageContext reply_context) {
197   if (!GetFileSystemURL().is_valid())
198     return PP_ERROR_FAILED;
199
200   fileapi::FileSystemOperation::FileEntryList* accumulated_file_list =
201       new fileapi::FileSystemOperation::FileEntryList;
202   GetFileSystemContext()->operation_runner()->ReadDirectory(
203       GetFileSystemURL(),
204       base::Bind(&PepperInternalFileRefBackend::ReadDirectoryComplete,
205                  weak_factory_.GetWeakPtr(),
206                  reply_context,
207                  base::Owned(accumulated_file_list)));
208   return PP_OK_COMPLETIONPENDING;
209 }
210
211 void PepperInternalFileRefBackend::ReadDirectoryComplete(
212     ppapi::host::ReplyMessageContext context,
213     fileapi::FileSystemOperation::FileEntryList* accumulated_file_list,
214     base::File::Error error,
215     const fileapi::FileSystemOperation::FileEntryList& file_list,
216     bool has_more) {
217   accumulated_file_list->insert(
218       accumulated_file_list->end(), file_list.begin(), file_list.end());
219   if (has_more)
220     return;
221
222   context.params.set_result(ppapi::FileErrorToPepperError(error));
223
224   std::vector<ppapi::FileRefCreateInfo> infos;
225   std::vector<PP_FileType> file_types;
226   if (error == base::File::FILE_OK && fs_host_.get()) {
227     std::string dir_path = path_;
228     if (dir_path.empty() || dir_path[dir_path.size() - 1] != '/')
229       dir_path += '/';
230
231     for (fileapi::FileSystemOperation::FileEntryList::const_iterator it =
232              accumulated_file_list->begin();
233          it != accumulated_file_list->end();
234          ++it) {
235       if (it->is_directory)
236         file_types.push_back(PP_FILETYPE_DIRECTORY);
237       else
238         file_types.push_back(PP_FILETYPE_REGULAR);
239
240       ppapi::FileRefCreateInfo info;
241       info.file_system_type = fs_type_;
242       info.file_system_plugin_resource = fs_host_->pp_resource();
243       std::string path =
244           dir_path + fileapi::FilePathToString(base::FilePath(it->name));
245       info.internal_path = path;
246       info.display_name = ppapi::GetNameForInternalFilePath(path);
247       infos.push_back(info);
248     }
249   }
250
251   host_->SendReply(
252       context,
253       PpapiPluginMsg_FileRef_ReadDirectoryEntriesReply(infos, file_types));
254 }
255
256 int32_t PepperInternalFileRefBackend::GetAbsolutePath(
257     ppapi::host::ReplyMessageContext reply_context) {
258   host_->SendReply(reply_context,
259                    PpapiPluginMsg_FileRef_GetAbsolutePathReply(path_));
260   return PP_OK_COMPLETIONPENDING;
261 }
262
263 int32_t PepperInternalFileRefBackend::CanRead() const {
264   fileapi::FileSystemURL url = GetFileSystemURL();
265   if (!FileSystemURLIsValid(GetFileSystemContext().get(), url))
266     return PP_ERROR_FAILED;
267   if (!ChildProcessSecurityPolicyImpl::GetInstance()->CanReadFileSystemFile(
268           render_process_id_, url)) {
269     return PP_ERROR_NOACCESS;
270   }
271   return PP_OK;
272 }
273
274 int32_t PepperInternalFileRefBackend::CanWrite() const {
275   fileapi::FileSystemURL url = GetFileSystemURL();
276   if (!FileSystemURLIsValid(GetFileSystemContext().get(), url))
277     return PP_ERROR_FAILED;
278   if (!ChildProcessSecurityPolicyImpl::GetInstance()->CanWriteFileSystemFile(
279           render_process_id_, url)) {
280     return PP_ERROR_NOACCESS;
281   }
282   return PP_OK;
283 }
284
285 int32_t PepperInternalFileRefBackend::CanCreate() const {
286   fileapi::FileSystemURL url = GetFileSystemURL();
287   if (!FileSystemURLIsValid(GetFileSystemContext().get(), url))
288     return PP_ERROR_FAILED;
289   if (!ChildProcessSecurityPolicyImpl::GetInstance()->CanCreateFileSystemFile(
290           render_process_id_, url)) {
291     return PP_ERROR_NOACCESS;
292   }
293   return PP_OK;
294 }
295
296 int32_t PepperInternalFileRefBackend::CanReadWrite() const {
297   fileapi::FileSystemURL url = GetFileSystemURL();
298   if (!FileSystemURLIsValid(GetFileSystemContext().get(), url))
299     return PP_ERROR_FAILED;
300   ChildProcessSecurityPolicyImpl* policy =
301       ChildProcessSecurityPolicyImpl::GetInstance();
302   if (!policy->CanReadFileSystemFile(render_process_id_, url) ||
303       !policy->CanWriteFileSystemFile(render_process_id_, url)) {
304     return PP_ERROR_NOACCESS;
305   }
306   return PP_OK;
307 }
308
309 }  // namespace content