root/native_client_sdk/src/tests/nacl_io_test/fake_ppapi/fake_pepper_interface_html5_fs.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. classname
  2. opened
  3. classname
  4. classname
  5. open_flags
  6. classname
  7. RunCompletionCallback
  8. contents_
  9. Read
  10. Write
  11. Append
  12. SetLength
  13. GetInfo
  14. IsRegular
  15. IsDirectory
  16. filesystem_type_
  17. Clear
  18. AddEmptyFile
  19. AddFile
  20. AddFile
  21. AddDirectory
  22. RemoveNode
  23. GetNode
  24. GetDirectoryEntries
  25. GetParentPath
  26. Create
  27. Open
  28. Query
  29. Read
  30. Write
  31. SetLength
  32. Flush
  33. Close
  34. var_interface_
  35. Create
  36. GetName
  37. MakeDirectory
  38. Delete
  39. Query
  40. ReadDirectoryEntries
  41. Rename
  42. Create
  43. Open
  44. file_io_interface_
  45. instance_
  46. Init
  47. GetCoreInterface
  48. GetFileSystemInterface
  49. GetFileRefInterface
  50. GetFileIoInterface
  51. GetVarInterface

// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "fake_ppapi/fake_pepper_interface_html5_fs.h"

#include <string.h>

#include <algorithm>

#include <ppapi/c/pp_completion_callback.h>
#include <ppapi/c/pp_errors.h>

#include "gtest/gtest.h"

namespace {

class FakeInstanceResource : public FakeResource {
 public:
  FakeInstanceResource() : filesystem_template(NULL) {}
  static const char* classname() { return "FakeInstanceResource"; }

  FakeHtml5FsFilesystem* filesystem_template;  // Weak reference.
};

class FakeFileSystemResource : public FakeResource {
 public:
  FakeFileSystemResource() : filesystem(NULL), opened(false) {}
  ~FakeFileSystemResource() { delete filesystem; }
  static const char* classname() { return "FakeFileSystemResource"; }

  FakeHtml5FsFilesystem* filesystem;  // Owned.
  bool opened;
};

class FakeFileRefResource : public FakeResource {
 public:
  FakeFileRefResource() : filesystem(NULL) {}
  static const char* classname() { return "FakeFileRefResource"; }

  FakeHtml5FsFilesystem* filesystem;  // Weak reference.
  FakeHtml5FsFilesystem::Path path;
};

class FakeFileIoResource : public FakeResource {
 public:
  FakeFileIoResource() : node(NULL), open_flags(0) {}
  static const char* classname() { return "FakeFileIoResource"; }

  FakeHtml5FsNode* node;  // Weak reference.
  int32_t open_flags;
};

// Helper function to call the completion callback if it is defined (an
// asynchronous call), or return the result directly if it isn't (a synchronous
// call).
//
// Use like this:
//   if (<some error condition>)
//     return RunCompletionCallback(callback, PP_ERROR_FUBAR);
//
//   /* Everything worked OK */
//   return RunCompletionCallback(callback, PP_OK);
int32_t RunCompletionCallback(PP_CompletionCallback* callback, int32_t result) {
  if (callback->func) {
    PP_RunCompletionCallback(callback, result);
    return PP_OK_COMPLETIONPENDING;
  }
  return result;
}

}  // namespace

FakeHtml5FsNode::FakeHtml5FsNode(const PP_FileInfo& info) : info_(info) {}

FakeHtml5FsNode::FakeHtml5FsNode(const PP_FileInfo& info,
                                 const std::vector<uint8_t>& contents)
    : info_(info), contents_(contents) {}

FakeHtml5FsNode::FakeHtml5FsNode(const PP_FileInfo& info,
                                 const std::string& contents)
    : info_(info) {
  std::copy(contents.begin(), contents.end(), std::back_inserter(contents_));
}

int32_t FakeHtml5FsNode::Read(int64_t offset,
                              char* buffer,
                              int32_t bytes_to_read) {
  if (offset < 0)
    return PP_ERROR_FAILED;

  bytes_to_read =
      std::max(0, std::min<int32_t>(bytes_to_read, contents_.size() - offset));
  memcpy(buffer, contents_.data() + offset, bytes_to_read);
  return bytes_to_read;
}

