Home | History | Annotate | Download | only in fake_ppapi
      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:
     20   FakeInstanceResource() : filesystem_template(NULL) {}
     21   static const char* classname() { return "FakeInstanceResource"; }
     22 
     23   FakeHtml5FsFilesystem* filesystem_template;  // Weak reference.
     24 };
     25 
     26 class FakeFileSystemResource : public FakeResource {
     27  public:
     28   FakeFileSystemResource() : filesystem(NULL), opened(false) {}
     29   ~FakeFileSystemResource() { delete filesystem; }
     30   static const char* classname() { return "FakeFileSystemResource"; }
     31 
     32   FakeHtml5FsFilesystem* filesystem;  // Owned.
     33   bool opened;
     34 };
     35 
     36 class FakeFileRefResource : public FakeResource {
     37  public:
     38   FakeFileRefResource() : filesystem(NULL) {}
     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:
     47   FakeFileIoResource() : node(NULL), open_flags(0) {}
     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);
     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 
     74 FakeHtml5FsNode::FakeHtml5FsNode(const PP_FileInfo& info) : info_(info) {}
     75 
     76 FakeHtml5FsNode::FakeHtml5FsNode(const PP_FileInfo& info,
     77                                  const std::vector<uint8_t>& contents)
     78     : info_(info), contents_(contents) {}
     79 
     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 
     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 
     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 
    113 int32_t FakeHtml5FsNode::Append(const char* buffer, int32_t bytes_to_write) {
    114   return Write(contents_.size(), buffer, bytes_to_write);
    115 }
    116 
    117 int32_t FakeHtml5FsNode::SetLength(int64_t length) {
    118   contents_.resize(length);
    119   info_.size = length;
    120   return PP_OK;
    121 }
    122 
    123 void FakeHtml5FsNode::GetInfo(PP_FileInfo* out_info) { *out_info = info_; }
    124 
    125 bool FakeHtml5FsNode::IsRegular() const {
    126   return info_.type == PP_FILETYPE_REGULAR;
    127 }
    128 
    129 bool FakeHtml5FsNode::IsDirectory() const {
    130   return info_.type == PP_FILETYPE_DIRECTORY;
    131 }
    132 
    133 FakeHtml5FsFilesystem::FakeHtml5FsFilesystem()
    134     : filesystem_type_(PP_FILESYSTEMTYPE_INVALID) {
    135   Clear();
    136 }
    137 
    138 FakeHtml5FsFilesystem::FakeHtml5FsFilesystem(PP_FileSystemType type)
    139     : filesystem_type_(type) {
    140   Clear();
    141 }
    142 
    143 FakeHtml5FsFilesystem::FakeHtml5FsFilesystem(
    144     const FakeHtml5FsFilesystem& filesystem,
    145     PP_FileSystemType type)
    146     : node_map_(filesystem.node_map_), filesystem_type_(type) {}
    147 
    148 void FakeHtml5FsFilesystem::Clear() {
    149   node_map_.clear();
    150   // Always have a root node.
    151   AddDirectory("/", NULL);
    152 }
    153 
    154 bool FakeHtml5FsFilesystem::AddEmptyFile(const Path& path,
    155                                          FakeHtml5FsNode** out_node) {
    156   return AddFile(path, std::vector<uint8_t>(), out_node);
    157 }
    158 
    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 
    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 
    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 
    222 bool FakeHtml5FsFilesystem::RemoveNode(const Path& path) {
    223   return node_map_.erase(path) >= 1;
    224 }
    225 
    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 
    233 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
    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 
    288 FakeFileIoInterface::FakeFileIoInterface(FakeCoreInterface* core_interface)
    289     : core_interface_(core_interface) {}
    290 
    291 PP_Resource FakeFileIoInterface::Create(PP_Resource) {
    292   return CREATE_RESOURCE(core_interface_->resource_manager(),
    293                          FakeFileIoResource,
    294                          new FakeFileIoResource);
    295 }
    296 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    457 FakeFileRefInterface::FakeFileRefInterface(FakeCoreInterface* core_interface,
    458                                            FakeVarInterface* var_interface)
    459     : core_interface_(core_interface), var_interface_(var_interface) {}
    460 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    657 FakeFileSystemInterface::FakeFileSystemInterface(
    658     FakeCoreInterface* core_interface)
    659     : core_interface_(core_interface) {}
    660 
    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 
    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 
    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 
    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 
    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 
    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 
    728 FakePepperInterfaceHtml5Fs::~FakePepperInterfaceHtml5Fs() {
    729   core_interface_.ReleaseResource(instance_);
    730 }
    731 
    732 nacl_io::CoreInterface* FakePepperInterfaceHtml5Fs::GetCoreInterface() {
    733   return &core_interface_;
    734 }
    735 
    736 nacl_io::FileSystemInterface*
    737 FakePepperInterfaceHtml5Fs::GetFileSystemInterface() {
    738   return &file_system_interface_;
    739 }
    740 
    741 nacl_io::FileRefInterface* FakePepperInterfaceHtml5Fs::GetFileRefInterface() {
    742   return &file_ref_interface_;
    743 }
    744 
    745 nacl_io::FileIoInterface* FakePepperInterfaceHtml5Fs::GetFileIoInterface() {
    746   return &file_io_interface_;
    747 }
    748 
    749 nacl_io::VarInterface* FakePepperInterfaceHtml5Fs::GetVarInterface() {
    750   return &var_interface_;
    751 }
    752