• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2014 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 "fake_ppapi/fake_pepper_interface_html5_fs.h"
6 
7 #include <string.h>
8 
9 #include <algorithm>
10 
11 #include <ppapi/c/pp_completion_callback.h>
12 #include <ppapi/c/pp_errors.h>
13 
14 #include "gtest/gtest.h"
15 
16 namespace {
17 
18 class FakeInstanceResource : public FakeResource {
19  public:
FakeInstanceResource()20   FakeInstanceResource() : filesystem_template(NULL) {}
classname()21   static const char* classname() { return "FakeInstanceResource"; }
22 
23   FakeHtml5FsFilesystem* filesystem_template;  // Weak reference.
24 };
25 
26 class FakeFileSystemResource : public FakeResource {
27  public:
FakeFileSystemResource()28   FakeFileSystemResource() : filesystem(NULL), opened(false) {}
~FakeFileSystemResource()29   ~FakeFileSystemResource() { delete filesystem; }
classname()30   static const char* classname() { return "FakeFileSystemResource"; }
31 
32   FakeHtml5FsFilesystem* filesystem;  // Owned.
33   bool opened;
34 };
35 
36 class FakeFileRefResource : public FakeResource {
37  public:
FakeFileRefResource()38   FakeFileRefResource() : filesystem(NULL) {}
classname()39   static const char* classname() { return "FakeFileRefResource"; }
40 
41   FakeHtml5FsFilesystem* filesystem;  // Weak reference.
42   FakeHtml5FsFilesystem::Path path;
43 };
44 
45 class FakeFileIoResource : public FakeResource {
46  public:
FakeFileIoResource()47   FakeFileIoResource() : node(NULL), open_flags(0) {}
classname()48   static const char* classname() { return "FakeFileIoResource"; }
49 
50   FakeHtml5FsNode* node;  // Weak reference.
51   int32_t open_flags;
52 };
53 
54 // Helper function to call the completion callback if it is defined (an
55 // asynchronous call), or return the result directly if it isn't (a synchronous
56 // call).
57 //
58 // Use like this:
59 //   if (<some error condition>)
60 //     return RunCompletionCallback(callback, PP_ERROR_FUBAR);
61 //
62 //   /* Everything worked OK */
63 //   return RunCompletionCallback(callback, PP_OK);
RunCompletionCallback(PP_CompletionCallback * callback,int32_t result)64 int32_t RunCompletionCallback(PP_CompletionCallback* callback, int32_t result) {
65   if (callback->func) {
66     PP_RunCompletionCallback(callback, result);
67     return PP_OK_COMPLETIONPENDING;
68   }
69   return result;
70 }
71 
72 }  // namespace
73 
FakeHtml5FsNode(const PP_FileInfo & info)74 FakeHtml5FsNode::FakeHtml5FsNode(const PP_FileInfo& info) : info_(info) {}
75 
FakeHtml5FsNode(const PP_FileInfo & info,const std::vector<uint8_t> & contents)76 FakeHtml5FsNode::FakeHtml5FsNode(const PP_FileInfo& info,
77                                  const std::vector<uint8_t>& contents)
78     : info_(info), contents_(contents) {}
79 
FakeHtml5FsNode(const PP_FileInfo & info,const std::string & contents)80 FakeHtml5FsNode::FakeHtml5FsNode(const PP_FileInfo& info,
81                                  const std::string& contents)
82     : info_(info) {
83   std::copy(contents.begin(), contents.end(), std::back_inserter(contents_));
84 }
85 
Read(int64_t offset,char * buffer,int32_t bytes_to_read)86 int32_t FakeHtml5FsNode::Read(int64_t offset,
87                               char* buffer,
88                               int32_t bytes_to_read) {
89   if (offset < 0)
90     return PP_ERROR_FAILED;
91 
92   bytes_to_read =
93       std::max(0, std::min<int32_t>(bytes_to_read, contents_.size() - offset));
94   memcpy(buffer, contents_.data() + offset, bytes_to_read);
95   return bytes_to_read;
96 }
97 
Write(int64_t offset,const char * buffer,int32_t bytes_to_write)98 int32_t FakeHtml5FsNode::Write(int64_t offset,
99                                const char* buffer,
100                                int32_t bytes_to_write) {
101   if (offset < 0)
102     return PP_ERROR_FAILED;
103 
104   size_t new_size = offset + bytes_to_write;
105   if (new_size > contents_.size())
106     contents_.resize(new_size);
107 
108   memcpy(contents_.data() + offset, buffer, bytes_to_write);
109   info_.size = new_size;
110   return bytes_to_write;
111 }
112 
Append(const char * buffer,int32_t bytes_to_write)113 int32_t FakeHtml5FsNode::Append(const char* buffer, int32_t bytes_to_write) {
114   return Write(contents_.size(), buffer, bytes_to_write);
115 }
116 
SetLength(int64_t length)117 int32_t FakeHtml5FsNode::SetLength(int64_t length) {
118   contents_.resize(length);
119   info_.size = length;
120   return PP_OK;
121 }
122 
GetInfo(PP_FileInfo * out_info)123 void FakeHtml5FsNode::GetInfo(PP_FileInfo* out_info) { *out_info = info_; }
124 
IsRegular() const125 bool FakeHtml5FsNode::IsRegular() const {
126   return info_.type == PP_FILETYPE_REGULAR;
127 }
128 
IsDirectory() const129 bool FakeHtml5FsNode::IsDirectory() const {
130   return info_.type == PP_FILETYPE_DIRECTORY;
131 }
132 
FakeHtml5FsFilesystem()133 FakeHtml5FsFilesystem::FakeHtml5FsFilesystem()
134     : filesystem_type_(PP_FILESYSTEMTYPE_INVALID) {
135   Clear();
136 }
137 
FakeHtml5FsFilesystem(PP_FileSystemType type)138 FakeHtml5FsFilesystem::FakeHtml5FsFilesystem(PP_FileSystemType type)
139     : filesystem_type_(type) {
140   Clear();
141 }
142 
FakeHtml5FsFilesystem(const FakeHtml5FsFilesystem & filesystem,PP_FileSystemType type)143 FakeHtml5FsFilesystem::FakeHtml5FsFilesystem(
144     const FakeHtml5FsFilesystem& filesystem,
145     PP_FileSystemType type)
146     : node_map_(filesystem.node_map_), filesystem_type_(type) {}
147 
Clear()148 void FakeHtml5FsFilesystem::Clear() {
149   node_map_.clear();
150   // Always have a root node.
151   AddDirectory("/", NULL);
152 }
153 
AddEmptyFile(const Path & path,FakeHtml5FsNode ** out_node)154 bool FakeHtml5FsFilesystem::AddEmptyFile(const Path& path,
155                                          FakeHtml5FsNode** out_node) {
156   return AddFile(path, std::vector<uint8_t>(), out_node);
157 }
158 
AddFile(const Path & path,const std::string & contents,FakeHtml5FsNode ** out_node)159 bool FakeHtml5FsFilesystem::AddFile(const Path& path,
160                                     const std::string& contents,
161                                     FakeHtml5FsNode** out_node) {
162   std::vector<uint8_t> data;
163   std::copy(contents.begin(), contents.end(), std::back_inserter(data));
164   return AddFile(path, data, out_node);
165 }
166 
AddFile(const Path & path,const std::vector<uint8_t> & contents,FakeHtml5FsNode ** out_node)167 bool FakeHtml5FsFilesystem::AddFile(const Path& path,
168                                     const std::vector<uint8_t>& contents,
169                                     FakeHtml5FsNode** out_node) {
170   NodeMap::iterator iter = node_map_.find(path);
171   if (iter != node_map_.end()) {
172     if (out_node)
173       *out_node = NULL;
174     return false;
175   }
176 
177   PP_FileInfo info;
178   info.size = contents.size();
179   info.type = PP_FILETYPE_REGULAR;
180   info.system_type = filesystem_type_;
181   info.creation_time = 0;
182   info.last_access_time = 0;
183   info.last_modified_time = 0;
184 
185   FakeHtml5FsNode node(info, contents);
186   std::pair<NodeMap::iterator, bool> result =
187       node_map_.insert(NodeMap::value_type(path, node));
188 
189   EXPECT_EQ(true, result.second);
190   if (out_node)
191     *out_node = &result.first->second;
192   return true;
193 }
194 
AddDirectory(const Path & path,FakeHtml5FsNode ** out_node)195 bool FakeHtml5FsFilesystem::AddDirectory(const Path& path,
196                                          FakeHtml5FsNode** out_node) {
197   NodeMap::iterator iter = node_map_.find(path);
198   if (iter != node_map_.end()) {
199     if (out_node)
200       *out_node = NULL;
201     return false;
202   }
203 
204   PP_FileInfo info;
205   info.size = 0;
206   info.type = PP_FILETYPE_DIRECTORY;
207   info.system_type = filesystem_type_;
208   info.creation_time = 0;
209   info.last_access_time = 0;
210   info.last_modified_time = 0;
211 
212   FakeHtml5FsNode node(info);
213   std::pair<NodeMap::iterator, bool> result =
214       node_map_.insert(NodeMap::value_type(path, node));
215 
216   EXPECT_EQ(true, result.second);
217   if (out_node)
218     *out_node = &result.first->second;
219   return true;
220 }
221 
RemoveNode(const Path & path)222 bool FakeHtml5FsFilesystem::RemoveNode(const Path& path) {
223   return node_map_.erase(path) >= 1;
224 }
225 
GetNode(const Path & path)226 FakeHtml5FsNode* FakeHtml5FsFilesystem::GetNode(const Path& path) {
227   NodeMap::iterator iter = node_map_.find(path);
228   if (iter == node_map_.end())
229     return NULL;
230   return &iter->second;
231 }
232 
GetDirectoryEntries(const Path & path,DirectoryEntries * out_dir_entries) const233 bool FakeHtml5FsFilesystem::GetDirectoryEntries(
234     const Path& path,
235     DirectoryEntries* out_dir_entries) const {
236   out_dir_entries->clear();
237 
238   NodeMap::const_iterator iter = node_map_.find(path);
239   if (iter == node_map_.end())
240     return false;
241 
242   const FakeHtml5FsNode& dir_node = iter->second;
243   if (!dir_node.IsDirectory())
244     return false;
245 
246   for (NodeMap::const_iterator iter = node_map_.begin();
247        iter != node_map_.end();
248        ++iter) {
249     const Path& node_path = iter->first;
250     if (node_path.find(path) == std::string::npos)
251       continue;
252 
253     // A node is not a child of itself.
254     if (&iter->second == &dir_node)
255       continue;
256 
257     // Only consider children, not descendants. If we find a forward slash, then
258     // the node must be in a subdirectory.
259     if (node_path.find('/', path.size() + 1) != std::string::npos)
260       continue;
261 
262     // The directory entry names do not include the path.
263     Path entry_path = node_path;
264     size_t last_slash = node_path.rfind('/');
265     if (last_slash != std::string::npos)
266       entry_path.erase(0, last_slash + 1);
267 
268     DirectoryEntry entry;
269     entry.path = entry_path;
270     entry.node = &iter->second;
271     out_dir_entries->push_back(entry);
272   }
273 
274   return true;
275 }
276 
277 // static
GetParentPath(const Path & path)278 FakeHtml5FsFilesystem::Path FakeHtml5FsFilesystem::GetParentPath(
279     const Path& path) {
280   size_t last_slash = path.rfind('/');
281   if (last_slash == 0)
282     return "/";
283 
284   EXPECT_EQ(std::string::npos, last_slash);
285   return path.substr(0, last_slash);
286 }
287 
FakeFileIoInterface(FakeCoreInterface * core_interface)288 FakeFileIoInterface::FakeFileIoInterface(FakeCoreInterface* core_interface)
289     : core_interface_(core_interface) {}
290 
Create(PP_Resource)291 PP_Resource FakeFileIoInterface::Create(PP_Resource) {
292   return CREATE_RESOURCE(core_interface_->resource_manager(),
293                          FakeFileIoResource,
294                          new FakeFileIoResource);
295 }
296 
Open(PP_Resource file_io,PP_Resource file_ref,int32_t open_flags,PP_CompletionCallback callback)297 int32_t FakeFileIoInterface::Open(PP_Resource file_io,
298                                   PP_Resource file_ref,
299                                   int32_t open_flags,
300                                   PP_CompletionCallback callback) {
301   FakeFileIoResource* file_io_resource =
302       core_interface_->resource_manager()->Get<FakeFileIoResource>(file_io);
303   if (file_io_resource == NULL)
304     return PP_ERROR_BADRESOURCE;
305 
306   bool flag_write = !!(open_flags & PP_FILEOPENFLAG_WRITE);
307   bool flag_create = !!(open_flags & PP_FILEOPENFLAG_CREATE);
308   bool flag_truncate = !!(open_flags & PP_FILEOPENFLAG_TRUNCATE);
309   bool flag_exclusive = !!(open_flags & PP_FILEOPENFLAG_EXCLUSIVE);
310   bool flag_append = !!(open_flags & PP_FILEOPENFLAG_APPEND);
311 
312   if ((flag_append && flag_write) || (flag_truncate && !flag_write))
313     return PP_ERROR_BADARGUMENT;
314 
315   FakeFileRefResource* file_ref_resource =
316       core_interface_->resource_manager()->Get<FakeFileRefResource>(file_ref);
317   if (file_ref_resource == NULL)
318     return PP_ERROR_BADRESOURCE;
319 
320   const FakeHtml5FsFilesystem::Path& path = file_ref_resource->path;
321   FakeHtml5FsFilesystem* filesystem = file_ref_resource->filesystem;
322   FakeHtml5FsNode* node = filesystem->GetNode(path);
323   bool node_exists = node != NULL;
324 
325   if (!node_exists) {
326     if (!flag_create)
327       return RunCompletionCallback(&callback, PP_ERROR_FILENOTFOUND);
328 
329     bool result = filesystem->AddEmptyFile(path, &node);
330     EXPECT_EQ(true, result);
331   } else {
332     if (flag_create && flag_exclusive)
333       return RunCompletionCallback(&callback, PP_ERROR_FILEEXISTS);
334   }
335 
336   file_io_resource->node = node;
337   file_io_resource->open_flags = open_flags;
338 
339   if (flag_truncate)
340     return RunCompletionCallback(&callback, node->SetLength(0));
341 
342   return RunCompletionCallback(&callback, PP_OK);
343 }
344 
Query(PP_Resource file_io,PP_FileInfo * info,PP_CompletionCallback callback)345 int32_t FakeFileIoInterface::Query(PP_Resource file_io,
346                                    PP_FileInfo* info,
347                                    PP_CompletionCallback callback) {
348   FakeFileIoResource* file_io_resource =
349       core_interface_->resource_manager()->Get<FakeFileIoResource>(file_io);
350   if (file_io_resource == NULL)
351     return PP_ERROR_BADRESOURCE;
352 
353   if (!file_io_resource->node)
354     return RunCompletionCallback(&callback, PP_ERROR_FAILED);
355 
356   file_io_resource->node->GetInfo(info);
357   return RunCompletionCallback(&callback, PP_OK);
358 }
359 
Read(PP_Resource file_io,int64_t offset,char * buffer,int32_t bytes_to_read,PP_CompletionCallback callback)360 int32_t FakeFileIoInterface::Read(PP_Resource file_io,
361                                   int64_t offset,
362                                   char* buffer,
363                                   int32_t bytes_to_read,
364                                   PP_CompletionCallback callback) {
365   FakeFileIoResource* file_io_resource =
366       core_interface_->resource_manager()->Get<FakeFileIoResource>(file_io);
367   if (file_io_resource == NULL)
368     return PP_ERROR_BADRESOURCE;
369 
370   if (bytes_to_read < 0)
371     return RunCompletionCallback(&callback, PP_ERROR_FAILED);
372 
373   if ((file_io_resource->open_flags & PP_FILEOPENFLAG_READ) !=
374       PP_FILEOPENFLAG_READ) {
375     return RunCompletionCallback(&callback, PP_ERROR_NOACCESS);
376   }
377 
378   if (!file_io_resource->node)
379     return RunCompletionCallback(&callback, PP_ERROR_FAILED);
380 
381   int32_t result = file_io_resource->node->Read(offset, buffer, bytes_to_read);
382   return RunCompletionCallback(&callback, result);
383 }
384 
Write(PP_Resource file_io,int64_t offset,const char * buffer,int32_t bytes_to_write,PP_CompletionCallback callback)385 int32_t FakeFileIoInterface::Write(PP_Resource file_io,
386                                    int64_t offset,
387                                    const char* buffer,
388                                    int32_t bytes_to_write,
389                                    PP_CompletionCallback callback) {
390   FakeFileIoResource* file_io_resource =
391       core_interface_->resource_manager()->Get<FakeFileIoResource>(file_io);
392   if (file_io_resource == NULL)
393     return PP_ERROR_BADRESOURCE;
394 
395   if ((file_io_resource->open_flags & PP_FILEOPENFLAG_WRITE) !=
396       PP_FILEOPENFLAG_WRITE) {
397     return RunCompletionCallback(&callback, PP_ERROR_NOACCESS);
398   }
399 
400   if (!file_io_resource->node)
401     return RunCompletionCallback(&callback, PP_ERROR_FAILED);
402 
403   int32_t result;
404   if ((file_io_resource->open_flags & PP_FILEOPENFLAG_APPEND) ==
405       PP_FILEOPENFLAG_APPEND) {
406     result = file_io_resource->node->Append(buffer, bytes_to_write);
407   } else {
408     result = file_io_resource->node->Write(offset, buffer, bytes_to_write);
409   }
410 
411   return RunCompletionCallback(&callback, result);
412 }
413 
SetLength(PP_Resource file_io,int64_t length,PP_CompletionCallback callback)414 int32_t FakeFileIoInterface::SetLength(PP_Resource file_io,
415                                        int64_t length,
416                                        PP_CompletionCallback callback) {
417   FakeFileIoResource* file_io_resource =
418       core_interface_->resource_manager()->Get<FakeFileIoResource>(file_io);
419   if (file_io_resource == NULL)
420     return PP_ERROR_BADRESOURCE;
421 
422   if ((file_io_resource->open_flags & PP_FILEOPENFLAG_WRITE) !=
423       PP_FILEOPENFLAG_WRITE) {
424     return RunCompletionCallback(&callback, PP_ERROR_NOACCESS);
425   }
426 
427   if (!file_io_resource->node)
428     return RunCompletionCallback(&callback, PP_ERROR_FAILED);
429 
430   int32_t result = file_io_resource->node->SetLength(length);
431   return RunCompletionCallback(&callback, result);
432 }
433 
Flush(PP_Resource file_io,PP_CompletionCallback callback)434 int32_t FakeFileIoInterface::Flush(PP_Resource file_io,
435                                    PP_CompletionCallback callback) {
436   FakeFileIoResource* file_io_resource =
437       core_interface_->resource_manager()->Get<FakeFileIoResource>(file_io);
438   if (file_io_resource == NULL)
439     return PP_ERROR_BADRESOURCE;
440 
441   if (!file_io_resource->node)
442     return RunCompletionCallback(&callback, PP_ERROR_FAILED);
443 
444   return RunCompletionCallback(&callback, PP_OK);
445 }
446 
Close(PP_Resource file_io)447 void FakeFileIoInterface::Close(PP_Resource file_io) {
448   FakeFileIoResource* file_io_resource =
449       core_interface_->resource_manager()->Get<FakeFileIoResource>(file_io);
450   if (file_io_resource == NULL)
451     return;
452 
453   file_io_resource->node = NULL;
454   file_io_resource->open_flags = 0;
455 }
456 
FakeFileRefInterface(FakeCoreInterface * core_interface,FakeVarInterface * var_interface)457 FakeFileRefInterface::FakeFileRefInterface(FakeCoreInterface* core_interface,
458                                            FakeVarInterface* var_interface)
459     : core_interface_(core_interface), var_interface_(var_interface) {}
460 
Create(PP_Resource file_system,const char * path)461 PP_Resource FakeFileRefInterface::Create(PP_Resource file_system,
462                                          const char* path) {
463   FakeFileSystemResource* file_system_resource =
464       core_interface_->resource_manager()->Get<FakeFileSystemResource>(
465           file_system);
466   if (file_system_resource == NULL)
467     return PP_ERROR_BADRESOURCE;
468 
469   if (!file_system_resource->opened)
470     return PP_ERROR_FAILED;
471 
472   if (path == NULL)
473     return PP_ERROR_FAILED;
474 
475   size_t path_len = strlen(path);
476   if (path_len == 0)
477     return PP_ERROR_FAILED;
478 
479   FakeFileRefResource* file_ref_resource = new FakeFileRefResource;
480   file_ref_resource->filesystem = file_system_resource->filesystem;
481   file_ref_resource->path = path;
482 
483   // Remove a trailing slash from the path, unless it is the root path.
484   if (path_len > 1 && file_ref_resource->path[path_len - 1] == '/')
485     file_ref_resource->path.erase(path_len - 1);
486 
487   return CREATE_RESOURCE(core_interface_->resource_manager(),
488                          FakeFileRefResource,
489                          file_ref_resource);
490 }
491 
GetName(PP_Resource file_ref)492 PP_Var FakeFileRefInterface::GetName(PP_Resource file_ref) {
493   FakeFileRefResource* file_ref_resource =
494       core_interface_->resource_manager()->Get<FakeFileRefResource>(file_ref);
495   if (file_ref_resource == NULL)
496     return PP_MakeUndefined();
497 
498   return var_interface_->VarFromUtf8(file_ref_resource->path.c_str(),
499                                      file_ref_resource->path.size());
500 }
501 
MakeDirectory(PP_Resource directory_ref,PP_Bool make_parents,PP_CompletionCallback callback)502 int32_t FakeFileRefInterface::MakeDirectory(PP_Resource directory_ref,
503                                             PP_Bool make_parents,
504                                             PP_CompletionCallback callback) {
505   FakeFileRefResource* directory_ref_resource =
506       core_interface_->resource_manager()->Get<FakeFileRefResource>(
507           directory_ref);
508   if (directory_ref_resource == NULL)
509     return PP_ERROR_BADRESOURCE;
510 
511   // TODO(binji): We don't currently use make_parents in nacl_io, so
512   // I won't bother handling it yet.
513   if (make_parents == PP_TRUE)
514     return PP_ERROR_FAILED;
515 
516   FakeHtml5FsFilesystem* filesystem = directory_ref_resource->filesystem;
517   FakeHtml5FsFilesystem::Path path = directory_ref_resource->path;
518 
519   // Pepper returns PP_ERROR_NOACCESS when trying to create the root directory,
520   // not PP_ERROR_FILEEXISTS, as you might expect.
521   if (path == "/")
522     return RunCompletionCallback(&callback, PP_ERROR_NOACCESS);
523 
524   FakeHtml5FsNode* node = filesystem->GetNode(path);
525   if (node != NULL)
526     return RunCompletionCallback(&callback, PP_ERROR_FILEEXISTS);
527 
528   FakeHtml5FsFilesystem::Path parent_path = filesystem->GetParentPath(path);
529   FakeHtml5FsNode* parent_node = filesystem->GetNode(parent_path);
530   if (parent_node == NULL)
531     return RunCompletionCallback(&callback, PP_ERROR_FILENOTFOUND);
532 
533   if (!parent_node->IsDirectory())
534     return RunCompletionCallback(&callback, PP_ERROR_FAILED);
535 
536   bool result = filesystem->AddDirectory(directory_ref_resource->path, NULL);
537   EXPECT_EQ(true, result);
538   return RunCompletionCallback(&callback, PP_OK);
539 }
540 
Delete(PP_Resource file_ref,PP_CompletionCallback callback)541 int32_t FakeFileRefInterface::Delete(PP_Resource file_ref,
542                                      PP_CompletionCallback callback) {
543   FakeFileRefResource* file_ref_resource =
544       core_interface_->resource_manager()->Get<FakeFileRefResource>(file_ref);
545   if (file_ref_resource == NULL)
546     return PP_ERROR_BADRESOURCE;
547 
548   FakeHtml5FsFilesystem* filesystem = file_ref_resource->filesystem;
549   FakeHtml5FsFilesystem::Path path = file_ref_resource->path;
550   FakeHtml5FsNode* node = filesystem->GetNode(path);
551   if (node == NULL)
552     return RunCompletionCallback(&callback, PP_ERROR_FILENOTFOUND);
553 
554   filesystem->RemoveNode(path);
555   return RunCompletionCallback(&callback, PP_OK);
556 }
557 
Query(PP_Resource file_ref,PP_FileInfo * info,PP_CompletionCallback callback)558 int32_t FakeFileRefInterface::Query(PP_Resource file_ref,
559                                     PP_FileInfo* info,
560                                     PP_CompletionCallback callback) {
561   FakeFileRefResource* file_ref_resource =
562       core_interface_->resource_manager()->Get<FakeFileRefResource>(file_ref);
563   if (file_ref_resource == NULL)
564     return PP_ERROR_BADRESOURCE;
565 
566   FakeHtml5FsFilesystem* filesystem = file_ref_resource->filesystem;
567   FakeHtml5FsFilesystem::Path path = file_ref_resource->path;
568   FakeHtml5FsNode* node = filesystem->GetNode(path);
569   if (node == NULL)
570     return RunCompletionCallback(&callback, PP_ERROR_FILENOTFOUND);
571 
572   node->GetInfo(info);
573   return RunCompletionCallback(&callback, PP_OK);
574 }
575 
ReadDirectoryEntries(PP_Resource directory_ref,const PP_ArrayOutput & output,PP_CompletionCallback callback)576 int32_t FakeFileRefInterface::ReadDirectoryEntries(
577     PP_Resource directory_ref,
578     const PP_ArrayOutput& output,
579     PP_CompletionCallback callback) {
580   FakeFileRefResource* directory_ref_resource =
581       core_interface_->resource_manager()->Get<FakeFileRefResource>(
582           directory_ref);
583   if (directory_ref_resource == NULL)
584     return PP_ERROR_BADRESOURCE;
585 
586   FakeHtml5FsFilesystem* filesystem = directory_ref_resource->filesystem;
587   FakeHtml5FsFilesystem::Path path = directory_ref_resource->path;
588   FakeHtml5FsNode* node = filesystem->GetNode(path);
589   if (node == NULL)
590     return RunCompletionCallback(&callback, PP_ERROR_FILENOTFOUND);
591 
592   if (!node->IsDirectory())
593     return RunCompletionCallback(&callback, PP_ERROR_FAILED);
594 
595   FakeHtml5FsFilesystem::DirectoryEntries fake_dir_entries;
596   filesystem->GetDirectoryEntries(path, &fake_dir_entries);
597 
598   uint32_t element_count = fake_dir_entries.size();
599   uint32_t element_size = sizeof(fake_dir_entries[0]);
600   void* data_buffer =
601       (*output.GetDataBuffer)(output.user_data, element_count, element_size);
602 
603   if (data_buffer == NULL)
604     return RunCompletionCallback(&callback, PP_ERROR_FAILED);
605 
606   PP_DirectoryEntry* dir_entries = static_cast<PP_DirectoryEntry*>(data_buffer);
607   for (uint32_t i = 0; i < element_count; ++i) {
608     const FakeHtml5FsFilesystem::DirectoryEntry& fake_dir_entry =
609         fake_dir_entries[i];
610 
611     FakeFileRefResource* file_ref_resource = new FakeFileRefResource;
612     file_ref_resource->filesystem = directory_ref_resource->filesystem;
613     file_ref_resource->path = fake_dir_entry.path;
614     PP_Resource file_ref = CREATE_RESOURCE(core_interface_->resource_manager(),
615                                            FakeFileRefResource,
616                                            file_ref_resource);
617 
618     dir_entries[i].file_ref = file_ref;
619     dir_entries[i].file_type = fake_dir_entry.node->file_type();
620   }
621 
622   return RunCompletionCallback(&callback, PP_OK);
623 }
624 
Rename(PP_Resource file_ref,PP_Resource new_file_ref,PP_CompletionCallback callback)625 int32_t FakeFileRefInterface::Rename(PP_Resource file_ref,
626                                      PP_Resource new_file_ref,
627                                      PP_CompletionCallback callback) {
628   FakeFileRefResource* file_ref_resource =
629       core_interface_->resource_manager()->Get<FakeFileRefResource>(file_ref);
630   if (file_ref_resource == NULL)
631     return PP_ERROR_BADRESOURCE;
632 
633   FakeFileRefResource* new_file_ref_resource =
634       core_interface_->resource_manager()->Get<FakeFileRefResource>(
635           new_file_ref);
636   if (new_file_ref_resource == NULL)
637     return PP_ERROR_BADRESOURCE;
638 
639   FakeHtml5FsFilesystem* filesystem = file_ref_resource->filesystem;
640   FakeHtml5FsFilesystem::Path path = file_ref_resource->path;
641   FakeHtml5FsFilesystem::Path newpath = new_file_ref_resource->path;
642   FakeHtml5FsNode* node = filesystem->GetNode(path);
643   if (node == NULL)
644     return RunCompletionCallback(&callback, PP_ERROR_FILENOTFOUND);
645   // FakeFileRefResource does not support directory rename.
646   if (!node->IsRegular())
647     return RunCompletionCallback(&callback, PP_ERROR_NOTAFILE);
648 
649   // Remove the destination if it exists.
650   filesystem->RemoveNode(newpath);
651   const std::vector<uint8_t> contents = node->contents();
652   EXPECT_TRUE(filesystem->AddFile(newpath, contents, NULL));
653   EXPECT_TRUE(filesystem->RemoveNode(path));
654   return RunCompletionCallback(&callback, PP_OK);
655 }
656 
FakeFileSystemInterface(FakeCoreInterface * core_interface)657 FakeFileSystemInterface::FakeFileSystemInterface(
658     FakeCoreInterface* core_interface)
659     : core_interface_(core_interface) {}
660 
IsFileSystem(PP_Resource resource)661 PP_Bool FakeFileSystemInterface::IsFileSystem(PP_Resource resource) {
662   bool not_found_ok = true;
663   FakeFileSystemResource* file_system_resource =
664       core_interface_->resource_manager()->Get<FakeFileSystemResource>(
665           resource, not_found_ok);
666   return file_system_resource != NULL ? PP_TRUE : PP_FALSE;
667 }
668 
Create(PP_Instance instance,PP_FileSystemType filesystem_type)669 PP_Resource FakeFileSystemInterface::Create(PP_Instance instance,
670                                             PP_FileSystemType filesystem_type) {
671   FakeInstanceResource* instance_resource =
672       core_interface_->resource_manager()->Get<FakeInstanceResource>(instance);
673   if (instance_resource == NULL)
674     return PP_ERROR_BADRESOURCE;
675 
676   FakeFileSystemResource* file_system_resource = new FakeFileSystemResource;
677   file_system_resource->filesystem = new FakeHtml5FsFilesystem(
678       *instance_resource->filesystem_template, filesystem_type);
679 
680   return CREATE_RESOURCE(core_interface_->resource_manager(),
681                          FakeFileSystemResource,
682                          file_system_resource);
683 }
684 
Open(PP_Resource file_system,int64_t expected_size,PP_CompletionCallback callback)685 int32_t FakeFileSystemInterface::Open(PP_Resource file_system,
686                                       int64_t expected_size,
687                                       PP_CompletionCallback callback) {
688   FakeFileSystemResource* file_system_resource =
689       core_interface_->resource_manager()->Get<FakeFileSystemResource>(
690           file_system);
691   if (file_system_resource == NULL)
692     return PP_ERROR_BADRESOURCE;
693 
694   file_system_resource->opened = true;
695   return RunCompletionCallback(&callback, PP_OK);
696 }
697 
FakePepperInterfaceHtml5Fs()698 FakePepperInterfaceHtml5Fs::FakePepperInterfaceHtml5Fs()
699     : core_interface_(&resource_manager_),
700       var_interface_(&var_manager_),
701       file_system_interface_(&core_interface_),
702       file_ref_interface_(&core_interface_, &var_interface_),
703       file_io_interface_(&core_interface_) {
704   Init();
705 }
706 
FakePepperInterfaceHtml5Fs(const FakeHtml5FsFilesystem & filesystem)707 FakePepperInterfaceHtml5Fs::FakePepperInterfaceHtml5Fs(
708     const FakeHtml5FsFilesystem& filesystem)
709     : core_interface_(&resource_manager_),
710       var_interface_(&var_manager_),
711       filesystem_template_(filesystem),
712       file_system_interface_(&core_interface_),
713       file_ref_interface_(&core_interface_, &var_interface_),
714       file_io_interface_(&core_interface_),
715       instance_(0) {
716   Init();
717 }
718 
Init()719 void FakePepperInterfaceHtml5Fs::Init() {
720   FakeInstanceResource* instance_resource = new FakeInstanceResource;
721   instance_resource->filesystem_template = &filesystem_template_;
722 
723   instance_ = CREATE_RESOURCE(core_interface_.resource_manager(),
724                               FakeInstanceResource,
725                               instance_resource);
726 }
727 
~FakePepperInterfaceHtml5Fs()728 FakePepperInterfaceHtml5Fs::~FakePepperInterfaceHtml5Fs() {
729   core_interface_.ReleaseResource(instance_);
730 }
731 
GetCoreInterface()732 nacl_io::CoreInterface* FakePepperInterfaceHtml5Fs::GetCoreInterface() {
733   return &core_interface_;
734 }
735 
736 nacl_io::FileSystemInterface*
GetFileSystemInterface()737 FakePepperInterfaceHtml5Fs::GetFileSystemInterface() {
738   return &file_system_interface_;
739 }
740 
GetFileRefInterface()741 nacl_io::FileRefInterface* FakePepperInterfaceHtml5Fs::GetFileRefInterface() {
742   return &file_ref_interface_;
743 }
744 
GetFileIoInterface()745 nacl_io::FileIoInterface* FakePepperInterfaceHtml5Fs::GetFileIoInterface() {
746   return &file_io_interface_;
747 }
748 
GetVarInterface()749 nacl_io::VarInterface* FakePepperInterfaceHtml5Fs::GetVarInterface() {
750   return &var_interface_;
751 }
752