int32_t FakeHtml5FsNode::Write(int64_t offset,
                               const char* buffer,
                               int32_t bytes_to_write) {
  if (offset < 0)
    return PP_ERROR_FAILED;

  size_t new_size = offset + bytes_to_write;
  if (new_size > contents_.size())
    contents_.resize(new_size);

  memcpy(contents_.data() + offset, buffer, bytes_to_write);
  info_.size = new_size;
  return bytes_to_write;
}

int32_t FakeHtml5FsNode::Append(const char* buffer, int32_t bytes_to_write) {
  return Write(contents_.size(), buffer, bytes_to_write);
}

int32_t FakeHtml5FsNode::SetLength(int64_t length) {
  contents_.resize(length);
  info_.size = length;
  return PP_OK;
}

void FakeHtml5FsNode::GetInfo(PP_FileInfo* out_info) { *out_info = info_; }

bool FakeHtml5FsNode::IsRegular() const {
  return info_.type == PP_FILETYPE_REGULAR;
}

bool FakeHtml5FsNode::IsDirectory() const {
  return info_.type == PP_FILETYPE_DIRECTORY;
}

FakeHtml5FsFilesystem::FakeHtml5FsFilesystem()
    : filesystem_type_(PP_FILESYSTEMTYPE_INVALID) {
  Clear();
}

FakeHtml5FsFilesystem::FakeHtml5FsFilesystem(PP_FileSystemType type)
    : filesystem_type_(type) {
  Clear();
}

FakeHtml5FsFilesystem::FakeHtml5FsFilesystem(
    const FakeHtml5FsFilesystem& filesystem,
    PP_FileSystemType type)
    : node_map_(filesystem.node_map_), filesystem_type_(type) {}

void FakeHtml5FsFilesystem::Clear() {
  node_map_.clear();
  // Always have a root node.
  AddDirectory("/", NULL);
}

bool FakeHtml5FsFilesystem::AddEmptyFile(const Path& path,
                                         FakeHtml5FsNode** out_node) {
  return AddFile(path, std::vector<uint8_t>(), out_node);
}

bool FakeHtml5FsFilesystem::AddFile(const Path& path,
                                    const std::string& contents,
                                    FakeHtml5FsNode** out_node) {
  std::vector<uint8_t> data;
  std::copy(contents.begin(), contents.end(), std::back_inserter(data));
  return AddFile(path, data, out_node);
}

bool FakeHtml5FsFilesystem::AddFile(const Path& path,
                                    const std::vector<uint8_t>& contents,
                                    FakeHtml5FsNode** out_node) {
  NodeMap::iterator iter = node_map_.find(path);
  if (iter != node_map_.end()) {
    if (out_node)
      *out_node = NULL;
    return false;
  }

  PP_FileInfo info;
  info.size = contents.size();
  info.type = PP_FILETYPE_REGULAR;
  info.system_type = filesystem_type_;
  info.creation_time = 0;
  info.last_access_time = 0;
  info.last_modified_time = 0;

  FakeHtml5FsNode node(info, contents);
  std::pair<NodeMap::iterator, bool> result =
      node_map_.insert(NodeMap::value_type(path, node));

  EXPECT_EQ(true, result.second);
  if (out_node)
    *out_node = &result.first->second;
  return true;
}

bool FakeHtml5FsFilesystem::AddDirectory(const Path& path,
                                         FakeHtml5FsNode** out_node) {
  NodeMap::iterator iter = node_map_.find(path);
  if (iter != node_map_.end()) {
    if (out_node)
      *out_node = NULL;
    return false;
  }

  PP_FileInfo info;
  info.size = 0;
  info.type = PP_FILETYPE_DIRECTORY;
  info.system_type = filesystem_type_;
  info.creation_time = 0;
  info.last_access_time = 0;
  info.last_modified_time = 0;

  FakeHtml5FsNode node(info);
  std::pair<NodeMap::iterator, bool> result =
      node_map_.insert(NodeMap::value_type(path, node));

  EXPECT_EQ(true, result.second);
  if (out_node)
    *out_node = &result.first->second;
  return true;
}

bool FakeHtml5FsFilesystem::RemoveNode(const Path& path) {
  return node_map_.erase(path) >= 1;
}

