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 16namespace { 17 18class 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 26class 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 36class 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 45class 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); 64int32_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 74FakeHtml5FsNode::FakeHtml5FsNode(const PP_FileInfo& info) : info_(info) {} 75 76FakeHtml5FsNode::FakeHtml5FsNode(const PP_FileInfo& info, 77 const std::vector<uint8_t>& contents) 78 : info_(info), contents_(contents) {} 79 80FakeHtml5FsNode::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 86int32_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 98int32_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 113int32_t FakeHtml5FsNode::Append(const char* buffer, int32_t bytes_to_write) { 114 return Write(contents_.size(), buffer, bytes_to_write); 115} 116 117int32_t FakeHtml5FsNode::SetLength(int64_t length) { 118 contents_.resize(length); 119 info_.size = length; 120 return PP_OK; 121} 122 123void FakeHtml5FsNode::GetInfo(PP_FileInfo* out_info) { *out_info = info_; } 124 125bool FakeHtml5FsNode::IsRegular() const { 126 return info_.type == PP_FILETYPE_REGULAR; 127} 128 129bool FakeHtml5FsNode::IsDirectory() const { 130 return info_.type == PP_FILETYPE_DIRECTORY; 131} 132 133FakeHtml5FsFilesystem::FakeHtml5FsFilesystem() 134 : filesystem_type_(PP_FILESYSTEMTYPE_INVALID) { 135 Clear(); 136} 137 138FakeHtml5FsFilesystem::FakeHtml5FsFilesystem(PP_FileSystemType type) 139 : filesystem_type_(type) { 140 Clear(); 141} 142 143FakeHtml5FsFilesystem::FakeHtml5FsFilesystem( 144 const FakeHtml5FsFilesystem& filesystem, 145 PP_FileSystemType type) 146 : node_map_(filesystem.node_map_), filesystem_type_(type) {} 147 148void FakeHtml5FsFilesystem::Clear() { 149 node_map_.clear(); 150 // Always have a root node. 151 AddDirectory("/", NULL); 152} 153 154bool FakeHtml5FsFilesystem::AddEmptyFile(const Path& path, 155 FakeHtml5FsNode** out_node) { 156 return AddFile(path, std::vector<uint8_t>(), out_node); 157} 158 159bool 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 167bool 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 195bool 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 222bool FakeHtml5FsFilesystem::RemoveNode(const Path& path) { 223 return node_map_.erase(path) >= 1; 224} 225 226FakeHtml5FsNode* 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 233bool 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 278FakeHtml5FsFilesystem::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 288FakeFileIoInterface::FakeFileIoInterface(FakeCoreInterface* core_interface) 289 : core_interface_(core_interface) {} 290 291PP_Resource FakeFileIoInterface::Create(PP_Resource) { 292 return CREATE_RESOURCE(core_interface_->resource_manager(), 293 FakeFileIoResource, 294 new FakeFileIoResource); 295} 296 297int32_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 345int32_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 360int32_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 385int32_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 414int32_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 434int32_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 447void 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 457FakeFileRefInterface::FakeFileRefInterface(FakeCoreInterface* core_interface, 458 FakeVarInterface* var_interface) 459 : core_interface_(core_interface), var_interface_(var_interface) {} 460 461PP_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 492PP_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 502int32_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 541int32_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 558int32_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 576int32_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 625int32_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 657FakeFileSystemInterface::FakeFileSystemInterface( 658 FakeCoreInterface* core_interface) 659 : core_interface_(core_interface) {} 660 661PP_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 669PP_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 685int32_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 698FakePepperInterfaceHtml5Fs::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 707FakePepperInterfaceHtml5Fs::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 719void 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 728FakePepperInterfaceHtml5Fs::~FakePepperInterfaceHtml5Fs() { 729 core_interface_.ReleaseResource(instance_); 730} 731 732nacl_io::CoreInterface* FakePepperInterfaceHtml5Fs::GetCoreInterface() { 733 return &core_interface_; 734} 735 736nacl_io::FileSystemInterface* 737FakePepperInterfaceHtml5Fs::GetFileSystemInterface() { 738 return &file_system_interface_; 739} 740 741nacl_io::FileRefInterface* FakePepperInterfaceHtml5Fs::GetFileRefInterface() { 742 return &file_ref_interface_; 743} 744 745nacl_io::FileIoInterface* FakePepperInterfaceHtml5Fs::GetFileIoInterface() { 746 return &file_io_interface_; 747} 748 749nacl_io::VarInterface* FakePepperInterfaceHtml5Fs::GetVarInterface() { 750 return &var_interface_; 751} 752