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.
4
5#include "ppapi/proxy/flash_file_resource.h"
6
7#include "base/files/file_path.h"
8#include "ipc/ipc_message.h"
9#include "ppapi/c/pp_errors.h"
10#include "ppapi/proxy/ppapi_messages.h"
11#include "ppapi/shared_impl/file_type_conversion.h"
12#include "ppapi/shared_impl/scoped_pp_var.h"
13#include "ppapi/shared_impl/time_conversion.h"
14#include "ppapi/shared_impl/var.h"
15#include "ppapi/thunk/enter.h"
16#include "ppapi/thunk/ppb_file_ref_api.h"
17
18namespace ppapi {
19namespace proxy {
20
21namespace {
22
23// Returns the path that a PPB_FileRef resource references as long as it is an
24// PP_FILESYSTEMTYPE_EXTERNAL path. Returns an empty string on error.
25std::string GetPathFromFileRef(PP_Resource file_ref) {
26  thunk::EnterResourceNoLock<thunk::PPB_FileRef_API> enter(file_ref, true);
27  if (enter.failed())
28    return std::string();
29  if (enter.object()->GetFileSystemType() != PP_FILESYSTEMTYPE_EXTERNAL)
30    return std::string();
31  ScopedPPVar var(ScopedPPVar::PassRef(), enter.object()->GetAbsolutePath());
32  StringVar* string_var = StringVar::FromPPVar(var.get());
33  if (!string_var)
34    return std::string();
35  return string_var->value();
36}
37
38}  // namespace
39
40FlashFileResource::FlashFileResource(Connection connection,
41                                     PP_Instance instance)
42    : PluginResource(connection, instance) {
43  SendCreate(BROWSER, PpapiHostMsg_FlashFile_Create());
44}
45
46FlashFileResource::~FlashFileResource() {
47}
48
49thunk::PPB_Flash_File_API* FlashFileResource::AsPPB_Flash_File_API() {
50  return this;
51}
52
53int32_t FlashFileResource::OpenFile(PP_Instance /*instance*/,
54                                    const char* path,
55                                    int32_t mode,
56                                    PP_FileHandle* file) {
57  return OpenFileHelper(path, PepperFilePath::DOMAIN_MODULE_LOCAL, mode, file);
58}
59
60int32_t FlashFileResource::RenameFile(PP_Instance /*instance*/,
61                                      const char* path_from,
62                                      const char* path_to) {
63  PepperFilePath pepper_from(PepperFilePath::DOMAIN_MODULE_LOCAL,
64                             base::FilePath::FromUTF8Unsafe(path_from));
65  PepperFilePath pepper_to(PepperFilePath::DOMAIN_MODULE_LOCAL,
66                           base::FilePath::FromUTF8Unsafe(path_to));
67
68  int32_t error = SyncCall<IPC::Message>(
69      BROWSER, PpapiHostMsg_FlashFile_RenameFile(pepper_from, pepper_to));
70
71  return error;
72}
73
74int32_t FlashFileResource::DeleteFileOrDir(PP_Instance /*instance*/,
75                                           const char* path,
76                                           PP_Bool recursive) {
77  PepperFilePath pepper_path(PepperFilePath::DOMAIN_MODULE_LOCAL,
78                             base::FilePath::FromUTF8Unsafe(path));
79
80  int32_t error = SyncCall<IPC::Message>(
81      BROWSER, PpapiHostMsg_FlashFile_DeleteFileOrDir(pepper_path,
82                                                      PP_ToBool(recursive)));
83
84  return error;
85}
86
87int32_t FlashFileResource::CreateDir(PP_Instance /*instance*/,
88                                     const char* path) {
89  PepperFilePath pepper_path(PepperFilePath::DOMAIN_MODULE_LOCAL,
90                             base::FilePath::FromUTF8Unsafe(path));
91
92  int32_t error = SyncCall<IPC::Message>(BROWSER,
93      PpapiHostMsg_FlashFile_CreateDir(pepper_path));
94
95  return error;
96}
97
98int32_t FlashFileResource::QueryFile(PP_Instance /*instance*/,
99                                     const char* path,
100                                     PP_FileInfo* info) {
101  return QueryFileHelper(path, PepperFilePath::DOMAIN_MODULE_LOCAL, info);
102}
103
104int32_t FlashFileResource::GetDirContents(PP_Instance /*instance*/,
105                                          const char* path,
106                                          PP_DirContents_Dev** contents) {
107  ppapi::DirContents entries;
108  PepperFilePath pepper_path(PepperFilePath::DOMAIN_MODULE_LOCAL,
109                             base::FilePath::FromUTF8Unsafe(path));
110
111  int32_t error = SyncCall<PpapiPluginMsg_FlashFile_GetDirContentsReply>(
112      BROWSER, PpapiHostMsg_FlashFile_GetDirContents(pepper_path), &entries);
113
114  if (error == PP_OK) {
115    // Copy the serialized dir entries to the output struct.
116    *contents = new PP_DirContents_Dev;
117    (*contents)->count = static_cast<int32_t>(entries.size());
118    (*contents)->entries = new PP_DirEntry_Dev[entries.size()];
119    for (size_t i = 0; i < entries.size(); i++) {
120      const ppapi::DirEntry& source = entries[i];
121      PP_DirEntry_Dev* dest = &(*contents)->entries[i];
122      std::string name = source.name.AsUTF8Unsafe();
123      char* name_copy = new char[name.size() + 1];
124      memcpy(name_copy, name.c_str(), name.size() + 1);
125      dest->name = name_copy;
126      dest->is_dir = PP_FromBool(source.is_dir);
127    }
128  }
129
130  return error;
131}
132
133void FlashFileResource::FreeDirContents(PP_Instance /*instance*/,
134                                        PP_DirContents_Dev* contents) {
135  for (int32_t i = 0; i < contents->count; ++i)
136    delete[] contents->entries[i].name;
137  delete[] contents->entries;
138  delete contents;
139}
140
141int32_t FlashFileResource::CreateTemporaryFile(PP_Instance /*instance*/,
142                                               PP_FileHandle* file) {
143  if (!file)
144    return PP_ERROR_BADARGUMENT;
145
146  IPC::Message unused;
147  ResourceMessageReplyParams reply_params;
148  int32_t error = GenericSyncCall(BROWSER,
149      PpapiHostMsg_FlashFile_CreateTemporaryFile(), &unused, &reply_params);
150  if (error != PP_OK)
151    return error;
152
153  IPC::PlatformFileForTransit transit_file;
154  if (!reply_params.TakeFileHandleAtIndex(0, &transit_file))
155    return PP_ERROR_FAILED;
156
157  *file = IPC::PlatformFileForTransitToPlatformFile(transit_file);
158  return PP_OK;
159}
160
161int32_t FlashFileResource::OpenFileRef(PP_Instance /*instance*/,
162                                       PP_Resource file_ref,
163                                       int32_t mode,
164                                       PP_FileHandle* file) {
165  return OpenFileHelper(GetPathFromFileRef(file_ref),
166                        PepperFilePath::DOMAIN_ABSOLUTE, mode, file);
167}
168
169int32_t FlashFileResource::QueryFileRef(PP_Instance /*instance*/,
170                                        PP_Resource file_ref,
171                                        PP_FileInfo* info) {
172  return QueryFileHelper(GetPathFromFileRef(file_ref),
173                         PepperFilePath::DOMAIN_ABSOLUTE, info);
174}
175
176int32_t FlashFileResource::OpenFileHelper(const std::string& path,
177                                          PepperFilePath::Domain domain_type,
178                                          int32_t mode,
179                                          PP_FileHandle* file) {
180  if (path.empty() ||
181      !ppapi::PepperFileOpenFlagsToPlatformFileFlags(mode, NULL) ||
182      !file)
183    return PP_ERROR_BADARGUMENT;
184
185  PepperFilePath pepper_path(domain_type, base::FilePath::FromUTF8Unsafe(path));
186
187  IPC::Message unused;
188  ResourceMessageReplyParams reply_params;
189  int32_t error = GenericSyncCall(BROWSER,
190      PpapiHostMsg_FlashFile_OpenFile(pepper_path, mode), &unused,
191      &reply_params);
192  if (error != PP_OK)
193    return error;
194
195  IPC::PlatformFileForTransit transit_file;
196  if (!reply_params.TakeFileHandleAtIndex(0, &transit_file))
197    return PP_ERROR_FAILED;
198
199  *file = IPC::PlatformFileForTransitToPlatformFile(transit_file);
200  return PP_OK;
201}
202
203int32_t FlashFileResource::QueryFileHelper(const std::string& path,
204                                           PepperFilePath::Domain domain_type,
205                                           PP_FileInfo* info) {
206  if (path.empty() || !info)
207    return PP_ERROR_BADARGUMENT;
208
209  base::File::Info file_info;
210  PepperFilePath pepper_path(domain_type, base::FilePath::FromUTF8Unsafe(path));
211
212  int32_t error = SyncCall<PpapiPluginMsg_FlashFile_QueryFileReply>(BROWSER,
213      PpapiHostMsg_FlashFile_QueryFile(pepper_path), &file_info);
214
215  if (error == PP_OK) {
216    info->size = file_info.size;
217    info->creation_time = TimeToPPTime(file_info.creation_time);
218    info->last_access_time = TimeToPPTime(file_info.last_accessed);
219    info->last_modified_time = TimeToPPTime(file_info.last_modified);
220    info->system_type = PP_FILESYSTEMTYPE_EXTERNAL;
221    if (file_info.is_directory)
222      info->type = PP_FILETYPE_DIRECTORY;
223    else
224      info->type = PP_FILETYPE_REGULAR;
225  }
226
227  return error;
228}
229
230}  // namespace proxy
231}  // namespace ppapi
232