FakeHtml5FsNode* FakeHtml5FsFilesystem::GetNode(const Path& path) {
  NodeMap::iterator iter = node_map_.find(path);
  if (iter == node_map_.end())
    return NULL;
  return &iter->second;
}

bool FakeHtml5FsFilesystem::GetDirectoryEntries(
    const Path& path,
    DirectoryEntries* out_dir_entries) const {
  out_dir_entries->clear();

  NodeMap::const_iterator iter = node_map_.find(path);
  if (iter == node_map_.end())
    return false;

  const FakeHtml5FsNode& dir_node = iter->second;
  if (!dir_node.IsDirectory())
    return false;

  for (NodeMap::const_iterator iter = node_map_.begin();
       iter != node_map_.end();
       ++iter) {
    const Path& node_path = iter->first;
    if (node_path.find(path) == std::string::npos)
      continue;

    // A node is not a child of itself.
    if (&iter->second == &dir_node)
      continue;

    // Only consider children, not descendants. If we find a forward slash, then
    // the node must be in a subdirectory.
    if (node_path.find('/', path.size() + 1) != std::string::npos)
      continue;

    // The directory entry names do not include the path.
    Path entry_path = node_path;
    size_t last_slash = node_path.rfind('/');
    if (last_slash != std::string::npos)
      entry_path.erase(0, last_slash + 1);

    DirectoryEntry entry;
    entry.path = entry_path;
    entry.node = &iter->second;
    out_dir_entries->push_back(entry);
  }

  return true;
}

// static
FakeHtml5FsFilesystem::Path FakeHtml5FsFilesystem::GetParentPath(
    const Path& path) {
  size_t last_slash = path.rfind('/');
  if (last_slash == 0)
    return "/";

  EXPECT_EQ(std::string::npos, last_slash);
  return path.substr(0, last_slash);
}

FakeFileIoInterface::FakeFileIoInterface(FakeCoreInterface* core_interface)
    : core_interface_(core_interface) {}

PP_Resource FakeFileIoInterface::Create(PP_Resource) {
  return CREATE_RESOURCE(core_interface_->resource_manager(),
                         FakeFileIoResource,
                         new FakeFileIoResource);
}

int32_t FakeFileIoInterface::Open(PP_Resource file_io,
                                  PP_Resource file_ref,
                                  int32_t open_flags,
                                  PP_CompletionCallback callback) {
  FakeFileIoResource* file_io_resource =
      core_interface_->resource_manager()->Get<FakeFileIoResource>(file_io);
  if (file_io_resource == NULL)
    return PP_ERROR_BADRESOURCE;

  bool flag_write = !!(open_flags & PP_FILEOPENFLAG_WRITE);
  bool flag_create = !!(open_flags & PP_FILEOPENFLAG_CREATE);
  bool flag_truncate = !!(open_flags & PP_FILEOPENFLAG_TRUNCATE);
  bool flag_exclusive = !!(open_flags & PP_FILEOPENFLAG_EXCLUSIVE);
  bool flag_append = !!(open_flags & PP_FILEOPENFLAG_APPEND);

  if ((flag_append && flag_write) || (flag_truncate && !flag_write))
    return PP_ERROR_BADARGUMENT;

  FakeFileRefResource* file_ref_resource =
      core_interface_->resource_manager()->Get<FakeFileRefResource>(file_ref);
  if (file_ref_resource == NULL)
    return PP_ERROR_BADRESOURCE;

  const FakeHtml5FsFilesystem::Path& path = file_ref_resource->path;
  FakeHtml5FsFilesystem* filesystem = file_ref_resource->filesystem;
  FakeHtml5FsNode* node = filesystem->GetNode(path);
  bool node_exists = node != NULL;

  if (!node_exists) {
    if (!flag_create)
      return RunCompletionCallback(&callback, PP_ERROR_FILENOTFOUND);

    bool result = filesystem->AddEmptyFile(path, &node);
    EXPECT_EQ(true, result);
  } else {
    if (flag_create && flag_exclusive)
      return RunCompletionCallback(&callback, PP_ERROR_FILEEXISTS);
  }

  file_io_resource->node = node;
  file_io_resource->open_flags = open_flags;

  if (flag_truncate)
    return RunCompletionCallback(&callback, node->SetLength(0));

  return RunCompletionCallback(&callback, PP_OK);
}

int32_t FakeFileIoInterface::Query(PP_Resource file_io,
                                   PP_FileInfo* info,
                                   PP_CompletionCallback callback) {
  FakeFileIoResource* file_io_resource =
      core_interface_->resource_manager()->Get<FakeFileIoResource>(file_io);
  if (file_io_resource == NULL)
    return PP_ERROR_BADRESOURCE;

  if (!file_io_resource->node)
    return RunCompletionCallback(&callback, PP_ERROR_FAILED);

  file_io_resource->node->GetInfo(info);
  return RunCompletionCallback(&callback, PP_OK);
}

int32_t FakeFileIoInterface::Read(PP_Resource file_io,
                                  int64_t offset,
                                  char* buffer,
                                  int32_t bytes_to_read,
                                  PP_CompletionCallback callback) {
  FakeFileIoResource* file_io_resource =
      core_interface_->resource_manager()->Get<FakeFileIoResource>(file_io);
  if (file_io_resource == NULL)
    return PP_ERROR_BADRESOURCE;

  if (bytes_to_read < 0)
    return RunCompletionCallback(&callback, PP_ERROR_FAILED);

  if ((file_io_resource->open_flags & PP_FILEOPENFLAG_READ) !=
      PP_FILEOPENFLAG_READ) {
    return RunCompletionCallback(&callback, PP_ERROR_NOACCESS);
  }

  if (!file_io_resource->node)
    return RunCompletionCallback(&callback, PP_ERROR_FAILED);

  int32_t result = file_io_resource->node->Read(offset, buffer, bytes_to_read);
  return RunCompletionCallback(&callback, result);
}

int32_t FakeFileIoInterface::Write(PP_Resource file_io,
                                   int64_t offset,
                                   const char* buffer,
                                   int32_t bytes_to_write,
                                   PP_CompletionCallback callback) {
  FakeFileIoResource* file_io_resource =
      core_interface_->resource_manager()->Get<FakeFileIoResource>(file_io);
  if (file_io_resource == NULL)
    return PP_ERROR_BADRESOURCE;

  if ((file_io_resource->open_flags & PP_FILEOPENFLAG_WRITE) !=
      PP_FILEOPENFLAG_WRITE) {
    return RunCompletionCallback(&callback, PP_ERROR_NOACCESS);
  }

  if (!file_io_resource->node)
    return RunCompletionCallback(&callback, PP_ERROR_FAILED);

  int32_t result;
  if ((file_io_resource->open_flags & PP_FILEOPENFLAG_APPEND) ==
      PP_FILEOPENFLAG_APPEND) {
    result = file_io_resource->node->Append(buffer, bytes_to_write);
  } else {
    result = file_io_resource->node->Write(offset, buffer, bytes_to_write);
  }

  return RunCompletionCallback(&callback, result);
}

int32_t FakeFileIoInterface::SetLength(PP_Resource file_io,
                                       int64_t length,
                                       PP_CompletionCallback callback) {
  FakeFileIoResource* file_io_resource =
      core_interface_->resource_manager()->Get<FakeFileIoResource>(file_io);
  if (file_io_resource == NULL)
    return PP_ERROR_BADRESOURCE;

  if ((file_io_resource->open_flags & PP_FILEOPENFLAG_WRITE) !=
      PP_FILEOPENFLAG_WRITE) {
    return RunCompletionCallback(&callback, PP_ERROR_NOACCESS);
  }

  if (!file_io_resource->node)
    return RunCompletionCallback(&callback, PP_ERROR_FAILED);

  int32_t result = file_io_resource->node->SetLength(length);
  return RunCompletionCallback(&callback, result);
}

int32_t FakeFileIoInterface::Flush(PP_Resource file_io,
                                   PP_CompletionCallback callback) {
  FakeFileIoResource* file_io_resource =
      core_interface_->resource_manager()->Get<FakeFileIoResource>(file_io);
  if (file_io_resource == NULL)
    return PP_ERROR_BADRESOURCE;

  if (!file_io_resource->node)
    return RunCompletionCallback(&callback, PP_ERROR_FAILED);

  return RunCompletionCallback(&callback, PP_OK);
}

void FakeFileIoInterface::Close(PP_Resource file_io) {
  FakeFileIoResource* file_io_resource =
      core_interface_->resource_manager()->Get<FakeFileIoResource>(file_io);
  if (file_io_resource == NULL)
    return;

  file_io_resource->node = NULL;
  file_io_resource->open_flags = 0;
}

FakeFileRefInterface::FakeFileRefInterface(FakeCoreInterface* core_interface,
                                           FakeVarInterface* var_interface)
    : core_interface_(core_interface), var_interface_(var_interface) {}

PP_Resource FakeFileRefInterface::Create(PP_Resource file_system,
                                         const char* path) {
  FakeFileSystemResource* file_system_resource =
      core_interface_->resource_manager()->Get<FakeFileSystemResource>(
          file_system);
  if (file_system_resource == NULL)
    return PP_ERROR_BADRESOURCE;

  if (!file_system_resource->opened)
    return PP_ERROR_FAILED;

  if (path == NULL)
    return PP_ERROR_FAILED;

  size_t path_len = strlen(path);
  if (path_len == 0)
    return PP_ERROR_FAILED;

  FakeFileRefResource* file_ref_resource = new FakeFileRefResource;
  file_ref_resource->filesystem = file_system_resource->filesystem;
  file_ref_resource->path = path;

  // Remove a trailing slash from the path, unless it is the root path.
  if (path_len > 1 && file_ref_resource->path[path_len - 1] == '/')
    file_ref_resource->path.erase(path_len - 1);

  return CREATE_RESOURCE(core_interface_->resource_manager(),
                         FakeFileRefResource,
                         file_ref_resource);
}

PP_Var FakeFileRefInterface::GetName(PP_Resource file_ref) {
  FakeFileRefResource* file_ref_resource =
      core_interface_->resource_manager()->Get<FakeFileRefResource>(file_ref);
  if (file_ref_resource == NULL)
    return PP_MakeUndefined();

  return var_interface_->VarFromUtf8(file_ref_resource->path.c_str(),
                                     file_ref_resource->path.size());
}

int32_t FakeFileRefInterface::MakeDirectory(PP_Resource directory_ref,
                                            PP_Bool make_parents,
                                            PP_CompletionCallback callback) {
  FakeFileRefResource* directory_ref_resource =
      core_interface_->resource_manager()->Get<FakeFileRefResource>(
          directory_ref);
  if (directory_ref_resource == NULL)
    return PP_ERROR_BADRESOURCE;

  // TODO(binji): We don't currently use make_parents in nacl_io, so
  // I won't bother handling it yet.
  if (make_parents == PP_TRUE)
    return PP_ERROR_FAILED;

  FakeHtml5FsFilesystem* filesystem = directory_ref_resource->filesystem;
  FakeHtml5FsFilesystem::Path path = directory_ref_resource->path;

  // Pepper returns PP_ERROR_NOACCESS when trying to create the root directory,
  // not PP_ERROR_FILEEXISTS, as you might expect.
  if (path == "/")
    return RunCompletionCallback(&callback, PP_ERROR_NOACCESS);

  FakeHtml5FsNode* node = filesystem->GetNode(path);
  if (node != NULL)
    return RunCompletionCallback(&callback, PP_ERROR_FILEEXISTS);

  FakeHtml5FsFilesystem::Path parent_path = filesystem->GetParentPath(path);
  FakeHtml5FsNode* parent_node = filesystem->GetNode(parent_path);
  if (parent_node == NULL)
    return RunCompletionCallback(&callback, PP_ERROR_FILENOTFOUND);

  if (!parent_node->IsDirectory())
    return RunCompletionCallback(&callback, PP_ERROR_FAILED);

  bool result = filesystem->AddDirectory(directory_ref_resource->path, NULL);
  EXPECT_EQ(true, result);
  return RunCompletionCallback(&callback, PP_OK);
}

int32_t FakeFileRefInterface::Delete(PP_Resource file_ref,
                                     PP_CompletionCallback callback) {
  FakeFileRefResource* file_ref_resource =
      core_interface_->resource_manager()->Get<FakeFileRefResource>(file_ref);
  if (file_ref_resource == NULL)
    return PP_ERROR_BADRESOURCE;

  FakeHtml5FsFilesystem* filesystem = file_ref_resource->filesystem;
  FakeHtml5FsFilesystem::Path path = file_ref_resource->path;
  FakeHtml5FsNode* node = filesystem->GetNode(path);
  if (node == NULL)
    return RunCompletionCallback(&callback, PP_ERROR_FILENOTFOUND);

  filesystem->RemoveNode(path);
  return RunCompletionCallback(&callback, PP_OK);
}

int32_t FakeFileRefInterface::Query(PP_Resource file_ref,
                                    PP_FileInfo* info,
                                    PP_CompletionCallback callback) {
  FakeFileRefResource* file_ref_resource =
      core_interface_->resource_manager()->Get<FakeFileRefResource>(file_ref);
  if (file_ref_resource == NULL)
    return PP_ERROR_BADRESOURCE;

  FakeHtml5FsFilesystem* filesystem = file_ref_resource->filesystem;
  FakeHtml5FsFilesystem::Path path = file_ref_resource->path;
  FakeHtml5FsNode* node = filesystem->GetNode(path);
  if (node == NULL)
    return RunCompletionCallback(&callback, PP_ERROR_FILENOTFOUND);

  node->GetInfo(info);
  return RunCompletionCallback(&callback, PP_OK);
}

int32_t FakeFileRefInterface::ReadDirectoryEntries(
    PP_Resource directory_ref,
    const PP_ArrayOutput& output,
    PP_CompletionCallback callback) {
  FakeFileRefResource* directory_ref_resource =
      core_interface_->resource_manager()->Get<FakeFileRefResource>(
          directory_ref);
  if (directory_ref_resource == NULL)
    return PP_ERROR_BADRESOURCE;

  FakeHtml5FsFilesystem* filesystem = directory_ref_resource->filesystem;
  FakeHtml5FsFilesystem::Path path = directory_ref_resource->path;
  FakeHtml5FsNode* node = filesystem->GetNode(path);
  if (node == NULL)
    return RunCompletionCallback(&callback, PP_ERROR_FILENOTFOUND);

  if (!node->IsDirectory())
    return RunCompletionCallback(&callback, PP_ERROR_FAILED);

  FakeHtml5FsFilesystem::DirectoryEntries fake_dir_entries;
  filesystem->GetDirectoryEntries(path, &fake_dir_entries);

  uint32_t element_count = fake_dir_entries.size();
  uint32_t element_size = sizeof(fake_dir_entries[0]);
  void* data_buffer =
      (*output.GetDataBuffer)(output.user_data, element_count, element_size);

  if (data_buffer == NULL)
    return RunCompletionCallback(&callback, PP_ERROR_FAILED);

  PP_DirectoryEntry* dir_entries = static_cast<PP_DirectoryEntry*>(data_buffer);
  for (uint32_t i = 0; i < element_count; ++i) {
    const FakeHtml5FsFilesystem::DirectoryEntry& fake_dir_entry =
        fake_dir_entries[i];

    FakeFileRefResource* file_ref_resource = new FakeFileRefResource;
    file_ref_resource->filesystem = directory_ref_resource->filesystem;
    file_ref_resource->path = fake_dir_entry.path;
    PP_Resource file_ref = CREATE_RESOURCE(core_interface_->resource_manager(),
                                           FakeFileRefResource,
                                           file_ref_resource);

    dir_entries[i].file_ref = file_ref;
    dir_entries[i].file_type = fake_dir_entry.node->file_type();
  }

  return RunCompletionCallback(&callback, PP_OK);
}

int32_t FakeFileRefInterface::Rename(PP_Resource file_ref,
                                     PP_Resource new_file_ref,
                                     PP_CompletionCallback callback) {
  FakeFileRefResource* file_ref_resource =
      core_interface_->resource_manager()->Get<FakeFileRefResource>(file_ref);
  if (file_ref_resource == NULL)
    return PP_ERROR_BADRESOURCE;

  FakeFileRefResource* new_file_ref_resource =
      core_interface_->resource_manager()->Get<FakeFileRefResource>(
          new_file_ref);
  if (new_file_ref_resource == NULL)
    return PP_ERROR_BADRESOURCE;

  FakeHtml5FsFilesystem* filesystem = file_ref_resource->filesystem;
  FakeHtml5FsFilesystem::Path path = file_ref_resource->path;
  FakeHtml5FsFilesystem::Path newpath = new_file_ref_resource->path;
  FakeHtml5FsNode* node = filesystem->GetNode(path);
  if (node == NULL)
    return RunCompletionCallback(&callback, PP_ERROR_FILENOTFOUND);
  // FakeFileRefResource does not support directory rename.
  if (!node->IsRegular())
    return RunCompletionCallback(&callback, PP_ERROR_NOTAFILE);

  // Remove the destination if it exists.
  filesystem->RemoveNode(newpath);
  const std::vector<uint8_t> contents = node->contents();
  EXPECT_TRUE(filesystem->AddFile(newpath, contents, NULL));
  EXPECT_TRUE(filesystem->RemoveNode(path));
  return RunCompletionCallback(&callback, PP_OK);
}

FakeFileSystemInterface::FakeFileSystemInterface(
    FakeCoreInterface* core_interface)
    : core_interface_(core_interface) {}

PP_Resource FakeFileSystemInterface::Create(PP_Instance instance,
                                            PP_FileSystemType filesystem_type) {
  FakeInstanceResource* instance_resource =
      core_interface_->resource_manager()->Get<FakeInstanceResource>(instance);
  if (instance_resource == NULL)
    return PP_ERROR_BADRESOURCE;

  FakeFileSystemResource* file_system_resource = new FakeFileSystemResource;
  file_system_resource->filesystem = new FakeHtml5FsFilesystem(
      *instance_resource->filesystem_template, filesystem_type);

  return CREATE_RESOURCE(core_interface_->resource_manager(),
                         FakeFileSystemResource,
                         file_system_resource);
}

int32_t FakeFileSystemInterface::Open(PP_Resource file_system,
                                      int64_t expected_size,
                                      PP_CompletionCallback callback) {
  FakeFileSystemResource* file_system_resource =
      core_interface_->resource_manager()->Get<FakeFileSystemResource>(
          file_system);
  if (file_system_resource == NULL)
    return PP_ERROR_BADRESOURCE;

  file_system_resource->opened = true;
  return RunCompletionCallback(&callback, PP_OK);
}

FakePepperInterfaceHtml5Fs::FakePepperInterfaceHtml5Fs()
    : core_interface_(&resource_manager_),
      var_interface_(&var_manager_),
      file_system_interface_(&core_interface_),
      file_ref_interface_(&core_interface_, &var_interface_),
      file_io_interface_(&core_interface_) {
  Init();
}

FakePepperInterfaceHtml5Fs::FakePepperInterfaceHtml5Fs(
    const FakeHtml5FsFilesystem& filesystem)
    : core_interface_(&resource_manager_),
      var_interface_(&var_manager_),
      filesystem_template_(filesystem),
      file_system_interface_(&core_interface_),
      file_ref_interface_(&core_interface_, &var_interface_),
      file_io_interface_(&core_interface_),
      instance_(0) {
  Init();
}

void FakePepperInterfaceHtml5Fs::Init() {
  FakeInstanceResource* instance_resource = new FakeInstanceResource;
  instance_resource->filesystem_template = &filesystem_template_;

  instance_ = CREATE_RESOURCE(core_interface_.resource_manager(),
                              FakeInstanceResource,
                              instance_resource);
}

FakePepperInterfaceHtml5Fs::~FakePepperInterfaceHtml5Fs() {
  core_interface_.ReleaseResource(instance_);
}

nacl_io::CoreInterface* FakePepperInterfaceHtml5Fs::GetCoreInterface() {
  return &core_interface_;
}

nacl_io::FileSystemInterface*
FakePepperInterfaceHtml5Fs::GetFileSystemInterface() {
  return &file_system_interface_;
}

nacl_io::FileRefInterface* FakePepperInterfaceHtml5Fs::GetFileRefInterface() {
  return &file_ref_interface_;
}

nacl_io::FileIoInterface* FakePepperInterfaceHtml5Fs::GetFileIoInterface() {
  return &file_io_interface_;
}

nacl_io::VarInterface* FakePepperInterfaceHtml5Fs::GetVarInterface() {
  return &var_interface_;
}

/* [<][>][^][v][top][bottom][index][help] */